The package rpms/netty.git has added or updated architecture specific content in its spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s): https://src.fedoraproject.org/cgit/rpms/netty.git/commit/?id=342e6b392cd905b....
Change: -%ifarch %{arm}
Thanks.
Full change: ============
commit 342e6b392cd905be34a8918ca862d2dca9a3dcd8 Author: Mat Booth mat.booth@redhat.com Date: Mon Sep 7 14:53:52 2020 +0100
Update to latest upstream version Native bits were not used by anything, so package is now noarch
diff --git a/.gitignore b/.gitignore index 859e799..488860d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -/netty-4.0.42.Final.tar.gz -/netty-4.1.13.Final.tar.gz +/netty-*.tar.gz +/*.src.rpm diff --git a/0001-Remove-optional-dep-Blockhound.patch b/0001-Remove-optional-dep-Blockhound.patch new file mode 100644 index 0000000..783b2f8 --- /dev/null +++ b/0001-Remove-optional-dep-Blockhound.patch @@ -0,0 +1,633 @@ +From 14fa8d4afda0fa1a31a2591298dc5c18e08dab1f Mon Sep 17 00:00:00 2001 +From: Mat Booth mat.booth@redhat.com +Date: Mon, 7 Sep 2020 12:17:31 +0100 +Subject: [PATCH 1/5] Remove optional dep Blockhound + +--- + common/pom.xml | 5 - + .../java/io/netty/util/internal/Hidden.java | 113 --------- + ...ockhound.integration.BlockHoundIntegration | 14 - + pom.xml | 7 - + transport-blockhound-tests/pom.xml | 92 ------- + .../NettyBlockHoundIntegrationTest.java | 239 ------------------ + .../netty/util/internal/localhost_server.key | 28 -- + .../netty/util/internal/localhost_server.pem | 17 -- + .../io/netty/util/internal/mutual_auth_ca.pem | 19 -- + 9 files changed, 534 deletions(-) + delete mode 100644 common/src/main/java/io/netty/util/internal/Hidden.java + delete mode 100644 common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration + delete mode 100644 transport-blockhound-tests/pom.xml + delete mode 100644 transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java + delete mode 100644 transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key + delete mode 100644 transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem + delete mode 100644 transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem + +diff --git a/common/pom.xml b/common/pom.xml +index 706279177a..abc73161eb 100644 +--- a/common/pom.xml ++++ b/common/pom.xml +@@ -78,11 +78,6 @@ + <artifactId>log4j-core</artifactId> + <scope>test</scope> + </dependency> +- <dependency> +- <groupId>io.projectreactor.tools</groupId> +- <artifactId>blockhound</artifactId> +- <optional>true</optional> +- </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> +diff --git a/common/src/main/java/io/netty/util/internal/Hidden.java b/common/src/main/java/io/netty/util/internal/Hidden.java +deleted file mode 100644 +index 7fd6d08396..0000000000 +--- a/common/src/main/java/io/netty/util/internal/Hidden.java ++++ /dev/null +@@ -1,113 +0,0 @@ +-/* +- * Copyright 2019 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.util.internal; +- +-import io.netty.util.concurrent.FastThreadLocalThread; +-import reactor.blockhound.BlockHound; +-import reactor.blockhound.integration.BlockHoundIntegration; +- +-import java.util.function.Function; +-import java.util.function.Predicate; +- +-/** +- * Contains classes that must be have public visibility but are not public API. +- */ +-class Hidden { +- +- /** +- * This class integrates Netty with BlockHound. +- * <p> +- * It is public but only because of the ServiceLoader's limitations +- * and SHOULD NOT be considered a public API. +- */ +- @UnstableApi +- @SuppressJava6Requirement(reason = "BlockHound is Java 8+, but this class is only loaded by it's SPI") +- public static final class NettyBlockHoundIntegration implements BlockHoundIntegration { +- +- @Override +- public void applyTo(BlockHound.Builder builder) { +- builder.allowBlockingCallsInside( +- "io.netty.channel.nio.NioEventLoop", +- "handleLoopException" +- ); +- +- builder.allowBlockingCallsInside( +- "io.netty.channel.kqueue.KQueueEventLoop", +- "handleLoopException" +- ); +- +- builder.allowBlockingCallsInside( +- "io.netty.channel.epoll.EpollEventLoop", +- "handleLoopException" +- ); +- +- builder.allowBlockingCallsInside( +- "io.netty.util.HashedWheelTimer$Worker", +- "waitForNextTick" +- ); +- +- builder.allowBlockingCallsInside( +- "io.netty.util.concurrent.SingleThreadEventExecutor", +- "confirmShutdown" +- ); +- +- builder.allowBlockingCallsInside( +- "io.netty.handler.ssl.SslHandler", +- "handshake" +- ); +- +- builder.allowBlockingCallsInside( +- "io.netty.handler.ssl.SslHandler", +- "runAllDelegatedTasks" +- ); +- +- builder.allowBlockingCallsInside( +- "io.netty.util.concurrent.GlobalEventExecutor", +- "takeTask"); +- +- builder.allowBlockingCallsInside( +- "io.netty.util.concurrent.GlobalEventExecutor", +- "addTask"); +- +- builder.allowBlockingCallsInside( +- "io.netty.util.concurrent.SingleThreadEventExecutor", +- "takeTask"); +- +- builder.allowBlockingCallsInside( +- "io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback", +- "verify"); +- +- builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>, Predicate<Thread>>() { +- @Override +- public Predicate<Thread> apply(final Predicate<Thread> p) { +- return new Predicate<Thread>() { +- @Override +- @SuppressJava6Requirement(reason = "Predicate#test") +- public boolean test(Thread thread) { +- return p.test(thread) || thread instanceof FastThreadLocalThread; +- } +- }; +- } +- }); +- } +- +- @Override +- public int compareTo(BlockHoundIntegration o) { +- return 0; +- } +- } +-} +diff --git a/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration b/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration +deleted file mode 100644 +index 5cf376dd8c..0000000000 +--- a/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration ++++ /dev/null +@@ -1,14 +0,0 @@ +-# Copyright 2019 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. +-io.netty.util.internal.Hidden$NettyBlockHoundIntegration +\ No newline at end of file +diff --git a/pom.xml b/pom.xml +index d00e3e88e0..d548aa5513 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -416,7 +416,6 @@ + <module>testsuite-osgi</module> + <module>testsuite-shading</module> + <module>testsuite-native-image</module> +- <module>transport-blockhound-tests</module> + <module>microbench</module> + <module>bom</module> + </modules> +@@ -717,12 +716,6 @@ + <scope>test</scope> + </dependency> + +- <!-- BlockHound integration --> +- <dependency> +- <groupId>io.projectreactor.tools</groupId> +- <artifactId>blockhound</artifactId> +- <version>1.0.3.RELEASE</version> +- </dependency> + </dependencies> + </dependencyManagement> + +diff --git a/transport-blockhound-tests/pom.xml b/transport-blockhound-tests/pom.xml +deleted file mode 100644 +index 359accd3c4..0000000000 +--- a/transport-blockhound-tests/pom.xml ++++ /dev/null +@@ -1,92 +0,0 @@ +-<?xml version="1.0" encoding="UTF-8"?> +-<!-- +- ~ Copyright 2019 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. +- --> +-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> +- +- <modelVersion>4.0.0</modelVersion> +- <parent> +- <groupId>io.netty</groupId> +- <artifactId>netty-parent</artifactId> +- <version>4.1.51.Final</version> +- </parent> +- +- <artifactId>netty-transport-blockhound-tests</artifactId> +- <packaging>jar</packaging> +- <description> +- Tests for the BlockHound integration. +- </description> +- +- <name>Netty/Transport/BlockHound/Tests</name> +- +- <profiles> +- <profile> +- <id>java13</id> +- <activation> +- <jdk>13</jdk> +- </activation> +- <properties> +- <argLine.common>-XX:+AllowRedefinitionToAddDeleteMethods</argLine.common> +- </properties> +- </profile> +- <profile> +- <id>java14</id> +- <activation> +- <jdk>14</jdk> +- </activation> +- <properties> +- <argLine.common>-XX:+AllowRedefinitionToAddDeleteMethods</argLine.common> +- </properties> +- </profile> +- </profiles> +- +- <properties> +- <maven.compiler.source>1.8</maven.compiler.source> +- <maven.compiler.target>1.8</maven.compiler.target> +- <!-- Needed for SelfSignedCertificate --> +- <argLine.java9.extras>--add-exports java.base/sun.security.x509=ALL-UNNAMED</argLine.java9.extras> +- <skipJapicmp>true</skipJapicmp> +- </properties> +- +- <dependencies> +- <dependency> +- <groupId>${project.groupId}</groupId> +- <artifactId>netty-transport</artifactId> +- <version>${project.version}</version> +- </dependency> +- <dependency> +- <groupId>${project.groupId}</groupId> +- <artifactId>netty-handler</artifactId> +- <version>${project.version}</version> +- </dependency> +- <dependency> +- <groupId>${project.groupId}</groupId> +- <artifactId>${tcnative.artifactId}</artifactId> +- <classifier>${tcnative.classifier}</classifier> +- <optional>true</optional> +- </dependency> +- +- <dependency> +- <groupId>org.bouncycastle</groupId> +- <artifactId>bcpkix-jdk15on</artifactId> +- <optional>true</optional> +- </dependency> +- <dependency> +- <groupId>io.projectreactor.tools</groupId> +- <artifactId>blockhound</artifactId> +- <scope>test</scope> +- </dependency> +- </dependencies> +-</project> +diff --git a/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java b/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java +deleted file mode 100644 +index 58e9284370..0000000000 +--- a/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java ++++ /dev/null +@@ -1,239 +0,0 @@ +-/* +- * Copyright 2019 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.util.internal; +- +-import io.netty.bootstrap.Bootstrap; +-import io.netty.bootstrap.ServerBootstrap; +-import io.netty.buffer.UnpooledByteBufAllocator; +-import io.netty.channel.Channel; +-import io.netty.channel.ChannelFuture; +-import io.netty.channel.ChannelHandlerContext; +-import io.netty.channel.ChannelInboundHandlerAdapter; +-import io.netty.channel.ChannelInitializer; +-import io.netty.channel.EventLoopGroup; +-import io.netty.channel.nio.NioEventLoopGroup; +-import io.netty.channel.socket.nio.NioServerSocketChannel; +-import io.netty.channel.socket.nio.NioSocketChannel; +-import io.netty.handler.ssl.SslContext; +-import io.netty.handler.ssl.SslContextBuilder; +-import io.netty.handler.ssl.SslHandler; +-import io.netty.handler.ssl.SslHandshakeCompletionEvent; +-import io.netty.handler.ssl.SslProvider; +-import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +-import io.netty.handler.ssl.util.SelfSignedCertificate; +-import io.netty.util.ReferenceCountUtil; +-import io.netty.util.concurrent.DefaultThreadFactory; +-import io.netty.util.concurrent.EventExecutor; +-import io.netty.util.concurrent.GlobalEventExecutor; +-import io.netty.util.concurrent.ImmediateEventExecutor; +-import io.netty.util.concurrent.ImmediateExecutor; +-import io.netty.util.concurrent.ScheduledFuture; +-import io.netty.util.concurrent.SingleThreadEventExecutor; +-import io.netty.util.internal.Hidden.NettyBlockHoundIntegration; +-import org.hamcrest.Matchers; +-import org.junit.BeforeClass; +-import org.junit.Test; +-import reactor.blockhound.BlockHound; +-import reactor.blockhound.BlockingOperationError; +-import reactor.blockhound.integration.BlockHoundIntegration; +- +-import java.net.InetSocketAddress; +-import java.util.ServiceLoader; +-import java.util.concurrent.CountDownLatch; +-import java.util.concurrent.ExecutionException; +-import java.util.concurrent.Executor; +-import java.util.concurrent.ExecutorService; +-import java.util.concurrent.Executors; +-import java.util.concurrent.FutureTask; +-import java.util.concurrent.TimeUnit; +- +-import static org.junit.Assert.assertThat; +-import static org.junit.Assert.assertTrue; +-import static org.junit.Assert.fail; +- +-public class NettyBlockHoundIntegrationTest { +- +- @BeforeClass +- public static void setUpClass() { +- BlockHound.install(); +- } +- +- @Test +- public void testServiceLoader() { +- for (BlockHoundIntegration integration : ServiceLoader.load(BlockHoundIntegration.class)) { +- if (integration instanceof NettyBlockHoundIntegration) { +- return; +- } +- } +- +- fail("NettyBlockHoundIntegration cannot be loaded with ServiceLoader"); +- } +- +- @Test +- public void testBlockingCallsInNettyThreads() throws Exception { +- final FutureTask<Void> future = new FutureTask<>(() -> { +- Thread.sleep(0); +- return null; +- }); +- GlobalEventExecutor.INSTANCE.execute(future); +- +- try { +- future.get(5, TimeUnit.SECONDS); +- fail("Expected an exception due to a blocking call but none was thrown"); +- } catch (ExecutionException e) { +- assertThat(e.getCause(), Matchers.instanceOf(BlockingOperationError.class)); +- } +- } +- +- @Test(timeout = 5000L) +- public void testGlobalEventExecutorTakeTask() throws InterruptedException { +- testEventExecutorTakeTask(GlobalEventExecutor.INSTANCE); +- } +- +- @Test(timeout = 5000L) +- public void testSingleThreadEventExecutorTakeTask() throws InterruptedException { +- SingleThreadEventExecutor executor = +- new SingleThreadEventExecutor(null, new DefaultThreadFactory("test"), true) { +- @Override +- protected void run() { +- while (!confirmShutdown()) { +- Runnable task = takeTask(); +- if (task != null) { +- task.run(); +- } +- } +- } +- }; +- testEventExecutorTakeTask(executor); +- } +- +- private static void testEventExecutorTakeTask(EventExecutor eventExecutor) throws InterruptedException { +- CountDownLatch latch = new CountDownLatch(1); +- ScheduledFuture<?> f = eventExecutor.schedule(latch::countDown, 10, TimeUnit.MILLISECONDS); +- f.sync(); +- latch.await(); +- } +- +- // Tests copied from io.netty.handler.ssl.SslHandlerTest +- @Test +- public void testHandshakeWithExecutorThatExecuteDirectory() throws Exception { +- testHandshakeWithExecutor(Runnable::run); +- } +- +- @Test +- public void testHandshakeWithImmediateExecutor() throws Exception { +- testHandshakeWithExecutor(ImmediateExecutor.INSTANCE); +- } +- +- @Test +- public void testHandshakeWithImmediateEventExecutor() throws Exception { +- testHandshakeWithExecutor(ImmediateEventExecutor.INSTANCE); +- } +- +- @Test +- public void testHandshakeWithExecutor() throws Exception { +- ExecutorService executorService = Executors.newCachedThreadPool(); +- try { +- testHandshakeWithExecutor(executorService); +- } finally { +- executorService.shutdown(); +- } +- } +- +- @Test +- public void testTrustManagerVerify() throws Exception { +- final SslContext sslClientCtx = +- SslContextBuilder.forClient() +- .trustManager(ResourcesUtil.getFile(getClass(), "mutual_auth_ca.pem")) +- .build(); +- +- final SslContext sslServerCtx = +- SslContextBuilder.forServer(ResourcesUtil.getFile(getClass(), "localhost_server.pem"), +- ResourcesUtil.getFile(getClass(), "localhost_server.key"), +- null) +- .build(); +- +- final SslHandler clientSslHandler = sslClientCtx.newHandler(UnpooledByteBufAllocator.DEFAULT); +- final SslHandler serverSslHandler = sslServerCtx.newHandler(UnpooledByteBufAllocator.DEFAULT); +- +- testHandshake(sslClientCtx, clientSslHandler, serverSslHandler); +- } +- +- private static void testHandshakeWithExecutor(Executor executor) throws Exception { +- String tlsVersion = "TLSv1.2"; +- final SslContext sslClientCtx = SslContextBuilder.forClient() +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .sslProvider(SslProvider.JDK).protocols(tlsVersion).build(); +- +- final SelfSignedCertificate cert = new SelfSignedCertificate(); +- final SslContext sslServerCtx = SslContextBuilder.forServer(cert.key(), cert.cert()) +- .sslProvider(SslProvider.JDK).protocols(tlsVersion).build(); +- +- final SslHandler clientSslHandler = sslClientCtx.newHandler(UnpooledByteBufAllocator.DEFAULT, executor); +- final SslHandler serverSslHandler = sslServerCtx.newHandler(UnpooledByteBufAllocator.DEFAULT, executor); +- +- testHandshake(sslClientCtx, clientSslHandler, serverSslHandler); +- } +- +- private static void testHandshake(SslContext sslClientCtx, SslHandler clientSslHandler, +- SslHandler serverSslHandler) throws Exception { +- EventLoopGroup group = new NioEventLoopGroup(); +- Channel sc = null; +- Channel cc = null; +- try { +- sc = new ServerBootstrap() +- .group(group) +- .channel(NioServerSocketChannel.class) +- .childHandler(serverSslHandler) +- .bind(new InetSocketAddress(0)).syncUninterruptibly().channel(); +- +- ChannelFuture future = new Bootstrap() +- .group(group) +- .channel(NioSocketChannel.class) +- .handler(new ChannelInitializer<Channel>() { +- @Override +- protected void initChannel(Channel ch) { +- ch.pipeline() +- .addLast(clientSslHandler) +- .addLast(new ChannelInboundHandlerAdapter() { +- +- @Override +- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { +- if (evt instanceof SslHandshakeCompletionEvent && +- ((SslHandshakeCompletionEvent) evt).cause() != null) { +- ((SslHandshakeCompletionEvent) evt).cause().printStackTrace(); +- } +- ctx.fireUserEventTriggered(evt); +- } +- }); +- } +- }).connect(sc.localAddress()); +- cc = future.syncUninterruptibly().channel(); +- +- assertTrue(clientSslHandler.handshakeFuture().await().isSuccess()); +- assertTrue(serverSslHandler.handshakeFuture().await().isSuccess()); +- } finally { +- if (cc != null) { +- cc.close().syncUninterruptibly(); +- } +- if (sc != null) { +- sc.close().syncUninterruptibly(); +- } +- group.shutdownGracefully(); +- ReferenceCountUtil.release(sslClientCtx); +- } +- } +-} +diff --git a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key +deleted file mode 100644 +index 9aa6611400..0000000000 +--- a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key ++++ /dev/null +@@ -1,28 +0,0 @@ +------BEGIN PRIVATE KEY----- +-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDYrLtMlZzoe2BP +-iCURF3So5XNLfsOLcAVERXXjnxqX6Mex55WdJiy6uWTFKbRHWJdbWELdZxVl5+GX +-pMv3OdkKZt+19ZdSfByv6bB5RNdZOEGnKOHSY2XdnzYnF5JBaWEx0fvtvIPZOUlW +-DWgsQzJk1UQhu+XnBc7P1hHYNvwsVNOR+HD9LGebDy+UcfiL34XwAyBdHUsbcIr8 +-hltABcj6vNbqOLndpU86DxU9z9b1PDmkFVfisElhpDEhpxmTCwI22Us1GC8D81LM +-ZzMlbWSzTfNPEuqNzJYGiFt/XPwPkPPyVvti0XWPBQpwzJFFUX5xKsOGERolELRT +-0yNQYznFAgMBAAECggEAOFR/xSNITbB1k3ejm1PrwlUUqlXkZIXU+LDOO0UL1t5v +-vDKm1Not2sWECzYSZlID132UtJauG3YzUgdH95gUcv3XvyiAFLOriZhJht181vcn +-KlwYiWfJ/dn8bCFWpqbM2/TpeB8AcCLSjAqkQI2ftlMziUmeNXdvEt1mej2hRay1 +-ULfoxlC0mftNRQptD5gBFzrc47O4mVpVEQt4yS3Qyzp2/9ds9UkhaCIFpXPVCalZ +-ds7R+bDDP+wiYTkUcd8fvelaMkD3Wcy8DedGRShhILZvBYTDdWcpJ7+e5EkNlEq4 +-+Ys4Y/u6aFDJD53g3zCaJhatmdAZcct2MMmWH1vewQKBgQD3Y2S245cad1D9AqYD +-ChZGp95EfRo3EzXk4VkE50bjZXjHq9fD8T0CWEZGWQZrXJCR+vBpEURy0mrPD8se +-QQ0Q5+I27RadtfPnMd6ry9nDGMPxyd/10vzU6LazzLNE+uf9ljF1RHZu1iDAvInR +-r1cQGbn/wKBF6BurPPIXABZEuQKBgQDgN6JHbIfDzHKhwEoUTvRrYJsTXqplD+h0 +-Whg+kSQyhtKdlpINFOoEj8FUNJvTjG8les1aoajyWIqikVdvHto/mrxrSIeRkEmt +-X+KG+5ld2n466tzv1DmVcIGXSrBrH3lA0i6R8Ly26FLSqw0Z12fx5GUUa1qaVRqo +-rwcrIZovbQKBgHa2mojs9AC+Sv3uvG1u9LuZKJ7jDaZqMI2R2d7xgOH0Op5Ohy6+ +-39D1PVvasqroc3Op4J36rEcRVDHi2Uy+WJ/JNpO2+AhcXRuPodP88ZWel8C6aB+V +-zL/6oFntnAU5BgR5g2hLny2W0YbLsrMNmhDe15O0AvUo6cYla+K/pu/5AoGACr/g +-EdiMMcDthf+4DX0zjqpVBPq25J18oYdoPierOpjoJBIB8oqcJZfWxvi2t8+1zHA0 +-xDGX7fZ8vwqEzJkIEaCTg/k4NqxaO+uq6pnJYoyFHMIB0aW1FQsNy3kTOC+MGqV5 +-Ahoukf5VajA1MpX3L8upZO84qsmFu6yYhWLZB4kCgYBlgSD5G4q6rX4ELa3XG61h +-fDtu75IYEsjWm4vgJzHjeYT2xPIm9OFFYXjPghto0f1oH37ODD3DoXmsnmddgpmn +-tH7aRWWHsSpB5zVgftV4urNCIsm87LWw8mvUGgCwYV1CtCX8warKokfeoA2ltz4u +-oeuUzo98hN+aKRU5RO6Bmg== +------END PRIVATE KEY----- +diff --git a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem +deleted file mode 100644 +index 70759b29e5..0000000000 +--- a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem ++++ /dev/null +@@ -1,17 +0,0 @@ +------BEGIN CERTIFICATE----- +-MIICozCCAYsCAnS/MA0GCSqGSIb3DQEBDQUAMBgxFjAUBgNVBAMTDU5ldHR5VGVz +-dFJvb3QwIBcNMTcwMjE3MDMzMzQ0WhgPMjExNzAxMjQwMzMzNDRaMBQxEjAQBgNV +-BAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANis +-u0yVnOh7YE+IJREXdKjlc0t+w4twBURFdeOfGpfox7HnlZ0mLLq5ZMUptEdYl1tY +-Qt1nFWXn4Zeky/c52Qpm37X1l1J8HK/psHlE11k4Qaco4dJjZd2fNicXkkFpYTHR +-++28g9k5SVYNaCxDMmTVRCG75ecFzs/WEdg2/CxU05H4cP0sZ5sPL5Rx+IvfhfAD +-IF0dSxtwivyGW0AFyPq81uo4ud2lTzoPFT3P1vU8OaQVV+KwSWGkMSGnGZMLAjbZ +-SzUYLwPzUsxnMyVtZLNN808S6o3MlgaIW39c/A+Q8/JW+2LRdY8FCnDMkUVRfnEq +-w4YRGiUQtFPTI1BjOcUCAwEAATANBgkqhkiG9w0BAQ0FAAOCAQEAQNXnwE2MJFy5 +-ti07xyi8h/mY0Kl1dwZUqx4F9D9eoxLCq2/p3h/Z18AlOmjdW06pvC2sGtQtyEqL +-YjuQFbMjXRo9c+6+d+xwdDKTu7+XOTHvznJ8xJpKnFOlohGq/n3efBIJSsaeasTU +-slFzmdKYABDZzbsQ4X6YCIOF4XVdEQqmXpS+uEbn5C2sVtG+LXI8srmkVGpCcRew +-SuTGanwxLparhBBeN1ARjKzNxXUWuK2UKZ9p8c7n7TXGhd12ZNTcLhk4rCnOFq1J +-ySFvP5YL2q29fpEt+Tq0zm3V7An2qtaNDp26cEdevtKPjRyOLkCJx8OlZxc9DZvJ +-HjalFDoRUw== +------END CERTIFICATE----- +diff --git a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem +deleted file mode 100644 +index 9c9241bc65..0000000000 +--- a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem ++++ /dev/null +@@ -1,19 +0,0 @@ +------BEGIN CERTIFICATE----- +-MIIDLDCCAhSgAwIBAgIJAO1m5pioZhLLMA0GCSqGSIb3DQEBDQUAMBgxFjAUBgNV +-BAMTDU5ldHR5VGVzdFJvb3QwHhcNMTcwMjE3MDMzMzQ0WhcNMTcwMzE5MDMzMzQ0 +-WjAYMRYwFAYDVQQDEw1OZXR0eVRlc3RSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC +-AQ8AMIIBCgKCAQEAnC7Y/p/TSWI1KxBKETfFKaRWCPEkoYn5G973WbCF0VDT90PX +-xK6yHvhqNdDQZPmddgfDAQfjekHeeIFkjCKlvQu0js0G4Bubz4NffNumd/Mgsix8 +-SWJ13lPk+Ly4PDv0bK1zB6BxP1qQm1qxVwsPy9zNP8ylJrM0Div4TXHmnWOfc0JD +-4/XPpfeUHH1tt/GMtsS2Gx6EpTVPD2w7LDKUza1/rQ7d9sqmFpgsNcI9Db/sAtFP +-lK2iJku5WIXQkmHimn4bqZ9wkiXJ85pm5ggGQqGMPSbe+2Lh24AvZMIBiwPbkjEU +-EDFXEJfKOC3Dl71JgWOthtHZ9vcCRDQ3Sky6AQIDAQABo3kwdzAdBgNVHQ4EFgQU +-qT+cH8qrebiVPpKCBQDB6At2iOAwSAYDVR0jBEEwP4AUqT+cH8qrebiVPpKCBQDB +-6At2iOChHKQaMBgxFjAUBgNVBAMTDU5ldHR5VGVzdFJvb3SCCQDtZuaYqGYSyzAM +-BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQCEemXTIew4pR2cHEFpVsW2 +-bLHXLAnC23wBMT46D3tqyxscukMYjFuWosCdEsgRW8d50BXy9o4dHWeg94+aDo3A +-DX4OTRN/veQGIG7dgM6poDzFuVJlSN0ubKKg6gpDD60IhopZpMviFAOsmzr7OXwS +-9hjbTqUWujMIEHQ95sPlQFdSaavYSFfqhSltWmVCPSbArxrw0lZ2QcnUqGN47EFp +-whc5wFB+rSw/ojU1jBLMvgvgzf/8V8zr1IBTDSiHNlknGqGpOOaookzUh95YRiAT +-hH82y9bBeflqroOeztqMpONpWoZjlz0sWbJNvXztXINL7LaNmVYOcoUrCcxPS54T +------END CERTIFICATE----- +-- +2.26.2 + diff --git a/0002-Remove-NPN-ALPN.patch b/0002-Remove-NPN-ALPN.patch deleted file mode 100644 index 73749cc..0000000 --- a/0002-Remove-NPN-ALPN.patch +++ /dev/null @@ -1,884 +0,0 @@ -From cfb6f2a620525a94d6964c287792f2645bff4f4a Mon Sep 17 00:00:00 2001 -From: Severin Gehwolf <sgehwolf@redhat.com> -Date: Thu, 20 Oct 2016 16:18:10 +0200 -Subject: [PATCH 2/2] Remove NPN ALPN - ---- - .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 120 --------- - .../io/netty/handler/ssl/JdkAlpnSslEngine.java | 124 ---------- - .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 --------- - .../java/io/netty/handler/ssl/JdkNpnSslEngine.java | 122 --------- - .../java/io/netty/handler/ssl/JdkSslContext.java | 44 ---- - .../io/netty/handler/ssl/JdkSslEngineTest.java | 273 --------------------- - 6 files changed, 803 deletions(-) - delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java - delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java - delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java - delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java - -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java -deleted file mode 100644 -index aaaf5b7..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java -+++ /dev/null -@@ -1,120 +0,0 @@ --/* -- * Copyright 2014 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 javax.net.ssl.SSLEngine; -- --/** -- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}. -- */ --public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { -- private static final SslEngineWrapperFactory ALPN_WRAPPER = new SslEngineWrapperFactory() { -- { -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw new RuntimeException("ALPN unsupported. Is your classpatch configured correctly?" -- + " See http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-starting"); -- } -- } -- -- @Override -- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, -- boolean isServer) { -- return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer); -- } -- }; -- -- /** -- * Create a new instance. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(Iterable<String> protocols) { -- this(false, protocols); -- } -- -- /** -- * Create a new instance. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(String... protocols) { -- this(false, protocols); -- } -- -- /** -- * Create a new instance. -- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) { -- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); -- } -- -- /** -- * Create a new instance. -- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) { -- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); -- } -- -- /** -- * Create a new instance. -- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. -- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, -- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) { -- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, -- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, -- protocols); -- } -- -- /** -- * Create a new instance. -- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. -- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, -- boolean serverFailIfNoCommonProtocols, String... protocols) { -- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, -- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, -- protocols); -- } -- -- /** -- * Create a new instance. -- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. -- * @param listenerFactory The factory which provides to be notified of which protocol was selected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, -- ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) { -- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols); -- } -- -- /** -- * Create a new instance. -- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. -- * @param listenerFactory The factory which provides to be notified of which protocol was selected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, -- ProtocolSelectionListenerFactory listenerFactory, String... protocols) { -- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols); -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java -deleted file mode 100644 -index bdf3aca..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java -+++ /dev/null -@@ -1,124 +0,0 @@ --/* -- * Copyright 2014 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 static io.netty.util.internal.ObjectUtil.checkNotNull; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; -- --import java.util.LinkedHashSet; --import java.util.List; -- --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLException; --import javax.net.ssl.SSLHandshakeException; -- --import org.eclipse.jetty.alpn.ALPN; --import org.eclipse.jetty.alpn.ALPN.ClientProvider; --import org.eclipse.jetty.alpn.ALPN.ServerProvider; -- --final class JdkAlpnSslEngine extends JdkSslEngine { -- private static boolean available; -- -- static boolean isAvailable() { -- updateAvailability(); -- return available; -- } -- -- private static void updateAvailability() { -- if (available) { -- return; -- } -- -- try { -- // Always use bootstrap class loader. -- Class.forName("sun.security.ssl.ALPNExtension", true, null); -- available = true; -- } catch (Exception ignore) { -- // alpn-boot was not loaded. -- } -- } -- -- JdkAlpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) { -- super(engine); -- checkNotNull(applicationNegotiator, "applicationNegotiator"); -- -- if (server) { -- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() -- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())), -- "protocolSelector"); -- ALPN.put(engine, new ServerProvider() { -- @Override -- public String select(List<String> protocols) throws SSLException { -- try { -- return protocolSelector.select(protocols); -- } catch (SSLHandshakeException e) { -- throw e; -- } catch (Throwable t) { -- SSLHandshakeException e = new SSLHandshakeException(t.getMessage()); -- e.initCause(t); -- throw e; -- } -- } -- -- @Override -- public void unsupported() { -- protocolSelector.unsupported(); -- } -- }); -- } else { -- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator -- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), -- "protocolListener"); -- ALPN.put(engine, new ClientProvider() { -- @Override -- public List<String> protocols() { -- return applicationNegotiator.protocols(); -- } -- -- @Override -- public void selected(String protocol) throws SSLException { -- try { -- protocolListener.selected(protocol); -- } catch (SSLHandshakeException e) { -- throw e; -- } catch (Throwable t) { -- SSLHandshakeException e = new SSLHandshakeException(t.getMessage()); -- e.initCause(t); -- throw e; -- } -- } -- -- @Override -- public void unsupported() { -- protocolListener.unsupported(); -- } -- }); -- } -- } -- -- @Override -- public void closeInbound() throws SSLException { -- ALPN.remove(getWrappedEngine()); -- super.closeInbound(); -- } -- -- @Override -- public void closeOutbound() { -- ALPN.remove(getWrappedEngine()); -- super.closeOutbound(); -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java -deleted file mode 100644 -index c893f05..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java -+++ /dev/null -@@ -1,120 +0,0 @@ --/* -- * Copyright 2014 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 javax.net.ssl.SSLEngine; -- --/** -- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}. -- */ --public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { -- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() { -- { -- if (!JdkNpnSslEngine.isAvailable()) { -- throw new RuntimeException("NPN unsupported. Is your classpatch configured correctly?" -- + " See http://www.eclipse.org/jetty/documentation/current/npn-chapter.html#npn-starting"); -- } -- } -- -- @Override -- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, -- boolean isServer) { -- return new JdkNpnSslEngine(engine, applicationNegotiator, isServer); -- } -- }; -- -- /** -- * Create a new instance. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(Iterable<String> protocols) { -- this(false, protocols); -- } -- -- /** -- * Create a new instance. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(String... protocols) { -- this(false, protocols); -- } -- -- /** -- * Create a new instance. -- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) { -- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); -- } -- -- /** -- * Create a new instance. -- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) { -- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); -- } -- -- /** -- * Create a new instance. -- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. -- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, -- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) { -- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, -- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, -- protocols); -- } -- -- /** -- * Create a new instance. -- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. -- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, -- boolean serverFailIfNoCommonProtocols, String... protocols) { -- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, -- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, -- protocols); -- } -- -- /** -- * Create a new instance. -- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. -- * @param listenerFactory The factory which provides to be notified of which protocol was selected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, -- ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) { -- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols); -- } -- -- /** -- * Create a new instance. -- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. -- * @param listenerFactory The factory which provides to be notified of which protocol was selected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, -- ProtocolSelectionListenerFactory listenerFactory, String... protocols) { -- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols); -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java -deleted file mode 100644 -index 422727a..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java -+++ /dev/null -@@ -1,122 +0,0 @@ --/* -- * Copyright 2014 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 static io.netty.util.internal.ObjectUtil.checkNotNull; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; --import io.netty.util.internal.PlatformDependent; -- --import java.util.LinkedHashSet; --import java.util.List; -- --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLException; -- --import org.eclipse.jetty.npn.NextProtoNego; --import org.eclipse.jetty.npn.NextProtoNego.ClientProvider; --import org.eclipse.jetty.npn.NextProtoNego.ServerProvider; -- --final class JdkNpnSslEngine extends JdkSslEngine { -- private static boolean available; -- -- static boolean isAvailable() { -- updateAvailability(); -- return available; -- } -- -- private static void updateAvailability() { -- if (available) { -- return; -- } -- try { -- // Always use bootstrap class loader. -- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null); -- available = true; -- } catch (Exception ignore) { -- // npn-boot was not loaded. -- } -- } -- -- JdkNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) { -- super(engine); -- checkNotNull(applicationNegotiator, "applicationNegotiator"); -- -- if (server) { -- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator -- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), -- "protocolListener"); -- NextProtoNego.put(engine, new ServerProvider() { -- @Override -- public void unsupported() { -- protocolListener.unsupported(); -- } -- -- @Override -- public List<String> protocols() { -- return applicationNegotiator.protocols(); -- } -- -- @Override -- public void protocolSelected(String protocol) { -- try { -- protocolListener.selected(protocol); -- } catch (Throwable t) { -- PlatformDependent.throwException(t); -- } -- } -- }); -- } else { -- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() -- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())), -- "protocolSelector"); -- NextProtoNego.put(engine, new ClientProvider() { -- @Override -- public boolean supports() { -- return true; -- } -- -- @Override -- public void unsupported() { -- protocolSelector.unsupported(); -- } -- -- @Override -- public String selectProtocol(List<String> protocols) { -- try { -- return protocolSelector.select(protocols); -- } catch (Throwable t) { -- PlatformDependent.throwException(t); -- return null; -- } -- } -- }); -- } -- } -- -- @Override -- public void closeInbound() throws SSLException { -- NextProtoNego.remove(getWrappedEngine()); -- super.closeInbound(); -- } -- -- @Override -- public void closeOutbound() { -- NextProtoNego.remove(getWrappedEngine()); -- super.closeOutbound(); -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java -index 0a120eb..cdad232 100644 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java -+++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java -@@ -270,50 +270,6 @@ public class JdkSslContext extends SslContext { - switch(config.protocol()) { - case NONE: - return JdkDefaultApplicationProtocolNegotiator.INSTANCE; -- case ALPN: -- if (isServer) { -- switch(config.selectorFailureBehavior()) { -- case FATAL_ALERT: -- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- case NO_ADVERTISE: -- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- default: -- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") -- .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); -- } -- } else { -- switch(config.selectedListenerFailureBehavior()) { -- case ACCEPT: -- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- case FATAL_ALERT: -- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- default: -- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") -- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); -- } -- } -- case NPN: -- if (isServer) { -- switch(config.selectedListenerFailureBehavior()) { -- case ACCEPT: -- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- case FATAL_ALERT: -- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- default: -- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") -- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); -- } -- } else { -- switch(config.selectorFailureBehavior()) { -- case FATAL_ALERT: -- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- case NO_ADVERTISE: -- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- default: -- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") -- .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); -- } -- } - default: - throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") - .append(config.protocol()).append(" protocol").toString()); -diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -index 9a57230..090f996 100644 ---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -@@ -15,262 +15,15 @@ - */ - package io.netty.handler.ssl; - --import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; --import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior; --import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectorFactory; --import io.netty.handler.ssl.util.InsecureTrustManagerFactory; --import io.netty.handler.ssl.util.SelfSignedCertificate; - import org.junit.Test; - --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLHandshakeException; --import java.util.List; --import java.util.Set; --import java.util.concurrent.TimeUnit; -- --import static org.junit.Assert.assertNull; --import static org.junit.Assert.assertTrue; --import static org.junit.Assume.assumeNoException; -- - public class JdkSslEngineTest extends SSLEngineTest { -- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2"; -- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1"; -- private static final String APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE = "my-protocol-FOO"; -- -- @Test -- public void testNpn() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkNpnSslEngine.isAvailable()) { -- throw tlsExtensionNotFound(Protocol.NPN); -- } -- ApplicationProtocolConfig apn = failingNegotiator(Protocol.NPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- setupHandlers(apn); -- runTest(); -- } catch (SkipTestException e) { -- // NPN availability is dependent on the java version. If NPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testNpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkNpnSslEngine.isAvailable()) { -- throw tlsExtensionNotFound(Protocol.NPN); -- } -- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- setupHandlers(serverApn, clientApn); -- runTest(null); -- } catch (SkipTestException e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testNpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkNpnSslEngine.isAvailable()) { -- throw tlsExtensionNotFound(Protocol.NPN); -- } -- ApplicationProtocolConfig clientApn = failingNegotiator(Protocol.NPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- setupHandlers(serverApn, clientApn); -- assertTrue(clientLatch.await(2, TimeUnit.SECONDS)); -- assertTrue(clientException instanceof SSLHandshakeException); -- } catch (SkipTestException e) { -- // NPN availability is dependent on the java version. If NPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testNpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkNpnSslEngine.isAvailable()) { -- throw tlsExtensionNotFound(Protocol.NPN); -- } -- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.NPN, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- setupHandlers(serverApn, clientApn); -- assertTrue(serverLatch.await(2, TimeUnit.SECONDS)); -- assertTrue(serverException instanceof SSLHandshakeException); -- } catch (SkipTestException e) { -- // NPN availability is dependent on the java version. If NPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testAlpn() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw tlsExtensionNotFound(Protocol.ALPN); -- } -- ApplicationProtocolConfig apn = failingNegotiator(Protocol.ALPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- setupHandlers(apn); -- runTest(); -- } catch (SkipTestException e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testAlpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw tlsExtensionNotFound(Protocol.ALPN); -- } -- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- setupHandlers(serverApn, clientApn); -- runTest(null); -- } catch (SkipTestException e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testAlpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw tlsExtensionNotFound(Protocol.ALPN); -- } -- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- setupHandlers(serverApn, clientApn); -- assertTrue(serverLatch.await(2, TimeUnit.SECONDS)); -- assertTrue(serverException instanceof SSLHandshakeException); -- } catch (SkipTestException e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw tlsExtensionNotFound(Protocol.ALPN); -- } -- // Even the preferred application protocol appears second in the client's list, it will be picked -- // because it's the first one on server's list. -- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN, -- FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL); -- setupHandlers(serverApn, clientApn); -- assertNull(serverException); -- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- } catch (SkipTestException e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testAlpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw tlsExtensionNotFound(Protocol.ALPN); -- } -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(true, true, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator( -- new ProtocolSelectorFactory() { -- @Override -- public ProtocolSelector newSelector(SSLEngine engine, Set<String> supportedProtocols) { -- return new ProtocolSelector() { -- @Override -- public void unsupported() { -- } -- -- @Override -- public String select(List<String> protocols) { -- return APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE; -- } -- }; -- } -- }, JdkBaseApplicationProtocolNegotiator.FAIL_SELECTION_LISTENER_FACTORY, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- -- SslContext serverSslCtx = new JdkSslServerContext(ssc.certificate(), ssc.privateKey(), null, null, -- IdentityCipherSuiteFilter.INSTANCE, serverApn, 0, 0); -- SslContext clientSslCtx = new JdkSslClientContext(null, InsecureTrustManagerFactory.INSTANCE, null, -- IdentityCipherSuiteFilter.INSTANCE, clientApn, 0, 0); -- -- setupHandlers(serverSslCtx, clientSslCtx); -- assertTrue(clientLatch.await(2, TimeUnit.SECONDS)); -- assertTrue(clientException instanceof SSLHandshakeException); -- } catch (SkipTestException e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } - - @Test - public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception { - testEnablingAnAlreadyDisabledSslProtocol(new String[]{}, new String[]{PROTOCOL_TLS_V1_2}); - } - -- private void runTest() throws Exception { -- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- } -- - @Override - protected SslProvider sslClientProvider() { - return SslProvider.JDK; -@@ -280,30 +33,4 @@ public class JdkSslEngineTest extends SSLEngineTest { - protected SslProvider sslServerProvider() { - return SslProvider.JDK; - } -- -- private ApplicationProtocolConfig failingNegotiator(Protocol protocol, -- String... supportedProtocols) { -- return new ApplicationProtocolConfig(protocol, -- SelectorFailureBehavior.FATAL_ALERT, -- SelectedListenerFailureBehavior.FATAL_ALERT, -- supportedProtocols); -- } -- -- private ApplicationProtocolConfig acceptingNegotiator(Protocol protocol, -- String... supportedProtocols) { -- return new ApplicationProtocolConfig(protocol, -- SelectorFailureBehavior.NO_ADVERTISE, -- SelectedListenerFailureBehavior.ACCEPT, -- supportedProtocols); -- } -- -- private SkipTestException tlsExtensionNotFound(Protocol protocol) { -- throw new SkipTestException(protocol + " not on classpath"); -- } -- -- private static final class SkipTestException extends RuntimeException { -- public SkipTestException(String message) { -- super(message); -- } -- } - } --- -2.7.4 - diff --git a/0002-Remove-NPN.patch b/0002-Remove-NPN.patch deleted file mode 100644 index 77a340a..0000000 --- a/0002-Remove-NPN.patch +++ /dev/null @@ -1,353 +0,0 @@ -From f7b8e27b5f55c4a21cf84fb56a616b8bfd4af8da Mon Sep 17 00:00:00 2001 -From: Michael Simacek <msimacek@redhat.com> -Date: Fri, 7 Jul 2017 16:07:23 +0200 -Subject: [PATCH 2/3] Remove NPN - ---- - handler/pom.xml | 5 - - .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 -------------------- - .../java/io/netty/handler/ssl/JdkSslContext.java | 30 ----- - .../io/netty/handler/ssl/JettyNpnSslEngine.java | 122 --------------------- - .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +- - 5 files changed, 1 insertion(+), 278 deletions(-) - delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java - delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java - -diff --git a/handler/pom.xml b/handler/pom.xml -index d0ed1bc..52e63ca 100644 ---- a/handler/pom.xml -+++ b/handler/pom.xml -@@ -55,11 +55,6 @@ - <optional>true</optional> - </dependency> - <dependency> -- <groupId>org.eclipse.jetty.npn</groupId> -- <artifactId>npn-api</artifactId> -- <optional>true</optional> -- </dependency> -- <dependency> - <groupId>org.eclipse.jetty.alpn</groupId> - <artifactId>alpn-api</artifactId> - <optional>true</optional> -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java -deleted file mode 100644 -index 06b29b7..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java -+++ /dev/null -@@ -1,120 +0,0 @@ --/* -- * Copyright 2014 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 javax.net.ssl.SSLEngine; -- --/** -- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}. -- */ --public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { -- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() { -- { -- if (!JettyNpnSslEngine.isAvailable()) { -- throw new RuntimeException("NPN unsupported. Is your classpath configured correctly?" -- + " See https://wiki.eclipse.org/Jetty/Feature/NPN"); -- } -- } -- -- @Override -- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, -- boolean isServer) { -- return new JettyNpnSslEngine(engine, applicationNegotiator, isServer); -- } -- }; -- -- /** -- * Create a new instance. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(Iterable<String> protocols) { -- this(false, protocols); -- } -- -- /** -- * Create a new instance. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(String... protocols) { -- this(false, protocols); -- } -- -- /** -- * Create a new instance. -- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) { -- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); -- } -- -- /** -- * Create a new instance. -- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) { -- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); -- } -- -- /** -- * Create a new instance. -- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. -- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, -- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) { -- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, -- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, -- protocols); -- } -- -- /** -- * Create a new instance. -- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. -- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, -- boolean serverFailIfNoCommonProtocols, String... protocols) { -- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, -- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, -- protocols); -- } -- -- /** -- * Create a new instance. -- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. -- * @param listenerFactory The factory which provides to be notified of which protocol was selected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, -- ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) { -- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols); -- } -- -- /** -- * Create a new instance. -- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. -- * @param listenerFactory The factory which provides to be notified of which protocol was selected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, -- ProtocolSelectionListenerFactory listenerFactory, String... protocols) { -- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols); -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java -index 0ad6639..d5b86ff 100644 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java -+++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java -@@ -288,47 +288,17 @@ public class JdkSslContext extends SslContext { - case ALPN: - if (isServer) { - switch(config.selectorFailureBehavior()) { -- case FATAL_ALERT: -- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- case NO_ADVERTISE: -- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); - default: - throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") - .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); - } - } else { - switch(config.selectedListenerFailureBehavior()) { -- case ACCEPT: -- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- case FATAL_ALERT: -- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); - default: - throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") - .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); - } - } -- case NPN: -- if (isServer) { -- switch(config.selectedListenerFailureBehavior()) { -- case ACCEPT: -- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- case FATAL_ALERT: -- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- default: -- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") -- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); -- } -- } else { -- switch(config.selectorFailureBehavior()) { -- case FATAL_ALERT: -- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- case NO_ADVERTISE: -- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- default: -- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") -- .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); -- } -- } - default: - throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") - .append(config.protocol()).append(" protocol").toString()); -diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java -deleted file mode 100644 -index 77e7366..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java -+++ /dev/null -@@ -1,122 +0,0 @@ --/* -- * Copyright 2014 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 static io.netty.util.internal.ObjectUtil.checkNotNull; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; --import io.netty.util.internal.PlatformDependent; -- --import java.util.LinkedHashSet; --import java.util.List; -- --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLException; -- --import org.eclipse.jetty.npn.NextProtoNego; --import org.eclipse.jetty.npn.NextProtoNego.ClientProvider; --import org.eclipse.jetty.npn.NextProtoNego.ServerProvider; -- --final class JettyNpnSslEngine extends JdkSslEngine { -- private static boolean available; -- -- static boolean isAvailable() { -- updateAvailability(); -- return available; -- } -- -- private static void updateAvailability() { -- if (available) { -- return; -- } -- try { -- // Always use bootstrap class loader. -- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null); -- available = true; -- } catch (Exception ignore) { -- // npn-boot was not loaded. -- } -- } -- -- JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) { -- super(engine); -- checkNotNull(applicationNegotiator, "applicationNegotiator"); -- -- if (server) { -- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator -- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), -- "protocolListener"); -- NextProtoNego.put(engine, new ServerProvider() { -- @Override -- public void unsupported() { -- protocolListener.unsupported(); -- } -- -- @Override -- public List<String> protocols() { -- return applicationNegotiator.protocols(); -- } -- -- @Override -- public void protocolSelected(String protocol) { -- try { -- protocolListener.selected(protocol); -- } catch (Throwable t) { -- PlatformDependent.throwException(t); -- } -- } -- }); -- } else { -- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() -- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())), -- "protocolSelector"); -- NextProtoNego.put(engine, new ClientProvider() { -- @Override -- public boolean supports() { -- return true; -- } -- -- @Override -- public void unsupported() { -- protocolSelector.unsupported(); -- } -- -- @Override -- public String selectProtocol(List<String> protocols) { -- try { -- return protocolSelector.select(protocols); -- } catch (Throwable t) { -- PlatformDependent.throwException(t); -- return null; -- } -- } -- }); -- } -- } -- -- @Override -- public void closeInbound() throws SSLException { -- NextProtoNego.remove(getWrappedEngine()); -- super.closeInbound(); -- } -- -- @Override -- public void closeOutbound() { -- NextProtoNego.remove(getWrappedEngine()); -- super.closeOutbound(); -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -index d6cd94d..4489b16 100644 ---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -@@ -46,7 +46,7 @@ public class JdkSslEngineTest extends SSLEngineTest { - NPN_DEFAULT { - @Override - boolean isAvailable() { -- return JettyNpnSslEngine.isAvailable(); -+ return false; - } - - @Override --- -2.9.4 - diff --git a/0002-Remove-optional-dep-conscrypt.patch b/0002-Remove-optional-dep-conscrypt.patch new file mode 100644 index 0000000..0a9cfef --- /dev/null +++ b/0002-Remove-optional-dep-conscrypt.patch @@ -0,0 +1,444 @@ +From 1a72454998ec91895648443c176ec41e542903e8 Mon Sep 17 00:00:00 2001 +From: Mat Booth <mat.booth@redhat.com> +Date: Mon, 7 Sep 2020 13:24:30 +0100 +Subject: [PATCH 2/5] Remove optional dep conscrypt + +--- + handler/pom.xml | 6 - + .../java/io/netty/handler/ssl/Conscrypt.java | 81 -------- + .../handler/ssl/ConscryptAlpnSslEngine.java | 196 ------------------ + .../JdkAlpnApplicationProtocolNegotiator.java | 8 +- + .../java/io/netty/handler/ssl/SslHandler.java | 47 +---- + pom.xml | 10 - + 6 files changed, 2 insertions(+), 346 deletions(-) + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/Conscrypt.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java + +diff --git a/handler/pom.xml b/handler/pom.xml +index c8e26119bd..378aeda2fe 100644 +--- a/handler/pom.xml ++++ b/handler/pom.xml +@@ -81,12 +81,6 @@ + <artifactId>alpn-api</artifactId> + <optional>true</optional> + </dependency> +- <dependency> +- <groupId>${conscrypt.groupId}</groupId> +- <artifactId>${conscrypt.artifactId}</artifactId> +- <classifier>${conscrypt.classifier}</classifier> +- <optional>true</optional> +- </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> +diff --git a/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java b/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java +deleted file mode 100644 +index d2f015f90f..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java ++++ /dev/null +@@ -1,81 +0,0 @@ +-/* +- * Copyright 2017 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.util.internal.PlatformDependent; +- +-import javax.net.ssl.SSLEngine; +-import java.lang.reflect.InvocationTargetException; +-import java.lang.reflect.Method; +- +-/** +- * Contains methods that can be used to detect if conscrypt is usable. +- */ +-final class Conscrypt { +- // This class exists to avoid loading other conscrypt related classes using features only available in JDK8+, +- // because we need to maintain JDK6+ runtime compatibility. +- private static final Method IS_CONSCRYPT_SSLENGINE = loadIsConscryptEngine(); +- private static final boolean CAN_INSTANCE_PROVIDER = canInstanceProvider(); +- +- private static Method loadIsConscryptEngine() { +- try { +- Class<?> conscryptClass = Class.forName("org.conscrypt.Conscrypt", true, +- ConscryptAlpnSslEngine.class.getClassLoader()); +- return conscryptClass.getMethod("isConscrypt", SSLEngine.class); +- } catch (Throwable ignore) { +- // Conscrypt was not loaded. +- return null; +- } +- } +- +- private static boolean canInstanceProvider() { +- try { +- Class<?> providerClass = Class.forName("org.conscrypt.OpenSSLProvider", true, +- ConscryptAlpnSslEngine.class.getClassLoader()); +- providerClass.newInstance(); +- return true; +- } catch (Throwable ignore) { +- return false; +- } +- } +- +- /** +- * Indicates whether or not conscrypt is available on the current system. +- */ +- static boolean isAvailable() { +- return CAN_INSTANCE_PROVIDER && IS_CONSCRYPT_SSLENGINE != null && +- ((PlatformDependent.javaVersion() >= 8 && +- // Only works on Java14 and earlier for now +- // See https://github.com/google/conscrypt/issues/838 +- PlatformDependent.javaVersion() < 15) || PlatformDependent.isAndroid()); +- } +- +- static boolean isEngineSupported(SSLEngine engine) { +- return isAvailable() && isConscryptEngine(engine); +- } +- +- private static boolean isConscryptEngine(SSLEngine engine) { +- try { +- return (Boolean) IS_CONSCRYPT_SSLENGINE.invoke(null, engine); +- } catch (IllegalAccessException ignore) { +- return false; +- } catch (InvocationTargetException ex) { +- throw new RuntimeException(ex); +- } +- } +- +- private Conscrypt() { } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java +deleted file mode 100644 +index d9767a7106..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java ++++ /dev/null +@@ -1,196 +0,0 @@ +-/* +- * Copyright 2017 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 static io.netty.handler.ssl.SslUtils.toSSLHandshakeException; +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import static java.lang.Math.min; +- +-import io.netty.buffer.ByteBuf; +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +-import java.nio.ByteBuffer; +-import java.util.Collections; +-import java.util.LinkedHashSet; +-import java.util.List; +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLEngineResult; +-import javax.net.ssl.SSLException; +- +-import io.netty.util.internal.SystemPropertyUtil; +-import org.conscrypt.AllocatedBuffer; +-import org.conscrypt.BufferAllocator; +-import org.conscrypt.Conscrypt; +-import org.conscrypt.HandshakeListener; +- +-/** +- * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN. +- */ +-abstract class ConscryptAlpnSslEngine extends JdkSslEngine { +- private static final boolean USE_BUFFER_ALLOCATOR = SystemPropertyUtil.getBoolean( +- "io.netty.handler.ssl.conscrypt.useBufferAllocator", true); +- +- static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, ByteBufAllocator alloc, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- return new ClientEngine(engine, alloc, applicationNegotiator); +- } +- +- static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine, ByteBufAllocator alloc, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- return new ServerEngine(engine, alloc, applicationNegotiator); +- } +- +- private ConscryptAlpnSslEngine(SSLEngine engine, ByteBufAllocator alloc, List<String> protocols) { +- super(engine); +- +- // Configure the Conscrypt engine to use Netty's buffer allocator. This is a trade-off of memory vs +- // performance. +- // +- // If no allocator is provided, the engine will internally allocate a direct buffer of max packet size in +- // order to optimize JNI calls (this happens the first time it is provided a non-direct buffer from the +- // application). +- // +- // Alternatively, if an allocator is provided, no internal buffer will be created and direct buffers will be +- // retrieved from the allocator on-demand. +- if (USE_BUFFER_ALLOCATOR) { +- Conscrypt.setBufferAllocator(engine, new BufferAllocatorAdapter(alloc)); +- } +- +- // Set the list of supported ALPN protocols on the engine. +- Conscrypt.setApplicationProtocols(engine, protocols.toArray(new String[0])); +- } +- +- /** +- * Calculates the maximum size of the encrypted output buffer required to wrap the given plaintext bytes. Assumes +- * as a worst case that there is one TLS record per buffer. +- * +- * @param plaintextBytes the number of plaintext bytes to be wrapped. +- * @param numBuffers the number of buffers that the plaintext bytes are spread across. +- * @return the maximum size of the encrypted output buffer required for the wrap operation. +- */ +- final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) { +- // Assuming a max of one frame per component in a composite buffer. +- long maxOverhead = (long) Conscrypt.maxSealOverhead(getWrappedEngine()) * numBuffers; +- // TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of Integer.MAX_VALUE +- return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead); +- } +- +- final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws SSLException { +- return Conscrypt.unwrap(getWrappedEngine(), srcs, dests); +- } +- +- private static final class ClientEngine extends ConscryptAlpnSslEngine { +- private final ProtocolSelectionListener protocolListener; +- +- ClientEngine(SSLEngine engine, ByteBufAllocator alloc, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- super(engine, alloc, applicationNegotiator.protocols()); +- // Register for completion of the handshake. +- Conscrypt.setHandshakeListener(engine, new HandshakeListener() { +- @Override +- public void onHandshakeFinished() throws SSLException { +- selectProtocol(); +- } +- }); +- +- protocolListener = checkNotNull(applicationNegotiator +- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), +- "protocolListener"); +- } +- +- private void selectProtocol() throws SSLException { +- String protocol = Conscrypt.getApplicationProtocol(getWrappedEngine()); +- try { +- protocolListener.selected(protocol); +- } catch (Throwable e) { +- throw toSSLHandshakeException(e); +- } +- } +- } +- +- private static final class ServerEngine extends ConscryptAlpnSslEngine { +- private final ProtocolSelector protocolSelector; +- +- ServerEngine(SSLEngine engine, ByteBufAllocator alloc, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- super(engine, alloc, applicationNegotiator.protocols()); +- +- // Register for completion of the handshake. +- Conscrypt.setHandshakeListener(engine, new HandshakeListener() { +- @Override +- public void onHandshakeFinished() throws SSLException { +- selectProtocol(); +- } +- }); +- +- protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() +- .newSelector(this, +- new LinkedHashSet<String>(applicationNegotiator.protocols())), +- "protocolSelector"); +- } +- +- private void selectProtocol() throws SSLException { +- try { +- String protocol = Conscrypt.getApplicationProtocol(getWrappedEngine()); +- protocolSelector.select(protocol != null ? Collections.singletonList(protocol) +- : Collections.<String>emptyList()); +- } catch (Throwable e) { +- throw toSSLHandshakeException(e); +- } +- } +- } +- +- private static final class BufferAllocatorAdapter extends BufferAllocator { +- private final ByteBufAllocator alloc; +- +- BufferAllocatorAdapter(ByteBufAllocator alloc) { +- this.alloc = alloc; +- } +- +- @Override +- public AllocatedBuffer allocateDirectBuffer(int capacity) { +- return new BufferAdapter(alloc.directBuffer(capacity)); +- } +- } +- +- private static final class BufferAdapter extends AllocatedBuffer { +- private final ByteBuf nettyBuffer; +- private final ByteBuffer buffer; +- +- BufferAdapter(ByteBuf nettyBuffer) { +- this.nettyBuffer = nettyBuffer; +- buffer = nettyBuffer.nioBuffer(0, nettyBuffer.capacity()); +- } +- +- @Override +- public ByteBuffer nioBuffer() { +- return buffer; +- } +- +- @Override +- public AllocatedBuffer retain() { +- nettyBuffer.retain(); +- return this; +- } +- +- @Override +- public AllocatedBuffer release() { +- nettyBuffer.release(); +- return this; +- } +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +index c4ca7b9b8c..2ed83a313b 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java ++++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +@@ -26,8 +26,7 @@ import javax.net.ssl.SSLEngine; + */ + @Deprecated + public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { +- private static final boolean AVAILABLE = Conscrypt.isAvailable() || +- JdkAlpnSslUtils.supportsAlpn() || ++ private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn() || + JettyAlpnSslEngine.isAvailable(); + + private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper(); +@@ -119,7 +118,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati + public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc, + JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) { + throw new RuntimeException("ALPN unsupported. Is your classpath configured correctly?" +- + " For Conscrypt, add the appropriate Conscrypt JAR to classpath and set the security provider." + + " For Jetty-ALPN, see " + + "http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-starting"); + } +@@ -129,10 +127,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati + @Override + public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc, + JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) { +- if (Conscrypt.isEngineSupported(engine)) { +- return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc, applicationNegotiator) +- : ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator); +- } + // ALPN support was recently backported to Java8 as + // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8230977. + // Because of this lets not do a Java version runtime check but just depend on if the required methods are +diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +index de101967ba..8e11bbf4cc 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java ++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +@@ -228,50 +228,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode; + } + }, +- CONSCRYPT(true, COMPOSITE_CUMULATOR) { +- @Override +- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) +- throws SSLException { +- int nioBufferCount = in.nioBufferCount(); +- int writerIndex = out.writerIndex(); +- final SSLEngineResult result; +- if (nioBufferCount > 1) { +- /* +- * Use a special unwrap method without additional memory copies. +- */ +- try { +- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes()); +- result = ((ConscryptAlpnSslEngine) handler.engine).unwrap( +- in.nioBuffers(readerIndex, len), +- handler.singleBuffer); +- } finally { +- handler.singleBuffer[0] = null; +- } +- } else { +- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len), +- toByteBuffer(out, writerIndex, out.writableBytes())); +- } +- out.writerIndex(writerIndex + result.bytesProduced()); +- return result; +- } +- +- @Override +- ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator, +- int pendingBytes, int numComponents) { +- return allocator.directBuffer( +- ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents)); +- } +- +- @Override +- int calculatePendingData(SslHandler handler, int guess) { +- return guess; +- } +- +- @Override +- boolean jdkCompatibilityMode(SSLEngine engine) { +- return true; +- } +- }, + JDK(false, MERGE_CUMULATOR) { + @Override + SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) +@@ -324,8 +280,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + }; + + static SslEngineType forEngine(SSLEngine engine) { +- return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : +- engine instanceof ConscryptAlpnSslEngine ? CONSCRYPT : JDK; ++ return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : JDK; + } + + SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) { +diff --git a/pom.xml b/pom.xml +index d548aa5513..db3d7b0d38 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -489,16 +489,6 @@ + <optional>true</optional> + </dependency> + +- <!-- Conscrypt - needed for running tests, used for acclerating SSL with OpenSSL. --> +- <dependency> +- <groupId>${conscrypt.groupId}</groupId> +- <artifactId>${conscrypt.artifactId}</artifactId> +- <classifier>${conscrypt.classifier}</classifier> +- <version>${conscrypt.version}</version> +- <scope>compile</scope> +- <optional>true</optional> +- </dependency> +- + <!-- + Bouncy Castle - completely optional, only needed when: + - you generate a temporary self-signed certificate using SelfSignedCertificate, and +-- +2.26.2 + diff --git a/0003-Remove-conscrypt-ALPN.patch b/0003-Remove-conscrypt-ALPN.patch deleted file mode 100644 index e71ba5a..0000000 --- a/0003-Remove-conscrypt-ALPN.patch +++ /dev/null @@ -1,511 +0,0 @@ -From 039534e20546221c3466d1ceb663625c59edb0e7 Mon Sep 17 00:00:00 2001 -From: Michael Simacek <msimacek@redhat.com> -Date: Tue, 11 Jul 2017 13:37:22 +0200 -Subject: [PATCH 3/3] Remove conscrypt ALPN - ---- - handler/pom.xml | 6 - - .../netty/handler/ssl/ConscryptAlpnSslEngine.java | 176 --------------------- - .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 6 +- - .../main/java/io/netty/handler/ssl/SslHandler.java | 35 ---- - .../ssl/ConscryptJdkSslEngineInteropTest.java | 76 --------- - .../io/netty/handler/ssl/Java8SslTestUtils.java | 7 - - .../ssl/JdkConscryptSslEngineInteropTest.java | 86 ---------- - .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +- - 8 files changed, 2 insertions(+), 392 deletions(-) - delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java - -diff --git a/handler/pom.xml b/handler/pom.xml -index 52e63ca..69af32a 100644 ---- a/handler/pom.xml -+++ b/handler/pom.xml -@@ -60,12 +60,6 @@ - <optional>true</optional> - </dependency> - <dependency> -- <groupId>${conscrypt.groupId}</groupId> -- <artifactId>${conscrypt.artifactId}</artifactId> -- <classifier>${conscrypt.classifier}</classifier> -- <optional>true</optional> -- </dependency> -- <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - </dependency> -diff --git a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java -deleted file mode 100644 -index 8e7a544..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java -+++ /dev/null -@@ -1,176 +0,0 @@ --/* -- * Copyright 2017 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 static io.netty.handler.ssl.SslUtils.toSSLHandshakeException; --import static io.netty.util.internal.ObjectUtil.checkNotNull; --import static java.lang.Math.min; -- --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; --import java.lang.reflect.Method; --import java.nio.ByteBuffer; --import java.util.Collections; --import java.util.LinkedHashSet; --import java.util.List; --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLEngineResult; --import javax.net.ssl.SSLException; -- --import io.netty.util.internal.PlatformDependent; --import org.conscrypt.Conscrypt; --import org.conscrypt.HandshakeListener; -- --/** -- * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN. -- */ --abstract class ConscryptAlpnSslEngine extends JdkSslEngine { -- private static final Class<?> ENGINES_CLASS = getEnginesClass(); -- -- /** -- * Indicates whether or not conscrypt is available on the current system. -- */ -- static boolean isAvailable() { -- return ENGINES_CLASS != null && PlatformDependent.javaVersion() >= 8; -- } -- -- static boolean isEngineSupported(SSLEngine engine) { -- return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS); -- } -- -- static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, -- JdkApplicationProtocolNegotiator applicationNegotiator) { -- return new ClientEngine(engine, applicationNegotiator); -- } -- -- static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine, -- JdkApplicationProtocolNegotiator applicationNegotiator) { -- return new ServerEngine(engine, applicationNegotiator); -- } -- -- private ConscryptAlpnSslEngine(SSLEngine engine, List<String> protocols) { -- super(engine); -- -- // Set the list of supported ALPN protocols on the engine. -- Conscrypt.Engines.setAlpnProtocols(engine, protocols.toArray(new String[protocols.size()])); -- } -- -- /** -- * Calculates the maximum size of the encrypted output buffer required to wrap the given plaintext bytes. Assumes -- * as a worst case that there is one TLS record per buffer. -- * -- * @param plaintextBytes the number of plaintext bytes to be wrapped. -- * @param numBuffers the number of buffers that the plaintext bytes are spread across. -- * @return the maximum size of the encrypted output buffer required for the wrap operation. -- */ -- final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) { -- // Assuming a max of one frame per component in a composite buffer. -- long maxOverhead = (long) Conscrypt.Engines.maxSealOverhead(getWrappedEngine()) * numBuffers; -- // TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of Integer.MAX_VALUE -- return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead); -- } -- -- final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws SSLException { -- return Conscrypt.Engines.unwrap(getWrappedEngine(), srcs, dests); -- } -- -- private static final class ClientEngine extends ConscryptAlpnSslEngine { -- private final ProtocolSelectionListener protocolListener; -- -- ClientEngine(SSLEngine engine, -- JdkApplicationProtocolNegotiator applicationNegotiator) { -- super(engine, applicationNegotiator.protocols()); -- // Register for completion of the handshake. -- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() { -- @Override -- public void onHandshakeFinished() throws SSLException { -- selectProtocol(); -- } -- }); -- -- protocolListener = checkNotNull(applicationNegotiator -- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), -- "protocolListener"); -- } -- -- private void selectProtocol() throws SSLException { -- String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine()); -- try { -- protocolListener.selected(protocol); -- } catch (Throwable e) { -- throw toSSLHandshakeException(e); -- } -- } -- } -- -- private static final class ServerEngine extends ConscryptAlpnSslEngine { -- private final ProtocolSelector protocolSelector; -- -- ServerEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator) { -- super(engine, applicationNegotiator.protocols()); -- -- // Register for completion of the handshake. -- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() { -- @Override -- public void onHandshakeFinished() throws SSLException { -- selectProtocol(); -- } -- }); -- -- protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() -- .newSelector(this, -- new LinkedHashSet<String>(applicationNegotiator.protocols())), -- "protocolSelector"); -- } -- -- private void selectProtocol() throws SSLException { -- try { -- String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine()); -- protocolSelector.select(protocol != null ? Collections.singletonList(protocol) -- : Collections.<String>emptyList()); -- } catch (Throwable e) { -- throw toSSLHandshakeException(e); -- } -- } -- } -- -- private static Class<?> getEnginesClass() { -- try { -- // Always use bootstrap class loader. -- Class<?> engineClass = Class.forName("org.conscrypt.Conscrypt$Engines", true, -- ConscryptAlpnSslEngine.class.getClassLoader()); -- // Ensure that it also has the isConscrypt method. -- getIsConscryptMethod(engineClass); -- return engineClass; -- } catch (Throwable ignore) { -- // Conscrypt was not loaded. -- return null; -- } -- } -- -- private static boolean isConscryptEngine(SSLEngine engine, Class<?> enginesClass) { -- try { -- Method method = getIsConscryptMethod(enginesClass); -- return (Boolean) method.invoke(null, engine); -- } catch (Throwable ignore) { -- return false; -- } -- } -- -- private static Method getIsConscryptMethod(Class<?> enginesClass) throws NoSuchMethodException { -- return enginesClass.getMethod("isConscrypt", SSLEngine.class); -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java -index f82c7da..9c4ab9e 100644 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java -+++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java -@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine; - * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}. - */ - public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { -- private static final boolean AVAILABLE = ConscryptAlpnSslEngine.isAvailable() || JettyAlpnSslEngine.isAvailable(); -+ private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable(); - private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper(); - - /** -@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati - @Override - public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, - boolean isServer) { -- if (ConscryptAlpnSslEngine.isEngineSupported(engine)) { -- return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, applicationNegotiator) -- : ConscryptAlpnSslEngine.newClientEngine(engine, applicationNegotiator); -- } - if (JettyAlpnSslEngine.isAvailable()) { - return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator) - : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator); -diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java -index 05c451a..8693011 100644 ---- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java -+++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java -@@ -187,38 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - new ClosedChannelException(), SslHandler.class, "channelInactive(...)"); - - private enum SslEngineType { -- CONSCRYPT(true, COMPOSITE_CUMULATOR) { -- @Override -- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) -- throws SSLException { -- int nioBufferCount = in.nioBufferCount(); -- int writerIndex = out.writerIndex(); -- final SSLEngineResult result; -- if (nioBufferCount > 1) { -- /* -- * Use a special unwrap method without additional memory copies. -- */ -- try { -- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes()); -- result = ((ConscryptAlpnSslEngine) handler.engine).unwrap( -- in.nioBuffers(readerIndex, len), -- handler.singleBuffer); -- } finally { -- handler.singleBuffer[0] = null; -- } -- } else { -- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len), -- toByteBuffer(out, writerIndex, out.writableBytes())); -- } -- out.writerIndex(writerIndex + result.bytesProduced()); -- return result; -- } -- -- @Override -- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) { -- return ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents); -- } -- }, - JDK(false, MERGE_CUMULATOR) { - @Override - SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) -@@ -237,9 +205,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - }; - - static SslEngineType forEngine(SSLEngine engine) { -- if (engine instanceof ConscryptAlpnSslEngine) { -- return CONSCRYPT; -- } - return JDK; - } - -diff --git a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java -deleted file mode 100644 -index e217136..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java -+++ /dev/null -@@ -1,76 +0,0 @@ --/* -- * 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 java.security.Provider; --import org.junit.BeforeClass; --import org.junit.Ignore; -- --import org.junit.runner.RunWith; --import org.junit.runners.Parameterized; -- --import java.util.ArrayList; --import java.util.Collection; --import java.util.List; -- --import static org.junit.Assume.assumeTrue; -- --@RunWith(Parameterized.class) --public class ConscryptJdkSslEngineInteropTest extends SSLEngineTest { -- -- @Parameterized.Parameters(name = "{index}: bufferType = {0}") -- public static Collection<Object> data() { -- List<Object> params = new ArrayList<Object>(); -- for (BufferType type: BufferType.values()) { -- params.add(type); -- } -- return params; -- } -- -- public ConscryptJdkSslEngineInteropTest(BufferType type) { -- super(type); -- } -- -- @BeforeClass -- public static void checkConscrypt() { -- assumeTrue(ConscryptAlpnSslEngine.isAvailable()); -- } -- -- @Override -- protected SslProvider sslClientProvider() { -- return SslProvider.JDK; -- } -- -- @Override -- protected SslProvider sslServerProvider() { -- return SslProvider.JDK; -- } -- -- @Override -- protected Provider clientSslContextProvider() { -- return Java8SslTestUtils.conscryptProvider(); -- } -- -- @Ignore /* Does the JDK support a "max certificate chain length"? */ -- @Override -- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { -- } -- -- @Ignore /* Does the JDK support a "max certificate chain length"? */ -- @Override -- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java -index cc2e6c6..f9cf771 100644 ---- a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java -+++ b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java -@@ -16,12 +16,9 @@ - - package io.netty.handler.ssl; - --import org.conscrypt.OpenSSLProvider; -- - import javax.net.ssl.SNIMatcher; - import javax.net.ssl.SNIServerName; - import javax.net.ssl.SSLParameters; --import java.security.Provider; - import java.util.Collections; - - final class Java8SslTestUtils { -@@ -37,8 +34,4 @@ final class Java8SslTestUtils { - }; - parameters.setSNIMatchers(Collections.singleton(matcher)); - } -- -- static Provider conscryptProvider() { -- return new OpenSSLProvider(); -- } - } -diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java -deleted file mode 100644 -index 0625f7a..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java -+++ /dev/null -@@ -1,86 +0,0 @@ --/* -- * Copyright 2017 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 java.security.Provider; --import org.junit.BeforeClass; --import org.junit.Ignore; --import org.junit.Test; --import org.junit.runner.RunWith; --import org.junit.runners.Parameterized; -- --import java.util.ArrayList; --import java.util.Collection; --import java.util.List; -- --import static org.junit.Assume.assumeTrue; -- --@RunWith(Parameterized.class) --public class JdkConscryptSslEngineInteropTest extends SSLEngineTest { -- -- @Parameterized.Parameters(name = "{index}: bufferType = {0}") -- public static Collection<Object> data() { -- List<Object> params = new ArrayList<Object>(); -- for (BufferType type: BufferType.values()) { -- params.add(type); -- } -- return params; -- } -- -- public JdkConscryptSslEngineInteropTest(BufferType type) { -- super(type); -- } -- -- @BeforeClass -- public static void checkConscrypt() { -- assumeTrue(ConscryptAlpnSslEngine.isAvailable()); -- } -- -- @Override -- protected SslProvider sslClientProvider() { -- return SslProvider.JDK; -- } -- -- @Override -- protected SslProvider sslServerProvider() { -- return SslProvider.JDK; -- } -- -- @Override -- protected Provider serverSslContextProvider() { -- return Java8SslTestUtils.conscryptProvider(); -- } -- -- @Override -- @Test -- @Ignore("TODO: Make this work with Conscrypt") -- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { -- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth(); -- } -- -- @Override -- @Test -- @Ignore("TODO: Make this work with Conscrypt") -- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { -- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth(); -- } -- -- @Override -- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) { -- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. -- return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause); -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -index 4489b16..e32fa0d 100644 ---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -@@ -81,7 +81,7 @@ public class JdkSslEngineTest extends SSLEngineTest { - - @Override - boolean isAvailable() { -- return ConscryptAlpnSslEngine.isAvailable(); -+ return false; - } - - @Override --- -2.9.4 - diff --git a/0003-Remove-optional-deps-jetty-alpn-and-npn.patch b/0003-Remove-optional-deps-jetty-alpn-and-npn.patch new file mode 100644 index 0000000..6e74960 --- /dev/null +++ b/0003-Remove-optional-deps-jetty-alpn-and-npn.patch @@ -0,0 +1,405 @@ +From cb6b51eed1faef580120e19aa1b5404c19a9398b Mon Sep 17 00:00:00 2001 +From: Mat Booth mat.booth@redhat.com +Date: Mon, 7 Sep 2020 13:26:20 +0100 +Subject: [PATCH 3/5] Remove optional deps jetty alpn and npn + +--- + handler/pom.xml | 10 -- + .../JdkAlpnApplicationProtocolNegotiator.java | 7 +- + .../JdkNpnApplicationProtocolNegotiator.java | 10 +- + .../netty/handler/ssl/JettyAlpnSslEngine.java | 157 ------------------ + .../netty/handler/ssl/JettyNpnSslEngine.java | 122 -------------- + pom.xml | 14 -- + 6 files changed, 3 insertions(+), 317 deletions(-) + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java + +diff --git a/handler/pom.xml b/handler/pom.xml +index 378aeda2fe..be8206dc89 100644 +--- a/handler/pom.xml ++++ b/handler/pom.xml +@@ -71,16 +71,6 @@ + <artifactId>bcpkix-jdk15on</artifactId> + <optional>true</optional> + </dependency> +- <dependency> +- <groupId>org.eclipse.jetty.npn</groupId> +- <artifactId>npn-api</artifactId> +- <optional>true</optional> +- </dependency> +- <dependency> +- <groupId>org.eclipse.jetty.alpn</groupId> +- <artifactId>alpn-api</artifactId> +- <optional>true</optional> +- </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +index 2ed83a313b..dbd5ed9f07 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java ++++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +@@ -26,8 +26,7 @@ import javax.net.ssl.SSLEngine; + */ + @Deprecated + public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { +- private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn() || +- JettyAlpnSslEngine.isAvailable(); ++ private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn(); + + private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper(); + +@@ -134,10 +133,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati + if (JdkAlpnSslUtils.supportsAlpn()) { + return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer); + } +- if (JettyAlpnSslEngine.isAvailable()) { +- return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator) +- : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator); +- } + throw new UnsupportedOperationException("ALPN not supported. Unable to wrap SSLEngine of type '" + + engine.getClass().getName() + "')"); + } +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java +index 3c2863b66c..2703336e8b 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java ++++ b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java +@@ -25,17 +25,11 @@ import javax.net.ssl.SSLEngine; + @Deprecated + public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { + private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() { +- { +- if (!JettyNpnSslEngine.isAvailable()) { +- throw new RuntimeException("NPN unsupported. Is your classpath configured correctly?" +- + " See https://wiki.eclipse.org/Jetty/Feature/NPN"); +- } +- } +- + @Override + public SSLEngine wrapSslEngine(SSLEngine engine, + JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) { +- return new JettyNpnSslEngine(engine, applicationNegotiator, isServer); ++ throw new UnsupportedOperationException("NPN not supported. Unable to wrap SSLEngine of type '" ++ + engine.getClass().getName() + "')"); + } + }; + +diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java +deleted file mode 100644 +index ce9f14a57e..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java ++++ /dev/null +@@ -1,157 +0,0 @@ +-/* +- * Copyright 2014 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 static io.netty.handler.ssl.SslUtils.toSSLHandshakeException; +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +- +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +- +-import java.util.LinkedHashSet; +-import java.util.List; +- +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +- +-import io.netty.util.internal.PlatformDependent; +-import org.eclipse.jetty.alpn.ALPN; +- +-abstract class JettyAlpnSslEngine extends JdkSslEngine { +- private static final boolean available = initAvailable(); +- +- static boolean isAvailable() { +- return available; +- } +- +- private static boolean initAvailable() { +- if (PlatformDependent.javaVersion() <= 8) { +- try { +- // Always use bootstrap class loader. +- Class.forName("sun.security.ssl.ALPNExtension", true, null); +- return true; +- } catch (Throwable ignore) { +- // alpn-boot was not loaded. +- } +- } +- return false; +- } +- +- static JettyAlpnSslEngine newClientEngine(SSLEngine engine, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- return new ClientEngine(engine, applicationNegotiator); +- } +- +- static JettyAlpnSslEngine newServerEngine(SSLEngine engine, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- return new ServerEngine(engine, applicationNegotiator); +- } +- +- private JettyAlpnSslEngine(SSLEngine engine) { +- super(engine); +- } +- +- private static final class ClientEngine extends JettyAlpnSslEngine { +- ClientEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) { +- super(engine); +- checkNotNull(applicationNegotiator, "applicationNegotiator"); +- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator +- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), +- "protocolListener"); +- ALPN.put(engine, new ALPN.ClientProvider() { +- @Override +- public List<String> protocols() { +- return applicationNegotiator.protocols(); +- } +- +- @Override +- public void selected(String protocol) throws SSLException { +- try { +- protocolListener.selected(protocol); +- } catch (Throwable t) { +- throw toSSLHandshakeException(t); +- } +- } +- +- @Override +- public void unsupported() { +- protocolListener.unsupported(); +- } +- }); +- } +- +- @Override +- public void closeInbound() throws SSLException { +- try { +- ALPN.remove(getWrappedEngine()); +- } finally { +- super.closeInbound(); +- } +- } +- +- @Override +- public void closeOutbound() { +- try { +- ALPN.remove(getWrappedEngine()); +- } finally { +- super.closeOutbound(); +- } +- } +- } +- +- private static final class ServerEngine extends JettyAlpnSslEngine { +- ServerEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) { +- super(engine); +- checkNotNull(applicationNegotiator, "applicationNegotiator"); +- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() +- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())), +- "protocolSelector"); +- ALPN.put(engine, new ALPN.ServerProvider() { +- @Override +- public String select(List<String> protocols) throws SSLException { +- try { +- return protocolSelector.select(protocols); +- } catch (Throwable t) { +- throw toSSLHandshakeException(t); +- } +- } +- +- @Override +- public void unsupported() { +- protocolSelector.unsupported(); +- } +- }); +- } +- +- @Override +- public void closeInbound() throws SSLException { +- try { +- ALPN.remove(getWrappedEngine()); +- } finally { +- super.closeInbound(); +- } +- } +- +- @Override +- public void closeOutbound() { +- try { +- ALPN.remove(getWrappedEngine()); +- } finally { +- super.closeOutbound(); +- } +- } +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java +deleted file mode 100644 +index 77e7366e53..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java ++++ /dev/null +@@ -1,122 +0,0 @@ +-/* +- * Copyright 2014 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 static io.netty.util.internal.ObjectUtil.checkNotNull; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +-import io.netty.util.internal.PlatformDependent; +- +-import java.util.LinkedHashSet; +-import java.util.List; +- +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +- +-import org.eclipse.jetty.npn.NextProtoNego; +-import org.eclipse.jetty.npn.NextProtoNego.ClientProvider; +-import org.eclipse.jetty.npn.NextProtoNego.ServerProvider; +- +-final class JettyNpnSslEngine extends JdkSslEngine { +- private static boolean available; +- +- static boolean isAvailable() { +- updateAvailability(); +- return available; +- } +- +- private static void updateAvailability() { +- if (available) { +- return; +- } +- try { +- // Always use bootstrap class loader. +- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null); +- available = true; +- } catch (Exception ignore) { +- // npn-boot was not loaded. +- } +- } +- +- JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) { +- super(engine); +- checkNotNull(applicationNegotiator, "applicationNegotiator"); +- +- if (server) { +- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator +- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), +- "protocolListener"); +- NextProtoNego.put(engine, new ServerProvider() { +- @Override +- public void unsupported() { +- protocolListener.unsupported(); +- } +- +- @Override +- public List<String> protocols() { +- return applicationNegotiator.protocols(); +- } +- +- @Override +- public void protocolSelected(String protocol) { +- try { +- protocolListener.selected(protocol); +- } catch (Throwable t) { +- PlatformDependent.throwException(t); +- } +- } +- }); +- } else { +- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() +- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())), +- "protocolSelector"); +- NextProtoNego.put(engine, new ClientProvider() { +- @Override +- public boolean supports() { +- return true; +- } +- +- @Override +- public void unsupported() { +- protocolSelector.unsupported(); +- } +- +- @Override +- public String selectProtocol(List<String> protocols) { +- try { +- return protocolSelector.select(protocols); +- } catch (Throwable t) { +- PlatformDependent.throwException(t); +- return null; +- } +- } +- }); +- } +- } +- +- @Override +- public void closeInbound() throws SSLException { +- NextProtoNego.remove(getWrappedEngine()); +- super.closeInbound(); +- } +- +- @Override +- public void closeOutbound() { +- NextProtoNego.remove(getWrappedEngine()); +- super.closeOutbound(); +- } +-} +diff --git a/pom.xml b/pom.xml +index db3d7b0d38..bedd6d6903 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -453,20 +453,6 @@ + <optional>true</optional> + </dependency> + +- <!-- SPDY and HTTP/2 - completely optional --> +- <dependency> +- <groupId>org.eclipse.jetty.npn</groupId> +- <artifactId>npn-api</artifactId> +- <version>1.1.1.v20141010</version> +- <scope>provided</scope> <!-- Provided by npn-boot --> +- </dependency> +- <dependency> +- <groupId>org.eclipse.jetty.alpn</groupId> +- <artifactId>alpn-api</artifactId> +- <version>1.1.2.v20150522</version> +- <scope>provided</scope> <!-- Provided by alpn-boot --> +- </dependency> +- + <!-- Google Protocol Buffers - completely optional --> + <dependency> + <groupId>com.google.protobuf</groupId> +-- +2.26.2 + diff --git a/0004-Remove-jetty-ALPN.patch b/0004-Remove-jetty-ALPN.patch deleted file mode 100644 index 42b5415..0000000 --- a/0004-Remove-jetty-ALPN.patch +++ /dev/null @@ -1,217 +0,0 @@ -diff --git a/handler/pom.xml b/handler/pom.xml -index 69af32a..b9e5596 100644 ---- a/handler/pom.xml -+++ b/handler/pom.xml -@@ -54,11 +54,6 @@ - <artifactId>bcpkix-jdk15on</artifactId> - <optional>true</optional> - </dependency> -- <dependency> -- <groupId>org.eclipse.jetty.alpn</groupId> -- <artifactId>alpn-api</artifactId> -- <optional>true</optional> -- </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java -index 9c4ab9e..5cc1ab7 100644 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java -+++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java -@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine; - * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}. - */ - public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { -- private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable(); -+ private static final boolean AVAILABLE = false; - private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper(); - - /** -@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati - @Override - public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, - boolean isServer) { -- if (JettyAlpnSslEngine.isAvailable()) { -- return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator) -- : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator); -- } - throw new RuntimeException("Unable to wrap SSLEngine of type " + engine.getClass().getName()); - } - } -diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java -deleted file mode 100644 -index 624719a..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java -+++ /dev/null -@@ -1,158 +0,0 @@ --/* -- * Copyright 2014 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 static io.netty.handler.ssl.SslUtils.toSSLHandshakeException; --import static io.netty.util.internal.ObjectUtil.checkNotNull; -- --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; -- --import java.util.LinkedHashSet; --import java.util.List; -- --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLException; -- --import io.netty.util.internal.PlatformDependent; --import org.eclipse.jetty.alpn.ALPN; -- --abstract class JettyAlpnSslEngine extends JdkSslEngine { -- private static final boolean available = initAvailable(); -- -- static boolean isAvailable() { -- return available; -- } -- -- private static boolean initAvailable() { -- // TODO: Add support for ALPN when using Java9 and still be able to configure it the Netty way. -- if (PlatformDependent.javaVersion() <= 8) { -- try { -- // Always use bootstrap class loader. -- Class.forName("sun.security.ssl.ALPNExtension", true, null); -- return true; -- } catch (Throwable ignore) { -- // alpn-boot was not loaded. -- } -- } -- return false; -- } -- -- static JettyAlpnSslEngine newClientEngine(SSLEngine engine, -- JdkApplicationProtocolNegotiator applicationNegotiator) { -- return new ClientEngine(engine, applicationNegotiator); -- } -- -- static JettyAlpnSslEngine newServerEngine(SSLEngine engine, -- JdkApplicationProtocolNegotiator applicationNegotiator) { -- return new ServerEngine(engine, applicationNegotiator); -- } -- -- private JettyAlpnSslEngine(SSLEngine engine) { -- super(engine); -- } -- -- private static final class ClientEngine extends JettyAlpnSslEngine { -- ClientEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) { -- super(engine); -- checkNotNull(applicationNegotiator, "applicationNegotiator"); -- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator -- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), -- "protocolListener"); -- ALPN.put(engine, new ALPN.ClientProvider() { -- @Override -- public List<String> protocols() { -- return applicationNegotiator.protocols(); -- } -- -- @Override -- public void selected(String protocol) throws SSLException { -- try { -- protocolListener.selected(protocol); -- } catch (Throwable t) { -- throw toSSLHandshakeException(t); -- } -- } -- -- @Override -- public void unsupported() { -- protocolListener.unsupported(); -- } -- }); -- } -- -- @Override -- public void closeInbound() throws SSLException { -- try { -- ALPN.remove(getWrappedEngine()); -- } finally { -- super.closeInbound(); -- } -- } -- -- @Override -- public void closeOutbound() { -- try { -- ALPN.remove(getWrappedEngine()); -- } finally { -- super.closeOutbound(); -- } -- } -- } -- -- private static final class ServerEngine extends JettyAlpnSslEngine { -- ServerEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) { -- super(engine); -- checkNotNull(applicationNegotiator, "applicationNegotiator"); -- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() -- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())), -- "protocolSelector"); -- ALPN.put(engine, new ALPN.ServerProvider() { -- @Override -- public String select(List<String> protocols) throws SSLException { -- try { -- return protocolSelector.select(protocols); -- } catch (Throwable t) { -- throw toSSLHandshakeException(t); -- } -- } -- -- @Override -- public void unsupported() { -- protocolSelector.unsupported(); -- } -- }); -- } -- -- @Override -- public void closeInbound() throws SSLException { -- try { -- ALPN.remove(getWrappedEngine()); -- } finally { -- super.closeInbound(); -- } -- } -- -- @Override -- public void closeOutbound() { -- try { -- ALPN.remove(getWrappedEngine()); -- } finally { -- super.closeOutbound(); -- } -- } -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -index e32fa0d..a8014e5 100644 ---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -@@ -62,7 +62,7 @@ public class JdkSslEngineTest extends SSLEngineTest { - ALPN_DEFAULT { - @Override - boolean isAvailable() { -- return JettyAlpnSslEngine.isAvailable(); -+ return false; - } - - @Override diff --git a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch b/0004-Remove-optional-dep-tcnative.patch similarity index 54% rename from 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch rename to 0004-Remove-optional-dep-tcnative.patch index aee0650..6ed11bd 100644 --- a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch +++ b/0004-Remove-optional-dep-tcnative.patch @@ -1,108 +1,94 @@ -From 39b320920d3473d8cbc94d4a35dad37fa236e278 Mon Sep 17 00:00:00 2001 -From: Severin Gehwolf sgehwolf@redhat.com -Date: Thu, 20 Oct 2016 15:54:52 +0200 -Subject: [PATCH 1/3] Remove OpenSSL parts depending on tcnative. +From c60f3b8d7ca0575bba15682a329dced786f898da Mon Sep 17 00:00:00 2001 +From: Mat Booth mat.booth@redhat.com +Date: Mon, 7 Sep 2020 13:41:44 +0100 +Subject: [PATCH 4/5] Remove optional dep tcnative
--- - handler/pom.xml | 6 - - .../main/java/io/netty/handler/ssl/OpenSsl.java | 503 ----- - .../handler/ssl/OpenSslCertificateException.java | 79 - - .../io/netty/handler/ssl/OpenSslClientContext.java | 211 -- - .../java/io/netty/handler/ssl/OpenSslContext.java | 58 - - .../java/io/netty/handler/ssl/OpenSslEngine.java | 40 - - .../io/netty/handler/ssl/OpenSslEngineMap.java | 35 - - .../ssl/OpenSslExtendedKeyMaterialManager.java | 40 - - .../handler/ssl/OpenSslKeyMaterialManager.java | 179 -- - .../io/netty/handler/ssl/OpenSslServerContext.java | 373 ---- - .../handler/ssl/OpenSslServerSessionContext.java | 124 -- - .../netty/handler/ssl/OpenSslSessionContext.java | 137 -- - .../io/netty/handler/ssl/OpenSslSessionStats.java | 253 --- - .../netty/handler/ssl/OpenSslSessionTicketKey.java | 78 - - .../ssl/ReferenceCountedOpenSslClientContext.java | 298 --- - .../ssl/ReferenceCountedOpenSslContext.java | 867 --------- - .../handler/ssl/ReferenceCountedOpenSslEngine.java | 2037 -------------------- - .../ssl/ReferenceCountedOpenSslServerContext.java | 239 --- - .../main/java/io/netty/handler/ssl/SslContext.java | 30 +- - .../main/java/io/netty/handler/ssl/SslHandler.java | 47 +- - .../netty/handler/ssl/ocsp/OcspClientHandler.java | 65 - - .../io/netty/handler/ssl/ocsp/package-info.java | 23 - - .../handler/ssl/JdkOpenSslEngineInteroptTest.java | 108 -- - .../ssl/OpenSslCertificateExceptionTest.java | 49 - - .../handler/ssl/OpenSslClientContextTest.java | 38 - - .../io/netty/handler/ssl/OpenSslEngineTest.java | 661 ------- - .../ssl/OpenSslJdkSslEngineInteroptTest.java | 114 -- - .../ssl/OpenSslRenegotiateSmallBIOTest.java | 23 - - .../netty/handler/ssl/OpenSslRenegotiateTest.java | 36 - - .../handler/ssl/OpenSslServerContextTest.java | 39 - - .../io/netty/handler/ssl/OpenSslTestUtils.java | 27 - - .../java/io/netty/handler/ssl/PemEncodedTest.java | 95 - - .../ssl/ReferenceCountedOpenSslEngineTest.java | 57 - - .../java/io/netty/handler/ssl/SniClientTest.java | 161 -- - .../java/io/netty/handler/ssl/SniHandlerTest.java | 496 ----- - .../netty/handler/ssl/SslContextBuilderTest.java | 132 -- - .../java/io/netty/handler/ssl/SslErrorTest.java | 255 --- - .../java/io/netty/handler/ssl/SslHandlerTest.java | 58 +- - .../java/io/netty/handler/ssl/ocsp/OcspTest.java | 501 ----- - 39 files changed, 10 insertions(+), 8562 deletions(-) + handler/pom.xml | 6 - + .../handler/ssl/CipherSuiteConverter.java | 494 ---- + .../ssl/DefaultOpenSslKeyMaterial.java | 126 - + .../java/io/netty/handler/ssl/OpenSsl.java | 610 ---- + .../OpenSslCachingKeyMaterialProvider.java | 79 - + .../OpenSslCachingX509KeyManagerFactory.java | 81 - + .../ssl/OpenSslCertificateException.java | 81 - + .../handler/ssl/OpenSslClientContext.java | 208 -- + .../io/netty/handler/ssl/OpenSslContext.java | 58 - + .../io/netty/handler/ssl/OpenSslEngine.java | 41 - + .../netty/handler/ssl/OpenSslEngineMap.java | 35 - + .../ssl/OpenSslKeyMaterialManager.java | 127 - + .../ssl/OpenSslKeyMaterialProvider.java | 154 - + .../netty/handler/ssl/OpenSslPrivateKey.java | 191 -- + .../handler/ssl/OpenSslPrivateKeyMethod.java | 62 - + .../handler/ssl/OpenSslServerContext.java | 367 --- + .../ssl/OpenSslServerSessionContext.java | 124 - + .../handler/ssl/OpenSslSessionContext.java | 158 -- + .../handler/ssl/OpenSslSessionStats.java | 253 -- + .../handler/ssl/OpenSslSessionTicketKey.java | 78 - + ...OpenSslTlsv13X509ExtendedTrustManager.java | 240 -- + .../ssl/OpenSslX509KeyManagerFactory.java | 413 --- + .../ReferenceCountedOpenSslClientContext.java | 343 --- + .../ssl/ReferenceCountedOpenSslContext.java | 968 ------- + .../ssl/ReferenceCountedOpenSslEngine.java | 2467 ----------------- + .../ReferenceCountedOpenSslServerContext.java | 286 -- + .../java/io/netty/handler/ssl/SslContext.java | 30 +- + .../java/io/netty/handler/ssl/SslHandler.java | 49 +- + .../handler/ssl/SslMasterKeyHandler.java | 3 - + .../io/netty/handler/ssl/SslProvider.java | 14 +- + .../handler/ssl/ocsp/OcspClientHandler.java | 61 - + .../netty/handler/ssl/ocsp/package-info.java | 23 - + pom.xml | 10 - + 33 files changed, 3 insertions(+), 8237 deletions(-) + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSsl.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java - delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SniClientTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java - delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
diff --git a/handler/pom.xml b/handler/pom.xml -index 7535c45..d0ed1bc 100644 +index be8206dc89..e28cc6f7af 100644 --- a/handler/pom.xml +++ b/handler/pom.xml -@@ -50,12 +50,6 @@ +@@ -60,12 +60,6 @@ + <artifactId>netty-codec</artifactId> <version>${project.version}</version> </dependency> - <dependency> +- <dependency> - <groupId>${project.groupId}</groupId> - <artifactId>${tcnative.artifactId}</artifactId> - <classifier>${tcnative.classifier}</classifier> - <optional>true</optional> - </dependency> -- <dependency> + <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> - <optional>true</optional> -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java b/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java deleted file mode 100644 -index d2f091a..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java +index 94e951f7f5..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java +++ /dev/null -@@ -1,503 +0,0 @@ +@@ -1,494 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -121,499 +107,490 @@ index d2f091a..0000000 - -package io.netty.handler.ssl; - --import io.netty.buffer.ByteBuf; --import io.netty.handler.ssl.util.SelfSignedCertificate; --import io.netty.util.ReferenceCountUtil; --import io.netty.util.ReferenceCounted; --import io.netty.util.internal.NativeLibraryLoader; --import io.netty.util.internal.SystemPropertyUtil; +-import io.netty.util.internal.PlatformDependent; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; --import io.netty.internal.tcnative.Buffer; --import io.netty.internal.tcnative.Library; --import io.netty.internal.tcnative.SSL; --import io.netty.internal.tcnative.SSLContext; - --import java.security.AccessController; --import java.security.PrivilegedAction; -import java.util.Collections; --import java.util.LinkedHashSet; --import java.util.Locale; --import java.util.Set; +-import java.util.HashMap; +-import java.util.Map; +-import java.util.concurrent.ConcurrentMap; +-import java.util.regex.Matcher; +-import java.util.regex.Pattern; +- +-import static java.util.Collections.singletonMap; - -/** -- * Tells if <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support -- * are available. +- * Converts a Java cipher suite string to an OpenSSL cipher suite string and vice versa. +- * +- * @see <a href="http://en.wikipedia.org/wiki/Cipher_suite">Wikipedia page about cipher suite</a> - */ --public final class OpenSsl { +-final class CipherSuiteConverter { - -- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class); -- private static final String LINUX = "linux"; -- private static final String UNKNOWN = "unknown"; -- private static final Throwable UNAVAILABILITY_CAUSE; +- private static final InternalLogger logger = InternalLoggerFactory.getInstance(CipherSuiteConverter.class); - -- static final Set<String> AVAILABLE_CIPHER_SUITES; -- private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES; -- private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES; -- private static final boolean SUPPORTS_KEYMANAGER_FACTORY; -- private static final boolean SUPPORTS_HOSTNAME_VALIDATION; -- private static final boolean USE_KEYMANAGER_FACTORY; -- private static final boolean SUPPORTS_OCSP; +- /** +- * A_B_WITH_C_D, where: +- * +- * A - TLS or SSL (protocol) +- * B - handshake algorithm (key exchange and authentication algorithms to be precise) +- * C - bulk cipher +- * D - HMAC algorithm +- * +- * This regular expression assumes that: +- * +- * 1) A is always TLS or SSL, and +- * 2) D is always a single word. +- */ +- private static final Pattern JAVA_CIPHERSUITE_PATTERN = +- Pattern.compile("^(?:TLS|SSL)_((?:(?!_WITH_).)+)_WITH_(.*)_(.*)$"); +- +- /** +- * A-B-C, where: +- * +- * A - handshake algorithm (key exchange and authentication algorithms to be precise) +- * B - bulk cipher +- * C - HMAC algorithm +- * +- * This regular expression assumes that: +- * +- * 1) A has some deterministic pattern as shown below, and +- * 2) C is always a single word +- */ +- private static final Pattern OPENSSL_CIPHERSUITE_PATTERN = +- // Be very careful not to break the indentation while editing. +- Pattern.compile( +- "^(?:(" + // BEGIN handshake algorithm +- "(?:(?:EXP-)?" + +- "(?:" + +- "(?:DHE|EDH|ECDH|ECDHE|SRP|RSA)-(?:DSS|RSA|ECDSA|PSK)|" + +- "(?:ADH|AECDH|KRB5|PSK|SRP)" + +- ')' + +- ")|" + +- "EXP" + +- ")-)?" + // END handshake algorithm +- "(.*)-(.*)$"); +- +- private static final Pattern JAVA_AES_CBC_PATTERN = Pattern.compile("^(AES)_([0-9]+)_CBC$"); +- private static final Pattern JAVA_AES_PATTERN = Pattern.compile("^(AES)_([0-9]+)_(.*)$"); +- private static final Pattern OPENSSL_AES_CBC_PATTERN = Pattern.compile("^(AES)([0-9]+)$"); +- private static final Pattern OPENSSL_AES_PATTERN = Pattern.compile("^(AES)([0-9]+)-(.*)$"); - -- // Protocols -- static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello"; -- static final String PROTOCOL_SSL_V2 = "SSLv2"; -- static final String PROTOCOL_SSL_V3 = "SSLv3"; -- static final String PROTOCOL_TLS_V1 = "TLSv1"; -- static final String PROTOCOL_TLS_V1_1 = "TLSv1.1"; -- static final String PROTOCOL_TLS_V1_2 = "TLSv1.2"; +- /** +- * Java-to-OpenSSL cipher suite conversion map +- * Note that the Java cipher suite has the protocol prefix (TLS_, SSL_) +- */ +- private static final ConcurrentMap<String, String> j2o = PlatformDependent.newConcurrentHashMap(); - -- static final Set<String> SUPPORTED_PROTOCOLS_SET; +- /** +- * OpenSSL-to-Java cipher suite conversion map. +- * Note that one OpenSSL cipher suite can be converted to more than one Java cipher suites because +- * a Java cipher suite has the protocol name prefix (TLS_, SSL_) +- */ +- private static final ConcurrentMap<String, Map<String, String>> o2j = PlatformDependent.newConcurrentHashMap(); +- +- private static final Map<String, String> j2oTls13; +- private static final Map<String, Map<String, String>> o2jTls13; - - static { -- Throwable cause = null; +- Map<String, String> j2oTls13Map = new HashMap<String, String>(); +- j2oTls13Map.put("TLS_AES_128_GCM_SHA256", "AEAD-AES128-GCM-SHA256"); +- j2oTls13Map.put("TLS_AES_256_GCM_SHA384", "AEAD-AES256-GCM-SHA384"); +- j2oTls13Map.put("TLS_CHACHA20_POLY1305_SHA256", "AEAD-CHACHA20-POLY1305-SHA256"); +- j2oTls13 = Collections.unmodifiableMap(j2oTls13Map); +- +- Map<String, Map<String, String>> o2jTls13Map = new HashMap<String, Map<String, String>>(); +- o2jTls13Map.put("TLS_AES_128_GCM_SHA256", singletonMap("TLS", "TLS_AES_128_GCM_SHA256")); +- o2jTls13Map.put("TLS_AES_256_GCM_SHA384", singletonMap("TLS", "TLS_AES_256_GCM_SHA384")); +- o2jTls13Map.put("TLS_CHACHA20_POLY1305_SHA256", singletonMap("TLS", "TLS_CHACHA20_POLY1305_SHA256")); +- o2jTls13Map.put("AEAD-AES128-GCM-SHA256", singletonMap("TLS", "TLS_AES_128_GCM_SHA256")); +- o2jTls13Map.put("AEAD-AES256-GCM-SHA384", singletonMap("TLS", "TLS_AES_256_GCM_SHA384")); +- o2jTls13Map.put("AEAD-CHACHA20-POLY1305-SHA256", singletonMap("TLS", "TLS_CHACHA20_POLY1305_SHA256")); +- o2jTls13 = Collections.unmodifiableMap(o2jTls13Map); +- } - -- // Test if netty-tcnative is in the classpath first. -- try { -- Class.forName("io.netty.internal.tcnative.SSL", false, OpenSsl.class.getClassLoader()); -- } catch (ClassNotFoundException t) { -- cause = t; -- logger.debug( -- "netty-tcnative not in the classpath; " + -- OpenSslEngine.class.getSimpleName() + " will be unavailable."); +- /** +- * Clears the cache for testing purpose. +- */ +- static void clearCache() { +- j2o.clear(); +- o2j.clear(); +- } +- +- /** +- * Tests if the specified key-value pair has been cached in Java-to-OpenSSL cache. +- */ +- static boolean isJ2OCached(String key, String value) { +- return value.equals(j2o.get(key)); +- } +- +- /** +- * Tests if the specified key-value pair has been cached in OpenSSL-to-Java cache. +- */ +- static boolean isO2JCached(String key, String protocol, String value) { +- Map<String, String> p2j = o2j.get(key); +- if (p2j == null) { +- return false; +- } else { +- return value.equals(p2j.get(protocol)); - } +- } - -- // If in the classpath, try to load the native library and initialize netty-tcnative. -- if (cause == null) { -- try { -- // The JNI library was not already loaded. Load it now. -- loadTcNative(); -- } catch (Throwable t) { -- cause = t; -- logger.debug( -- "Failed to load netty-tcnative; " + -- OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " + -- "application has already loaded the symbols by some other means. " + -- "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t); -- } +- /** +- * Converts the specified Java cipher suite to its corresponding OpenSSL cipher suite name. +- * +- * @return {@code null} if the conversion has failed +- */ +- static String toOpenSsl(String javaCipherSuite, boolean boringSSL) { +- String converted = j2o.get(javaCipherSuite); +- if (converted != null) { +- return converted; +- } +- return cacheFromJava(javaCipherSuite, boringSSL); +- } - -- try { -- initializeTcNative(); -- -- // The library was initialized successfully. If loading the library failed above, -- // reset the cause now since it appears that the library was loaded by some other -- // means. -- cause = null; -- } catch (Throwable t) { -- if (cause == null) { -- cause = t; -- } -- logger.debug( -- "Failed to initialize netty-tcnative; " + -- OpenSslEngine.class.getSimpleName() + " will be unavailable. " + -- "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t); -- } +- private static String cacheFromJava(String javaCipherSuite, boolean boringSSL) { +- String converted = j2oTls13.get(javaCipherSuite); +- if (converted != null) { +- return boringSSL ? converted : javaCipherSuite; - } - -- UNAVAILABILITY_CAUSE = cause; +- String openSslCipherSuite = toOpenSslUncached(javaCipherSuite, boringSSL); +- if (openSslCipherSuite == null) { +- return null; +- } - -- if (cause == null) { -- logger.debug("netty-tcnative using native library: {}", SSL.versionString()); +- // Cache the mapping. +- j2o.putIfAbsent(javaCipherSuite, openSslCipherSuite); - -- final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<String>(128); -- boolean supportsKeyManagerFactory = false; -- boolean useKeyManagerFactory = false; -- boolean supportsHostNameValidation = false; -- try { -- final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER); -- long certBio = 0; -- SelfSignedCertificate cert = null; -- try { -- SSLContext.setCipherSuite(sslCtx, "ALL"); -- final long ssl = SSL.newSSL(sslCtx, true); -- try { -- for (String c: SSL.getCiphers(ssl)) { -- // Filter out bad input. -- if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c)) { -- continue; -- } -- availableOpenSslCipherSuites.add(c); -- } -- try { -- SSL.setHostNameValidation(ssl, 0, "netty.io"); -- supportsHostNameValidation = true; -- } catch (Throwable ignore) { -- logger.debug("Hostname Verification not supported."); -- } -- try { -- cert = new SelfSignedCertificate(); -- certBio = ReferenceCountedOpenSslContext.toBIO(cert.cert()); -- SSL.setCertificateChainBio(ssl, certBio, false); -- supportsKeyManagerFactory = true; -- try { -- useKeyManagerFactory = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { -- @Override -- public Boolean run() { -- return SystemPropertyUtil.getBoolean( -- "io.netty.handler.ssl.openssl.useKeyManagerFactory", true); -- } -- }); -- } catch (Throwable ignore) { -- logger.debug("Failed to get useKeyManagerFactory system property."); -- } -- } catch (Throwable ignore) { -- logger.debug("KeyManagerFactory not supported."); -- } -- } finally { -- SSL.freeSSL(ssl); -- if (certBio != 0) { -- SSL.freeBIO(certBio); -- } -- if (cert != null) { -- cert.delete(); -- } -- } -- } finally { -- SSLContext.free(sslCtx); -- } -- } catch (Exception e) { -- logger.warn("Failed to get the list of available OpenSSL cipher suites.", e); -- } -- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites); +- // Cache the reverse mapping after stripping the protocol prefix (TLS_ or SSL_) +- final String javaCipherSuiteSuffix = javaCipherSuite.substring(4); +- Map<String, String> p2j = new HashMap<String, String>(4); +- p2j.put("", javaCipherSuiteSuffix); +- p2j.put("SSL", "SSL_" + javaCipherSuiteSuffix); +- p2j.put("TLS", "TLS_" + javaCipherSuiteSuffix); +- o2j.put(openSslCipherSuite, p2j); - -- final Set<String> availableJavaCipherSuites = new LinkedHashSet<String>( -- AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2); -- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) { -- // Included converted but also openssl cipher name -- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS")); -- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL")); -- } -- AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites); +- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuite, openSslCipherSuite); - -- final Set<String> availableCipherSuites = new LinkedHashSet<String>( -- AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size()); -- availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES); -- availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES); +- return openSslCipherSuite; +- } - -- AVAILABLE_CIPHER_SUITES = availableCipherSuites; -- SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory; -- SUPPORTS_HOSTNAME_VALIDATION = supportsHostNameValidation; -- USE_KEYMANAGER_FACTORY = useKeyManagerFactory; +- static String toOpenSslUncached(String javaCipherSuite, boolean boringSSL) { +- String converted = j2oTls13.get(javaCipherSuite); +- if (converted != null) { +- return boringSSL ? converted : javaCipherSuite; +- } - -- Set<String> protocols = new LinkedHashSet<String>(6); -- // Seems like there is no way to explicitly disable SSLv2Hello in openssl so it is always enabled -- protocols.add(PROTOCOL_SSL_V2_HELLO); -- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2)) { -- protocols.add(PROTOCOL_SSL_V2); -- } -- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3)) { -- protocols.add(PROTOCOL_SSL_V3); -- } -- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1)) { -- protocols.add(PROTOCOL_TLS_V1); -- } -- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1)) { -- protocols.add(PROTOCOL_TLS_V1_1); -- } -- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2)) { -- protocols.add(PROTOCOL_TLS_V1_2); -- } +- Matcher m = JAVA_CIPHERSUITE_PATTERN.matcher(javaCipherSuite); +- if (!m.matches()) { +- return null; +- } - -- SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols); -- SUPPORTS_OCSP = doesSupportOcsp(); +- String handshakeAlgo = toOpenSslHandshakeAlgo(m.group(1)); +- String bulkCipher = toOpenSslBulkCipher(m.group(2)); +- String hmacAlgo = toOpenSslHmacAlgo(m.group(3)); +- if (handshakeAlgo.isEmpty()) { +- return bulkCipher + '-' + hmacAlgo; +- } else if (bulkCipher.contains("CHACHA20")) { +- return handshakeAlgo + '-' + bulkCipher; - } else { -- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet(); -- AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet(); -- AVAILABLE_CIPHER_SUITES = Collections.emptySet(); -- SUPPORTS_KEYMANAGER_FACTORY = false; -- SUPPORTS_HOSTNAME_VALIDATION = false; -- USE_KEYMANAGER_FACTORY = false; -- SUPPORTED_PROTOCOLS_SET = Collections.emptySet(); -- SUPPORTS_OCSP = false; +- return handshakeAlgo + '-' + bulkCipher + '-' + hmacAlgo; - } - } - -- private static boolean doesSupportOcsp() { -- boolean supportsOcsp = false; -- if (version() >= 0x10002000L) { -- long sslCtx = -1; -- try { -- sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_MODE_SERVER); -- SSLContext.enableOcsp(sslCtx, false); -- supportsOcsp = true; -- } catch (Exception ignore) { -- // ignore -- } finally { -- if (sslCtx != -1) { -- SSLContext.free(sslCtx); -- } +- private static String toOpenSslHandshakeAlgo(String handshakeAlgo) { +- final boolean export = handshakeAlgo.endsWith("_EXPORT"); +- if (export) { +- handshakeAlgo = handshakeAlgo.substring(0, handshakeAlgo.length() - 7); +- } +- +- if ("RSA".equals(handshakeAlgo)) { +- handshakeAlgo = ""; +- } else if (handshakeAlgo.endsWith("_anon")) { +- handshakeAlgo = 'A' + handshakeAlgo.substring(0, handshakeAlgo.length() - 5); +- } +- +- if (export) { +- if (handshakeAlgo.isEmpty()) { +- handshakeAlgo = "EXP"; +- } else { +- handshakeAlgo = "EXP-" + handshakeAlgo; - } - } -- return supportsOcsp; +- +- return handshakeAlgo.replace('_', '-'); - } -- private static boolean doesSupportProtocol(int protocol) { -- long sslCtx = -1; -- try { -- sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED); -- return true; -- } catch (Exception ignore) { -- return false; -- } finally { -- if (sslCtx != -1) { -- SSLContext.free(sslCtx); +- +- private static String toOpenSslBulkCipher(String bulkCipher) { +- if (bulkCipher.startsWith("AES_")) { +- Matcher m = JAVA_AES_CBC_PATTERN.matcher(bulkCipher); +- if (m.matches()) { +- return m.replaceFirst("$1$2"); +- } +- +- m = JAVA_AES_PATTERN.matcher(bulkCipher); +- if (m.matches()) { +- return m.replaceFirst("$1$2-$3"); - } - } -- } - -- /** -- * Returns {@code true} if and only if -- * <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support -- * are available. -- */ -- public static boolean isAvailable() { -- return UNAVAILABILITY_CAUSE == null; -- } +- if ("3DES_EDE_CBC".equals(bulkCipher)) { +- return "DES-CBC3"; +- } - -- /** -- * Returns {@code true} if the used version of openssl supports -- * <a href="https://tools.ietf.org/html/rfc7301">ALPN</a>. -- */ -- public static boolean isAlpnSupported() { -- return version() >= 0x10002000L; -- } +- if ("RC4_128".equals(bulkCipher) || "RC4_40".equals(bulkCipher)) { +- return "RC4"; +- } - -- /** -- * Returns {@code true} if the used version of OpenSSL supports OCSP stapling. -- */ -- public static boolean isOcspSupported() { -- return SUPPORTS_OCSP; -- } +- if ("DES40_CBC".equals(bulkCipher) || "DES_CBC_40".equals(bulkCipher)) { +- return "DES-CBC"; +- } - -- /** -- * Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()} -- * returns {@code false}. -- */ -- public static int version() { -- return isAvailable() ? SSL.version() : -1; +- if ("RC2_CBC_40".equals(bulkCipher)) { +- return "RC2-CBC"; +- } +- +- return bulkCipher.replace('_', '-'); - } - -- /** -- * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()} -- * returns {@code false}. -- */ -- public static String versionString() { -- return isAvailable() ? SSL.versionString() : null; +- private static String toOpenSslHmacAlgo(String hmacAlgo) { +- // Java and OpenSSL use the same algorithm names for: +- // +- // * SHA +- // * SHA256 +- // * MD5 +- // +- return hmacAlgo; - } - - /** -- * Ensure that <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and -- * its OpenSSL support are available. -- * -- * @throws UnsatisfiedLinkError if unavailable +- * Convert from OpenSSL cipher suite name convention to java cipher suite name convention. +- * @param openSslCipherSuite An OpenSSL cipher suite name. +- * @param protocol The cryptographic protocol (i.e. SSL, TLS, ...). +- * @return The translated cipher suite name according to java conventions. This will not be {@code null}. - */ -- public static void ensureAvailability() { -- if (UNAVAILABILITY_CAUSE != null) { -- throw (Error) new UnsatisfiedLinkError( -- "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE); +- static String toJava(String openSslCipherSuite, String protocol) { +- Map<String, String> p2j = o2j.get(openSslCipherSuite); +- if (p2j == null) { +- p2j = cacheFromOpenSsl(openSslCipherSuite); +- // This may happen if this method is queried when OpenSSL doesn't yet have a cipher setup. It will return +- // "(NONE)" in this case. +- if (p2j == null) { +- return null; +- } +- } +- +- String javaCipherSuite = p2j.get(protocol); +- if (javaCipherSuite == null) { +- String cipher = p2j.get(""); +- if (cipher == null) { +- return null; +- } +- javaCipherSuite = protocol + '_' + cipher; - } +- +- return javaCipherSuite; - } - -- /** -- * Returns the cause of unavailability of -- * <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support. -- * -- * @return the cause if unavailable. {@code null} if available. -- */ -- public static Throwable unavailabilityCause() { -- return UNAVAILABILITY_CAUSE; -- } -- -- /** -- * @deprecated use {@link #availableOpenSslCipherSuites()} -- */ -- @Deprecated -- public static Set<String> availableCipherSuites() { -- return availableOpenSslCipherSuites(); -- } +- private static Map<String, String> cacheFromOpenSsl(String openSslCipherSuite) { +- Map<String, String> converted = o2jTls13.get(openSslCipherSuite); +- if (converted != null) { +- return converted; +- } - -- /** -- * Returns all the available OpenSSL cipher suites. -- * Please note that the returned array may include the cipher suites that are insecure or non-functional. -- */ -- public static Set<String> availableOpenSslCipherSuites() { -- return AVAILABLE_OPENSSL_CIPHER_SUITES; -- } +- String javaCipherSuiteSuffix = toJavaUncached0(openSslCipherSuite, false); +- if (javaCipherSuiteSuffix == null) { +- return null; +- } - -- /** -- * Returns all the available cipher suites (Java-style). -- * Please note that the returned array may include the cipher suites that are insecure or non-functional. -- */ -- public static Set<String> availableJavaCipherSuites() { -- return AVAILABLE_JAVA_CIPHER_SUITES; -- } +- final String javaCipherSuiteSsl = "SSL_" + javaCipherSuiteSuffix; +- final String javaCipherSuiteTls = "TLS_" + javaCipherSuiteSuffix; - -- /** -- * Returns {@code true} if and only if the specified cipher suite is available in OpenSSL. -- * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted. -- */ -- public static boolean isCipherSuiteAvailable(String cipherSuite) { -- String converted = CipherSuiteConverter.toOpenSsl(cipherSuite); -- if (converted != null) { -- cipherSuite = converted; -- } -- return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite); -- } +- // Cache the mapping. +- final Map<String, String> p2j = new HashMap<String, String>(4); +- p2j.put("", javaCipherSuiteSuffix); +- p2j.put("SSL", javaCipherSuiteSsl); +- p2j.put("TLS", javaCipherSuiteTls); +- o2j.putIfAbsent(openSslCipherSuite, p2j); - -- /** -- * Returns {@code true} if {@link javax.net.ssl.KeyManagerFactory} is supported when using OpenSSL. -- */ -- public static boolean supportsKeyManagerFactory() { -- return SUPPORTS_KEYMANAGER_FACTORY; -- } +- // Cache the reverse mapping after adding the protocol prefix (TLS_ or SSL_) +- j2o.putIfAbsent(javaCipherSuiteTls, openSslCipherSuite); +- j2o.putIfAbsent(javaCipherSuiteSsl, openSslCipherSuite); - -- /** -- * Returns {@code true} if <a href="https://wiki.openssl.org/index.php/Hostname_validation">Hostname Validation</a> -- * is supported when using OpenSSL. -- */ -- public static boolean supportsHostnameValidation() { -- return SUPPORTS_HOSTNAME_VALIDATION; -- } +- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteTls, openSslCipherSuite); +- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteSsl, openSslCipherSuite); - -- static boolean useKeyManagerFactory() { -- return USE_KEYMANAGER_FACTORY; +- return p2j; - } - -- static long memoryAddress(ByteBuf buf) { -- assert buf.isDirect(); -- return buf.hasMemoryAddress() ? buf.memoryAddress() : Buffer.address(buf.nioBuffer()); +- static String toJavaUncached(String openSslCipherSuite) { +- return toJavaUncached0(openSslCipherSuite, true); - } - -- private OpenSsl() { } +- private static String toJavaUncached0(String openSslCipherSuite, boolean checkTls13) { +- if (checkTls13) { +- Map<String, String> converted = o2jTls13.get(openSslCipherSuite); +- if (converted != null) { +- return converted.get("TLS"); +- } +- } - -- private static void loadTcNative() throws Exception { -- String os = normalizeOs(SystemPropertyUtil.get("os.name", "")); -- String arch = normalizeArch(SystemPropertyUtil.get("os.arch", "")); +- Matcher m = OPENSSL_CIPHERSUITE_PATTERN.matcher(openSslCipherSuite); +- if (!m.matches()) { +- return null; +- } - -- Set<String> libNames = new LinkedHashSet<String>(4); -- // First, try loading the platform-specific library. Platform-specific -- // libraries will be available if using a tcnative uber jar. -- libNames.add("netty-tcnative-" + os + '-' + arch); -- if (LINUX.equalsIgnoreCase(os)) { -- // Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0).. -- libNames.add("netty-tcnative-" + os + '-' + arch + "-fedora"); +- String handshakeAlgo = m.group(1); +- final boolean export; +- if (handshakeAlgo == null) { +- handshakeAlgo = ""; +- export = false; +- } else if (handshakeAlgo.startsWith("EXP-")) { +- handshakeAlgo = handshakeAlgo.substring(4); +- export = true; +- } else if ("EXP".equals(handshakeAlgo)) { +- handshakeAlgo = ""; +- export = true; +- } else { +- export = false; - } -- // finally the default library. -- libNames.add("netty-tcnative"); -- // in Java 8, statically compiled JNI code is namespaced -- libNames.add("netty_tcnative"); - -- NativeLibraryLoader.loadFirstAvailable(SSL.class.getClassLoader(), -- libNames.toArray(new String[libNames.size()])); -- } +- handshakeAlgo = toJavaHandshakeAlgo(handshakeAlgo, export); +- String bulkCipher = toJavaBulkCipher(m.group(2), export); +- String hmacAlgo = toJavaHmacAlgo(m.group(3)); - -- private static boolean initializeTcNative() throws Exception { -- return Library.initialize(); +- String javaCipherSuite = handshakeAlgo + "_WITH_" + bulkCipher + '_' + hmacAlgo; +- // For historical reasons the CHACHA20 ciphers do not follow OpenSSL's custom naming convention and omits the +- // HMAC algorithm portion of the name. There is currently no way to derive this information because it is +- // omitted from the OpenSSL cipher name, but they currently all use SHA256 for HMAC [1]. +- // [1] https://www.openssl.org/docs/man1.1.0/apps/ciphers.html +- return bulkCipher.contains("CHACHA20") ? javaCipherSuite + "_SHA256" : javaCipherSuite; - } - -- private static String normalizeOs(String value) { -- value = normalize(value); -- if (value.startsWith("aix")) { -- return "aix"; +- private static String toJavaHandshakeAlgo(String handshakeAlgo, boolean export) { +- if (handshakeAlgo.isEmpty()) { +- handshakeAlgo = "RSA"; +- } else if ("ADH".equals(handshakeAlgo)) { +- handshakeAlgo = "DH_anon"; +- } else if ("AECDH".equals(handshakeAlgo)) { +- handshakeAlgo = "ECDH_anon"; - } -- if (value.startsWith("hpux")) { -- return "hpux"; +- +- handshakeAlgo = handshakeAlgo.replace('-', '_'); +- if (export) { +- return handshakeAlgo + "_EXPORT"; +- } else { +- return handshakeAlgo; - } -- if (value.startsWith("os400")) { -- // Avoid the names such as os4000 -- if (value.length() <= 5 || !Character.isDigit(value.charAt(5))) { -- return "os400"; +- } +- +- private static String toJavaBulkCipher(String bulkCipher, boolean export) { +- if (bulkCipher.startsWith("AES")) { +- Matcher m = OPENSSL_AES_CBC_PATTERN.matcher(bulkCipher); +- if (m.matches()) { +- return m.replaceFirst("$1_$2_CBC"); +- } +- +- m = OPENSSL_AES_PATTERN.matcher(bulkCipher); +- if (m.matches()) { +- return m.replaceFirst("$1_$2_$3"); - } - } -- if (value.startsWith(LINUX)) { -- return LINUX; -- } -- if (value.startsWith("macosx") || value.startsWith("osx")) { -- return "osx"; -- } -- if (value.startsWith("freebsd")) { -- return "freebsd"; -- } -- if (value.startsWith("openbsd")) { -- return "openbsd"; +- +- if ("DES-CBC3".equals(bulkCipher)) { +- return "3DES_EDE_CBC"; - } -- if (value.startsWith("netbsd")) { -- return "netbsd"; +- +- if ("RC4".equals(bulkCipher)) { +- if (export) { +- return "RC4_40"; +- } else { +- return "RC4_128"; +- } - } -- if (value.startsWith("solaris") || value.startsWith("sunos")) { -- return "sunos"; +- +- if ("DES-CBC".equals(bulkCipher)) { +- if (export) { +- return "DES_CBC_40"; +- } else { +- return "DES_CBC"; +- } - } -- if (value.startsWith("windows")) { -- return "windows"; +- +- if ("RC2-CBC".equals(bulkCipher)) { +- if (export) { +- return "RC2_CBC_40"; +- } else { +- return "RC2_CBC"; +- } - } - -- return UNKNOWN; +- return bulkCipher.replace('-', '_'); - } - -- private static String normalizeArch(String value) { -- value = normalize(value); -- if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) { -- return "x86_64"; -- } -- if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) { -- return "x86_32"; -- } -- if (value.matches("^(ia64|itanium64)$")) { -- return "itanium_64"; -- } -- if (value.matches("^(sparc|sparc32)$")) { -- return "sparc_32"; -- } -- if (value.matches("^(sparcv9|sparc64)$")) { -- return "sparc_64"; -- } -- if (value.matches("^(arm|arm32)$")) { -- return "arm_32"; -- } -- if ("aarch64".equals(value)) { -- return "aarch_64"; -- } -- if (value.matches("^(ppc|ppc32)$")) { -- return "ppc_32"; -- } -- if ("ppc64".equals(value)) { -- return "ppc_64"; +- private static String toJavaHmacAlgo(String hmacAlgo) { +- // Java and OpenSSL use the same algorithm names for: +- // +- // * SHA +- // * SHA256 +- // * MD5 +- // +- return hmacAlgo; +- } +- +- /** +- * Convert the given ciphers if needed to OpenSSL format and append them to the correct {@link StringBuilder} +- * depending on if its a TLSv1.3 cipher or not. If this methods returns without throwing an exception its +- * guaranteed that at least one of the {@link StringBuilder}s contain some ciphers that can be used to configure +- * OpenSSL. +- */ +- static void convertToCipherStrings(Iterable<String> cipherSuites, StringBuilder cipherBuilder, +- StringBuilder cipherTLSv13Builder, boolean boringSSL) { +- for (String c: cipherSuites) { +- if (c == null) { +- break; +- } +- +- String converted = toOpenSsl(c, boringSSL); +- if (converted == null) { +- converted = c; +- } +- +- if (!OpenSsl.isCipherSuiteAvailable(converted)) { +- throw new IllegalArgumentException("unsupported cipher suite: " + c + '(' + converted + ')'); +- } +- +- if (SslUtils.isTLSv13Cipher(converted) || SslUtils.isTLSv13Cipher(c)) { +- cipherTLSv13Builder.append(converted); +- cipherTLSv13Builder.append(':'); +- } else { +- cipherBuilder.append(converted); +- cipherBuilder.append(':'); +- } - } -- if ("ppc64le".equals(value)) { -- return "ppcle_64"; +- +- if (cipherBuilder.length() == 0 && cipherTLSv13Builder.length() == 0) { +- throw new IllegalArgumentException("empty cipher suites"); - } -- if ("s390".equals(value)) { -- return "s390_32"; +- if (cipherBuilder.length() > 0) { +- cipherBuilder.setLength(cipherBuilder.length() - 1); - } -- if ("s390x".equals(value)) { -- return "s390_64"; +- if (cipherTLSv13Builder.length() > 0) { +- cipherTLSv13Builder.setLength(cipherTLSv13Builder.length() - 1); - } -- -- return UNKNOWN; - } - -- private static String normalize(String value) { -- return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", ""); -- } -- -- static void releaseIfNeeded(ReferenceCounted counted) { -- if (counted.refCnt() > 0) { -- ReferenceCountUtil.safeRelease(counted); -- } -- } +- private CipherSuiteConverter() { } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java b/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java deleted file mode 100644 -index 4672d00..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java +index fcea5266f2..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java +++ /dev/null -@@ -1,79 +0,0 @@ +@@ -1,126 +0,0 @@ -/* -- * Copyright 2016 The Netty Project +- * Copyright 2018 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 @@ -629,74 +606,121 @@ index 4672d00..0000000 - */ -package io.netty.handler.ssl; - --import io.netty.internal.tcnative.CertificateVerifier; +-import io.netty.internal.tcnative.SSL; +-import io.netty.util.AbstractReferenceCounted; +-import io.netty.util.IllegalReferenceCountException; +-import io.netty.util.ResourceLeakDetector; +-import io.netty.util.ResourceLeakDetectorFactory; +-import io.netty.util.ResourceLeakTracker; - --import java.security.cert.CertificateException; +-import java.security.cert.X509Certificate; - --/** -- * A special {@link CertificateException} which allows to specify which error code is included in the -- * SSL Record. This only work when {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT} is used. -- */ --public final class OpenSslCertificateException extends CertificateException { -- private static final long serialVersionUID = 5542675253797129798L; +-final class DefaultOpenSslKeyMaterial extends AbstractReferenceCounted implements OpenSslKeyMaterial { - -- private final int errorCode; +- private static final ResourceLeakDetector<DefaultOpenSslKeyMaterial> leakDetector = +- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(DefaultOpenSslKeyMaterial.class); +- private final ResourceLeakTracker<DefaultOpenSslKeyMaterial> leak; +- private final X509Certificate[] x509CertificateChain; +- private long chain; +- private long privateKey; - -- /** -- * Construct a new exception with the -- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a>. -- */ -- public OpenSslCertificateException(int errorCode) { -- this((String) null, errorCode); +- DefaultOpenSslKeyMaterial(long chain, long privateKey, X509Certificate[] x509CertificateChain) { +- this.chain = chain; +- this.privateKey = privateKey; +- this.x509CertificateChain = x509CertificateChain; +- leak = leakDetector.track(this); - } - -- /** -- * Construct a new exception with the msg and -- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> . -- */ -- public OpenSslCertificateException(String msg, int errorCode) { -- super(msg); -- this.errorCode = checkErrorCode(errorCode); +- @Override +- public X509Certificate[] certificateChain() { +- return x509CertificateChain.clone(); - } - -- /** -- * Construct a new exception with the msg, cause and -- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> . -- */ -- public OpenSslCertificateException(String message, Throwable cause, int errorCode) { -- super(message, cause); -- this.errorCode = checkErrorCode(errorCode); +- @Override +- public long certificateChainAddress() { +- if (refCnt() <= 0) { +- throw new IllegalReferenceCountException(); +- } +- return chain; - } - -- /** -- * Construct a new exception with the cause and -- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> . -- */ -- public OpenSslCertificateException(Throwable cause, int errorCode) { -- this(null, cause, errorCode); +- @Override +- public long privateKeyAddress() { +- if (refCnt() <= 0) { +- throw new IllegalReferenceCountException(); +- } +- return privateKey; - } - -- /** -- * Return the <a href="https://www.openssl.org/docs/man1.0.2/apps/verify.html">error code</a> to use. -- */ -- public int errorCode() { -- return errorCode; +- @Override +- protected void deallocate() { +- SSL.freeX509Chain(chain); +- chain = 0; +- SSL.freePrivateKey(privateKey); +- privateKey = 0; +- if (leak != null) { +- boolean closed = leak.close(this); +- assert closed; +- } - } - -- private static int checkErrorCode(int errorCode) { -- if (!CertificateVerifier.isValid(errorCode)) { -- throw new IllegalArgumentException("errorCode '" + errorCode + -- "' invalid, see https://www.openssl.org/docs/man1.0.2/apps/verify.html."); +- @Override +- public DefaultOpenSslKeyMaterial retain() { +- if (leak != null) { +- leak.record(); - } -- return errorCode; +- super.retain(); +- return this; +- } +- +- @Override +- public DefaultOpenSslKeyMaterial retain(int increment) { +- if (leak != null) { +- leak.record(); +- } +- super.retain(increment); +- return this; +- } +- +- @Override +- public DefaultOpenSslKeyMaterial touch() { +- if (leak != null) { +- leak.record(); +- } +- super.touch(); +- return this; +- } +- +- @Override +- public DefaultOpenSslKeyMaterial touch(Object hint) { +- if (leak != null) { +- leak.record(hint); +- } +- return this; +- } +- +- @Override +- public boolean release() { +- if (leak != null) { +- leak.record(); +- } +- return super.release(); +- } +- +- @Override +- public boolean release(int decrement) { +- if (leak != null) { +- leak.record(); +- } +- return super.release(decrement); - } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java deleted file mode 100644 -index 46412e9..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java +index d7d44cf3e7..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java +++ /dev/null -@@ -1,211 +0,0 @@ +@@ -1,610 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -712,210 +736,609 @@ index 46412e9..0000000 - * License for the specific language governing permissions and limitations - * under the License. - */ +- -package io.netty.handler.ssl; - +-import io.netty.buffer.ByteBuf; +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.buffer.UnpooledByteBufAllocator; +-import io.netty.internal.tcnative.Buffer; +-import io.netty.internal.tcnative.Library; -import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +-import io.netty.util.CharsetUtil; +-import io.netty.util.ReferenceCountUtil; +-import io.netty.util.ReferenceCounted; +-import io.netty.util.internal.EmptyArrays; +-import io.netty.util.internal.NativeLibraryLoader; +-import io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.SystemPropertyUtil; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; - --import java.io.File; --import java.security.PrivateKey; +-import java.io.ByteArrayInputStream; +-import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; +-import java.util.ArrayList; +-import java.util.Collections; +-import java.util.LinkedHashSet; +-import java.util.List; +-import java.util.Set; - --import javax.net.ssl.KeyManagerFactory; --import javax.net.ssl.SSLException; --import javax.net.ssl.TrustManager; --import javax.net.ssl.TrustManagerFactory; -- --import static io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext; +-import static io.netty.handler.ssl.SslUtils.*; - -/** -- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. -- * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers -- * and manually release the native memory see {@link ReferenceCountedOpenSslClientContext}. +- * Tells if <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support +- * are available. - */ --public final class OpenSslClientContext extends OpenSslContext { -- private final OpenSslSessionContext sessionContext; +-public final class OpenSsl { - -- /** -- * Creates a new instance. -- * @deprecated use {@link SslContextBuilder} -- */ -- @Deprecated -- public OpenSslClientContext() throws SSLException { -- this((File) null, null, null, null, null, null, null, IdentityCipherSuiteFilter.INSTANCE, null, 0, 0); +- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class); +- private static final Throwable UNAVAILABILITY_CAUSE; +- +- static final List<String> DEFAULT_CIPHERS; +- static final Set<String> AVAILABLE_CIPHER_SUITES; +- private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES; +- private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES; +- private static final boolean SUPPORTS_KEYMANAGER_FACTORY; +- private static final boolean USE_KEYMANAGER_FACTORY; +- private static final boolean SUPPORTS_OCSP; +- private static final boolean TLSV13_SUPPORTED; +- private static final boolean IS_BORINGSSL; +- static final Set<String> SUPPORTED_PROTOCOLS_SET; +- static final String[] EXTRA_SUPPORTED_TLS_1_3_CIPHERS; +- +- // self-signed certificate for netty.io and the matching private-key +- private static final String CERT = "-----BEGIN CERTIFICATE-----\n" + +- "MIICrjCCAZagAwIBAgIIdSvQPv1QAZQwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAxMLZXhhbXBs\n" + +- "ZS5jb20wIBcNMTgwNDA2MjIwNjU5WhgPOTk5OTEyMzEyMzU5NTlaMBYxFDASBgNVBAMTC2V4YW1w\n" + +- "bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAggbWsmDQ6zNzRZ5AW8E3eoGl\n" + +- "qWvOBDb5Fs1oBRrVQHuYmVAoaqwDzXYJ0LOwa293AgWEQ1jpcbZ2hpoYQzqEZBTLnFhMrhRFlH6K\n" + +- "bJND8Y33kZ/iSVBBDuGbdSbJShlM+4WwQ9IAso4MZ4vW3S1iv5fGGpLgbtXRmBf/RU8omN0Gijlv\n" + +- "WlLWHWijLN8xQtySFuBQ7ssW8RcKAary3pUm6UUQB+Co6lnfti0Tzag8PgjhAJq2Z3wbsGRnP2YS\n" + +- "vYoaK6qzmHXRYlp/PxrjBAZAmkLJs4YTm/XFF+fkeYx4i9zqHbyone5yerRibsHaXZWLnUL+rFoe\n" + +- "MdKvr0VS3sGmhQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQADQi441pKmXf9FvUV5EHU4v8nJT9Iq\n" + +- "yqwsKwXnr7AsUlDGHBD7jGrjAXnG5rGxuNKBQ35wRxJATKrUtyaquFUL6H8O6aGQehiFTk6zmPbe\n" + +- "12Gu44vqqTgIUxnv3JQJiox8S2hMxsSddpeCmSdvmalvD6WG4NthH6B9ZaBEiep1+0s0RUaBYn73\n" + +- "I7CCUaAtbjfR6pcJjrFk5ei7uwdQZFSJtkP2z8r7zfeANJddAKFlkaMWn7u+OIVuB4XPooWicObk\n" + +- "NAHFtP65bocUYnDpTVdiyvn8DdqyZ/EO8n1bBKBzuSLplk2msW4pdgaFgY7Vw/0wzcFXfUXmL1uy\n" + +- "G8sQD/wx\n" + +- "-----END CERTIFICATE-----"; +- +- private static final String KEY = "-----BEGIN PRIVATE KEY-----\n" + +- "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCCBtayYNDrM3NFnkBbwTd6gaWp\n" + +- "a84ENvkWzWgFGtVAe5iZUChqrAPNdgnQs7Brb3cCBYRDWOlxtnaGmhhDOoRkFMucWEyuFEWUfops\n" + +- "k0PxjfeRn+JJUEEO4Zt1JslKGUz7hbBD0gCyjgxni9bdLWK/l8YakuBu1dGYF/9FTyiY3QaKOW9a\n" + +- "UtYdaKMs3zFC3JIW4FDuyxbxFwoBqvLelSbpRRAH4KjqWd+2LRPNqDw+COEAmrZnfBuwZGc/ZhK9\n" + +- "ihorqrOYddFiWn8/GuMEBkCaQsmzhhOb9cUX5+R5jHiL3OodvKid7nJ6tGJuwdpdlYudQv6sWh4x\n" + +- "0q+vRVLewaaFAgMBAAECggEAP8tPJvFtTxhNJAkCloHz0D0vpDHqQBMgntlkgayqmBqLwhyb18pR\n" + +- "i0qwgh7HHc7wWqOOQuSqlEnrWRrdcI6TSe8R/sErzfTQNoznKWIPYcI/hskk4sdnQ//Yn9/Jvnsv\n" + +- "U/BBjOTJxtD+sQbhAl80JcA3R+5sArURQkfzzHOL/YMqzAsn5hTzp7HZCxUqBk3KaHRxV7NefeOE\n" + +- "xlZuWSmxYWfbFIs4kx19/1t7h8CHQWezw+G60G2VBtSBBxDnhBWvqG6R/wpzJ3nEhPLLY9T+XIHe\n" + +- "ipzdMOOOUZorfIg7M+pyYPji+ZIZxIpY5OjrOzXHciAjRtr5Y7l99K1CG1LguQKBgQDrQfIMxxtZ\n" + +- "vxU/1cRmUV9l7pt5bjV5R6byXq178LxPKVYNjdZ840Q0/OpZEVqaT1xKVi35ohP1QfNjxPLlHD+K\n" + +- "iDAR9z6zkwjIrbwPCnb5kuXy4lpwPcmmmkva25fI7qlpHtbcuQdoBdCfr/KkKaUCMPyY89LCXgEw\n" + +- "5KTDj64UywKBgQCNfbO+eZLGzhiHhtNJurresCsIGWlInv322gL8CSfBMYl6eNfUTZvUDdFhPISL\n" + +- "UljKWzXDrjw0ujFSPR0XhUGtiq89H+HUTuPPYv25gVXO+HTgBFZEPl4PpA+BUsSVZy0NddneyqLk\n" + +- "42Wey9omY9Q8WsdNQS5cbUvy0uG6WFoX7wKBgQDZ1jpW8pa0x2bZsQsm4vo+3G5CRnZlUp+XlWt2\n" + +- "dDcp5dC0xD1zbs1dc0NcLeGDOTDv9FSl7hok42iHXXq8AygjEm/QcuwwQ1nC2HxmQP5holAiUs4D\n" + +- "WHM8PWs3wFYPzE459EBoKTxeaeP/uWAn+he8q7d5uWvSZlEcANs/6e77eQKBgD21Ar0hfFfj7mK8\n" + +- "9E0FeRZBsqK3omkfnhcYgZC11Xa2SgT1yvs2Va2n0RcdM5kncr3eBZav2GYOhhAdwyBM55XuE/sO\n" + +- "eokDVutNeuZ6d5fqV96TRaRBpvgfTvvRwxZ9hvKF4Vz+9wfn/JvCwANaKmegF6ejs7pvmF3whq2k\n" + +- "drZVAoGAX5YxQ5XMTD0QbMAl7/6qp6S58xNoVdfCkmkj1ZLKaHKIjS/benkKGlySVQVPexPfnkZx\n" + +- "p/Vv9yyphBoudiTBS9Uog66ueLYZqpgxlM/6OhYg86Gm3U2ycvMxYjBM1NFiyze21AqAhI+HX+Ot\n" + +- "mraV2/guSgDgZAhukRZzeQ2RucI=\n" + +- "-----END PRIVATE KEY-----"; +- +- static { +- Throwable cause = null; +- +- if (SystemPropertyUtil.getBoolean("io.netty.handler.ssl.noOpenSsl", false)) { +- cause = new UnsupportedOperationException( +- "OpenSSL was explicit disabled with -Dio.netty.handler.ssl.noOpenSsl=true"); +- +- logger.debug( +- "netty-tcnative explicit disabled; " + +- OpenSslEngine.class.getSimpleName() + " will be unavailable.", cause); +- } else { +- // Test if netty-tcnative is in the classpath first. +- try { +- Class.forName("io.netty.internal.tcnative.SSLContext", false, OpenSsl.class.getClassLoader()); +- } catch (ClassNotFoundException t) { +- cause = t; +- logger.debug( +- "netty-tcnative not in the classpath; " + +- OpenSslEngine.class.getSimpleName() + " will be unavailable."); +- } +- +- // If in the classpath, try to load the native library and initialize netty-tcnative. +- if (cause == null) { +- try { +- // The JNI library was not already loaded. Load it now. +- loadTcNative(); +- } catch (Throwable t) { +- cause = t; +- logger.debug( +- "Failed to load netty-tcnative; " + +- OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " + +- "application has already loaded the symbols by some other means. " + +- "See https://netty.io/wiki/forked-tomcat-native.html for more information.", t); +- } +- +- try { +- String engine = SystemPropertyUtil.get("io.netty.handler.ssl.openssl.engine", null); +- if (engine == null) { +- logger.debug("Initialize netty-tcnative using engine: 'default'"); +- } else { +- logger.debug("Initialize netty-tcnative using engine: '{}'", engine); +- } +- initializeTcNative(engine); +- +- // The library was initialized successfully. If loading the library failed above, +- // reset the cause now since it appears that the library was loaded by some other +- // means. +- cause = null; +- } catch (Throwable t) { +- if (cause == null) { +- cause = t; +- } +- logger.debug( +- "Failed to initialize netty-tcnative; " + +- OpenSslEngine.class.getSimpleName() + " will be unavailable. " + +- "See https://netty.io/wiki/forked-tomcat-native.html for more information.", t); +- } +- } +- } +- +- UNAVAILABILITY_CAUSE = cause; +- +- if (cause == null) { +- logger.debug("netty-tcnative using native library: {}", SSL.versionString()); +- +- final List<String> defaultCiphers = new ArrayList<String>(); +- final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<String>(128); +- boolean supportsKeyManagerFactory = false; +- boolean useKeyManagerFactory = false; +- boolean tlsv13Supported = false; +- +- IS_BORINGSSL = "BoringSSL".equals(versionString()); +- if (IS_BORINGSSL) { +- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = new String [] { "TLS_AES_128_GCM_SHA256", +- "TLS_AES_256_GCM_SHA384" , +- "TLS_CHACHA20_POLY1305_SHA256" }; +- } else { +- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS; +- } +- +- try { +- final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER); +- long certBio = 0; +- long keyBio = 0; +- long cert = 0; +- long key = 0; +- try { +- try { +- StringBuilder tlsv13Ciphers = new StringBuilder(); +- +- for (String cipher: TLSV13_CIPHERS) { +- String converted = CipherSuiteConverter.toOpenSsl(cipher, IS_BORINGSSL); +- if (converted != null) { +- tlsv13Ciphers.append(converted).append(':'); +- } +- } +- if (tlsv13Ciphers.length() == 0) { +- tlsv13Supported = false; +- } else { +- tlsv13Ciphers.setLength(tlsv13Ciphers.length() - 1); +- SSLContext.setCipherSuite(sslCtx, tlsv13Ciphers.toString() , true); +- tlsv13Supported = true; +- } +- +- } catch (Exception ignore) { +- tlsv13Supported = false; +- } +- +- SSLContext.setCipherSuite(sslCtx, "ALL", false); +- +- final long ssl = SSL.newSSL(sslCtx, true); +- try { +- for (String c: SSL.getCiphers(ssl)) { +- // Filter out bad input. +- if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c) || +- // Filter out TLSv1.3 ciphers if not supported. +- !tlsv13Supported && isTLSv13Cipher(c)) { +- continue; +- } +- availableOpenSslCipherSuites.add(c); +- } +- if (IS_BORINGSSL) { +- // Currently BoringSSL does not include these when calling SSL.getCiphers() even when these +- // are supported. +- Collections.addAll(availableOpenSslCipherSuites, EXTRA_SUPPORTED_TLS_1_3_CIPHERS); +- Collections.addAll(availableOpenSslCipherSuites, +- "AEAD-AES128-GCM-SHA256", +- "AEAD-AES256-GCM-SHA384", +- "AEAD-CHACHA20-POLY1305-SHA256"); +- } +- +- PemEncoded privateKey = PemPrivateKey.valueOf(KEY.getBytes(CharsetUtil.US_ASCII)); +- try { +- // Let's check if we can set a callback, which may not work if the used OpenSSL version +- // is to old. +- SSLContext.setCertificateCallback(sslCtx, null); +- +- X509Certificate certificate = selfSignedCertificate(); +- certBio = ReferenceCountedOpenSslContext.toBIO(ByteBufAllocator.DEFAULT, certificate); +- cert = SSL.parseX509Chain(certBio); +- +- keyBio = ReferenceCountedOpenSslContext.toBIO( +- UnpooledByteBufAllocator.DEFAULT, privateKey.retain()); +- key = SSL.parsePrivateKey(keyBio, null); +- +- SSL.setKeyMaterial(ssl, cert, key); +- supportsKeyManagerFactory = true; +- try { +- boolean propertySet = SystemPropertyUtil.contains( +- "io.netty.handler.ssl.openssl.useKeyManagerFactory"); +- if (!IS_BORINGSSL) { +- useKeyManagerFactory = SystemPropertyUtil.getBoolean( +- "io.netty.handler.ssl.openssl.useKeyManagerFactory", true); +- +- if (propertySet) { +- logger.info("System property " + +- "'io.netty.handler.ssl.openssl.useKeyManagerFactory'" + +- " is deprecated and so will be ignored in the future"); +- } +- } else { +- useKeyManagerFactory = true; +- if (propertySet) { +- logger.info("System property " + +- "'io.netty.handler.ssl.openssl.useKeyManagerFactory'" + +- " is deprecated and will be ignored when using BoringSSL"); +- } +- } +- } catch (Throwable ignore) { +- logger.debug("Failed to get useKeyManagerFactory system property."); +- } +- } catch (Error ignore) { +- logger.debug("KeyManagerFactory not supported."); +- } finally { +- privateKey.release(); +- } +- } finally { +- SSL.freeSSL(ssl); +- if (certBio != 0) { +- SSL.freeBIO(certBio); +- } +- if (keyBio != 0) { +- SSL.freeBIO(keyBio); +- } +- if (cert != 0) { +- SSL.freeX509Chain(cert); +- } +- if (key != 0) { +- SSL.freePrivateKey(key); +- } +- } +- } finally { +- SSLContext.free(sslCtx); +- } +- } catch (Exception e) { +- logger.warn("Failed to get the list of available OpenSSL cipher suites.", e); +- } +- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites); +- final Set<String> availableJavaCipherSuites = new LinkedHashSet<String>( +- AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2); +- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) { +- // Included converted but also openssl cipher name +- if (!isTLSv13Cipher(cipher)) { +- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS")); +- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL")); +- } else { +- // TLSv1.3 ciphers have the correct format. +- availableJavaCipherSuites.add(cipher); +- } +- } +- +- addIfSupported(availableJavaCipherSuites, defaultCiphers, DEFAULT_CIPHER_SUITES); +- addIfSupported(availableJavaCipherSuites, defaultCiphers, TLSV13_CIPHER_SUITES); +- +- useFallbackCiphersIfDefaultIsEmpty(defaultCiphers, availableJavaCipherSuites); +- DEFAULT_CIPHERS = Collections.unmodifiableList(defaultCiphers); +- +- AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites); +- +- final Set<String> availableCipherSuites = new LinkedHashSet<String>( +- AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size()); +- availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES); +- availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES); +- +- AVAILABLE_CIPHER_SUITES = availableCipherSuites; +- SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory; +- USE_KEYMANAGER_FACTORY = useKeyManagerFactory; +- +- Set<String> protocols = new LinkedHashSet<String>(6); +- // Seems like there is no way to explicitly disable SSLv2Hello in openssl so it is always enabled +- protocols.add(PROTOCOL_SSL_V2_HELLO); +- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2, SSL.SSL_OP_NO_SSLv2)) { +- protocols.add(PROTOCOL_SSL_V2); +- } +- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3, SSL.SSL_OP_NO_SSLv3)) { +- protocols.add(PROTOCOL_SSL_V3); +- } +- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1, SSL.SSL_OP_NO_TLSv1)) { +- protocols.add(PROTOCOL_TLS_V1); +- } +- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1, SSL.SSL_OP_NO_TLSv1_1)) { +- protocols.add(PROTOCOL_TLS_V1_1); +- } +- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_OP_NO_TLSv1_2)) { +- protocols.add(PROTOCOL_TLS_V1_2); +- } +- +- // This is only supported by java11 and later. +- if (tlsv13Supported && doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_3, SSL.SSL_OP_NO_TLSv1_3)) { +- protocols.add(PROTOCOL_TLS_V1_3); +- TLSV13_SUPPORTED = true; +- } else { +- TLSV13_SUPPORTED = false; +- } +- +- SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols); +- SUPPORTS_OCSP = doesSupportOcsp(); +- +- if (logger.isDebugEnabled()) { +- logger.debug("Supported protocols (OpenSSL): {} ", SUPPORTED_PROTOCOLS_SET); +- logger.debug("Default cipher suites (OpenSSL): {}", DEFAULT_CIPHERS); +- } +- } else { +- DEFAULT_CIPHERS = Collections.emptyList(); +- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet(); +- AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet(); +- AVAILABLE_CIPHER_SUITES = Collections.emptySet(); +- SUPPORTS_KEYMANAGER_FACTORY = false; +- USE_KEYMANAGER_FACTORY = false; +- SUPPORTED_PROTOCOLS_SET = Collections.emptySet(); +- SUPPORTS_OCSP = false; +- TLSV13_SUPPORTED = false; +- IS_BORINGSSL = false; +- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS; +- } - } - - /** -- * Creates a new instance. -- * -- * @param certChainFile an X.509 certificate chain file in PEM format. -- * {@code null} to use the system default -- * @deprecated use {@link SslContextBuilder} +- * Returns a self-signed {@link X509Certificate} for {@code netty.io}. - */ -- @Deprecated -- public OpenSslClientContext(File certChainFile) throws SSLException { -- this(certChainFile, null); +- static X509Certificate selfSignedCertificate() throws CertificateException { +- return (X509Certificate) SslContext.X509_CERT_FACTORY.generateCertificate( +- new ByteArrayInputStream(CERT.getBytes(CharsetUtil.US_ASCII)) +- ); +- } +- +- private static boolean doesSupportOcsp() { +- boolean supportsOcsp = false; +- if (version() >= 0x10002000L) { +- long sslCtx = -1; +- try { +- sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_MODE_SERVER); +- SSLContext.enableOcsp(sslCtx, false); +- supportsOcsp = true; +- } catch (Exception ignore) { +- // ignore +- } finally { +- if (sslCtx != -1) { +- SSLContext.free(sslCtx); +- } +- } +- } +- return supportsOcsp; +- } +- private static boolean doesSupportProtocol(int protocol, int opt) { +- if (opt == 0) { +- // If the opt is 0 the protocol is not supported. This is for example the case with BoringSSL and SSLv2. +- return false; +- } +- long sslCtx = -1; +- try { +- sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED); +- return true; +- } catch (Exception ignore) { +- return false; +- } finally { +- if (sslCtx != -1) { +- SSLContext.free(sslCtx); +- } +- } - } - - /** -- * Creates a new instance. -- * -- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s -- * that verifies the certificates sent from servers. -- * {@code null} to use the default. -- * @deprecated use {@link SslContextBuilder} +- * Returns {@code true} if and only if +- * <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support +- * are available. - */ -- @Deprecated -- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws SSLException { -- this(null, trustManagerFactory); +- public static boolean isAvailable() { +- return UNAVAILABILITY_CAUSE == null; - } - - /** -- * Creates a new instance. +- * Returns {@code true} if the used version of openssl supports +- * <a href="https://tools.ietf.org/html/rfc7301">ALPN</a>. - * -- * @param certChainFile an X.509 certificate chain file in PEM format. -- * {@code null} to use the system default -- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s -- * that verifies the certificates sent from servers. -- * {@code null} to use the default. -- * @deprecated use {@link SslContextBuilder} +- * @deprecated use {@link SslProvider#isAlpnSupported(SslProvider)} with {@link SslProvider#OPENSSL}. - */ - @Deprecated -- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException { -- this(certChainFile, trustManagerFactory, null, null, null, null, null, -- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0); +- public static boolean isAlpnSupported() { +- return version() >= 0x10002000L; - } - - /** -- * Creates a new instance. -- * -- * @param certChainFile an X.509 certificate chain file in PEM format -- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s -- * that verifies the certificates sent from servers. -- * {@code null} to use the default.. -- * @param ciphers the cipher suites to enable, in the order of preference. -- * {@code null} to use the default cipher suites. -- * @param apn Provides a means to configure parameters related to application protocol negotiation. -- * @param sessionCacheSize the size of the cache used for storing SSL session objects. -- * {@code 0} to use the default value. -- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. -- * {@code 0} to use the default value. -- * @deprecated use {@link SslContextBuilder} +- * Returns {@code true} if the used version of OpenSSL supports OCSP stapling. - */ -- @Deprecated -- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers, -- ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) -- throws SSLException { -- this(certChainFile, trustManagerFactory, null, null, null, null, ciphers, IdentityCipherSuiteFilter.INSTANCE, -- apn, sessionCacheSize, sessionTimeout); +- public static boolean isOcspSupported() { +- return SUPPORTS_OCSP; - } - - /** -- * Creates a new instance. -- * -- * @param certChainFile an X.509 certificate chain file in PEM format -- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s -- * that verifies the certificates sent from servers. -- * {@code null} to use the default.. -- * @param ciphers the cipher suites to enable, in the order of preference. -- * {@code null} to use the default cipher suites. -- * @param cipherFilter a filter to apply over the supplied list of ciphers -- * @param apn Provides a means to configure parameters related to application protocol negotiation. -- * @param sessionCacheSize the size of the cache used for storing SSL session objects. -- * {@code 0} to use the default value. -- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. -- * {@code 0} to use the default value. -- * @deprecated use {@link SslContextBuilder} +- * Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()} +- * returns {@code false}. +- */ +- public static int version() { +- return isAvailable() ? SSL.version() : -1; +- } +- +- /** +- * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()} +- * returns {@code false}. +- */ +- public static String versionString() { +- return isAvailable() ? SSL.versionString() : null; +- } +- +- /** +- * Ensure that <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and +- * its OpenSSL support are available. +- * +- * @throws UnsatisfiedLinkError if unavailable +- */ +- public static void ensureAvailability() { +- if (UNAVAILABILITY_CAUSE != null) { +- throw (Error) new UnsatisfiedLinkError( +- "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE); +- } +- } +- +- /** +- * Returns the cause of unavailability of +- * <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support. +- * +- * @return the cause if unavailable. {@code null} if available. +- */ +- public static Throwable unavailabilityCause() { +- return UNAVAILABILITY_CAUSE; +- } +- +- /** +- * @deprecated use {@link #availableOpenSslCipherSuites()} - */ - @Deprecated -- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers, -- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- this(certChainFile, trustManagerFactory, null, null, null, null, -- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); +- public static Set<String> availableCipherSuites() { +- return availableOpenSslCipherSuites(); - } - - /** -- * Creates a new instance. -- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. -- * {@code null} to use the system default -- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s -- * that verifies the certificates sent from servers. -- * {@code null} to use the default or the results of parsing -- * {@code trustCertCollectionFile} -- * @param keyCertChainFile an X.509 certificate chain file in PEM format. -- * This provides the public key for mutual authentication. -- * {@code null} to use the system default -- * @param keyFile a PKCS#8 private key file in PEM format. -- * This provides the private key for mutual authentication. -- * {@code null} for no mutual authentication. -- * @param keyPassword the password of the {@code keyFile}. -- * {@code null} if it's not password-protected. -- * Ignored if {@code keyFile} is {@code null}. -- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link javax.net.ssl.KeyManager}s -- * that is used to encrypt data being sent to servers. -- * {@code null} to use the default or the results of parsing -- * {@code keyCertChainFile} and {@code keyFile}. -- * @param ciphers the cipher suites to enable, in the order of preference. -- * {@code null} to use the default cipher suites. -- * @param cipherFilter a filter to apply over the supplied list of ciphers -- * @param apn Application Protocol Negotiator object. -- * @param sessionCacheSize the size of the cache used for storing SSL session objects. -- * {@code 0} to use the default value. -- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. -- * {@code 0} to use the default value. -- * @deprecated use {@link SslContextBuilder} +- * Returns all the available OpenSSL cipher suites. +- * Please note that the returned array may include the cipher suites that are insecure or non-functional. +- */ +- public static Set<String> availableOpenSslCipherSuites() { +- return AVAILABLE_OPENSSL_CIPHER_SUITES; +- } +- +- /** +- * Returns all the available cipher suites (Java-style). +- * Please note that the returned array may include the cipher suites that are insecure or non-functional. +- */ +- public static Set<String> availableJavaCipherSuites() { +- return AVAILABLE_JAVA_CIPHER_SUITES; +- } +- +- /** +- * Returns {@code true} if and only if the specified cipher suite is available in OpenSSL. +- * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted. +- */ +- public static boolean isCipherSuiteAvailable(String cipherSuite) { +- String converted = CipherSuiteConverter.toOpenSsl(cipherSuite, IS_BORINGSSL); +- if (converted != null) { +- cipherSuite = converted; +- } +- return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite); +- } +- +- /** +- * Returns {@code true} if {@link javax.net.ssl.KeyManagerFactory} is supported when using OpenSSL. +- */ +- public static boolean supportsKeyManagerFactory() { +- return SUPPORTS_KEYMANAGER_FACTORY; +- } +- +- /** +- * Always returns {@code true} if {@link #isAvailable()} returns {@code true}. +- * +- * @deprecated Will be removed because hostname validation is always done by a +- * {@link javax.net.ssl.TrustManager} implementation. - */ - @Deprecated -- public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, -- File keyCertChainFile, File keyFile, String keyPassword, -- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, -- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, -- long sessionCacheSize, long sessionTimeout) -- throws SSLException { -- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, -- toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), -- keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, null, sessionCacheSize, -- sessionTimeout, false); +- public static boolean supportsHostnameValidation() { +- return isAvailable(); - } - -- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, -- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, -- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, -- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols, -- long sessionCacheSize, long sessionTimeout, boolean enableOcsp) -- throws SSLException { -- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, -- ClientAuth.NONE, protocols, false, enableOcsp); -- boolean success = false; -- try { -- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, -- keyCertChain, key, keyPassword, keyManagerFactory); -- success = true; -- } finally { -- if (!success) { -- release(); -- } +- static boolean useKeyManagerFactory() { +- return USE_KEYMANAGER_FACTORY; +- } +- +- static long memoryAddress(ByteBuf buf) { +- assert buf.isDirect(); +- return buf.hasMemoryAddress() ? buf.memoryAddress() : Buffer.address(buf.nioBuffer()); +- } +- +- private OpenSsl() { } +- +- private static void loadTcNative() throws Exception { +- String os = PlatformDependent.normalizedOs(); +- String arch = PlatformDependent.normalizedArch(); +- +- Set<String> libNames = new LinkedHashSet<String>(5); +- String staticLibName = "netty_tcnative"; +- +- // First, try loading the platform-specific library. Platform-specific +- // libraries will be available if using a tcnative uber jar. +- if ("linux".equalsIgnoreCase(os)) { +- Set<String> classifiers = PlatformDependent.normalizedLinuxClassifiers(); +- for (String classifier : classifiers) { +- libNames.add(staticLibName + "_" + os + '_' + arch + "_" + classifier); +- } +- // generic arch-dependent library +- libNames.add(staticLibName + "_" + os + '_' + arch); +- +- // Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0). +- // note: should already be included from the classifiers but if not, we use this as an +- // additional fallback option here +- libNames.add(staticLibName + "_" + os + '_' + arch + "_fedora"); +- } else { +- libNames.add(staticLibName + "_" + os + '_' + arch); - } +- libNames.add(staticLibName + "_" + arch); +- libNames.add(staticLibName); +- +- NativeLibraryLoader.loadFirstAvailable(SSLContext.class.getClassLoader(), +- libNames.toArray(new String[0])); - } - -- @Override -- public OpenSslSessionContext sessionContext() { -- return sessionContext; +- private static boolean initializeTcNative(String engine) throws Exception { +- return Library.initialize("provided", engine); - } - -- @Override -- OpenSslKeyMaterialManager keyMaterialManager() { -- return null; +- static void releaseIfNeeded(ReferenceCounted counted) { +- if (counted.refCnt() > 0) { +- ReferenceCountUtil.safeRelease(counted); +- } +- } +- +- static boolean isTlsv13Supported() { +- return TLSV13_SUPPORTED; +- } +- +- static boolean isBoringSSL() { +- return IS_BORINGSSL; - } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java deleted file mode 100644 -index c4ca6b5..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java +index 07b67d9fa7..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java +++ /dev/null -@@ -1,58 +0,0 @@ +@@ -1,79 +0,0 @@ -/* -- * Copyright 2014 The Netty Project +- * Copyright 2018 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 @@ -933,53 +1356,74 @@ index c4ca6b5..0000000 - -import io.netty.buffer.ByteBufAllocator; - --import java.security.cert.Certificate; -- --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLException; +-import javax.net.ssl.X509KeyManager; +-import java.util.Iterator; +-import java.util.concurrent.ConcurrentHashMap; +-import java.util.concurrent.ConcurrentMap; - -/** -- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers -- * and manually release the native memory see {@link ReferenceCountedOpenSslContext}. +- * {@link OpenSslKeyMaterialProvider} that will cache the {@link OpenSslKeyMaterial} to reduce the overhead +- * of parsing the chain and the key for generation of the material. - */ --public abstract class OpenSslContext extends ReferenceCountedOpenSslContext { -- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg, -- long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain, -- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp) -- throws SSLException { -- super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain, -- clientAuth, protocols, startTls, enableOcsp, false); -- } +-final class OpenSslCachingKeyMaterialProvider extends OpenSslKeyMaterialProvider { - -- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, -- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, -- long sessionTimeout, int mode, Certificate[] keyCertChain, -- ClientAuth clientAuth, String[] protocols, boolean startTls, -- boolean enableOcsp) throws SSLException { -- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, protocols, -- startTls, enableOcsp, false); +- private final int maxCachedEntries; +- private volatile boolean full; +- private final ConcurrentMap<String, OpenSslKeyMaterial> cache = new ConcurrentHashMap<String, OpenSslKeyMaterial>(); +- +- OpenSslCachingKeyMaterialProvider(X509KeyManager keyManager, String password, int maxCachedEntries) { +- super(keyManager, password); +- this.maxCachedEntries = maxCachedEntries; - } - - @Override -- final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) { -- return new OpenSslEngine(this, alloc, peerHost, peerPort); +- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception { +- OpenSslKeyMaterial material = cache.get(alias); +- if (material == null) { +- material = super.chooseKeyMaterial(allocator, alias); +- if (material == null) { +- // No keymaterial should be used. +- return null; +- } +- +- if (full) { +- return material; +- } +- if (cache.size() > maxCachedEntries) { +- full = true; +- // Do not cache... +- return material; +- } +- OpenSslKeyMaterial old = cache.putIfAbsent(alias, material); +- if (old != null) { +- material.release(); +- material = old; +- } +- } +- // We need to call retain() as we want to always have at least a refCnt() of 1 before destroy() was called. +- return material.retain(); - } - - @Override -- @SuppressWarnings("FinalizeDeclaration") -- protected final void finalize() throws Throwable { -- super.finalize(); -- OpenSsl.releaseIfNeeded(this); +- void destroy() { +- // Remove and release all entries. +- do { +- Iterator<OpenSslKeyMaterial> iterator = cache.values().iterator(); +- while (iterator.hasNext()) { +- iterator.next().release(); +- iterator.remove(); +- } +- } while (!cache.isEmpty()); - } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java deleted file mode 100644 -index cbc7ee4..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java +index 7f67bc8198..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java +++ /dev/null -@@ -1,40 +0,0 @@ +@@ -1,81 +0,0 @@ -/* -- * Copyright 2014 The Netty Project +- * Copyright 2018 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 @@ -995,37 +1439,78 @@ index cbc7ee4..0000000 - */ -package io.netty.handler.ssl; - --import io.netty.buffer.ByteBufAllocator; +-import io.netty.util.internal.ObjectUtil; - --import javax.net.ssl.SSLEngine; +-import javax.net.ssl.KeyManager; +-import javax.net.ssl.KeyManagerFactory; +-import javax.net.ssl.KeyManagerFactorySpi; +-import javax.net.ssl.ManagerFactoryParameters; +-import javax.net.ssl.X509ExtendedKeyManager; +-import javax.net.ssl.X509KeyManager; +-import java.security.InvalidAlgorithmParameterException; +-import java.security.KeyStore; +-import java.security.KeyStoreException; +-import java.security.NoSuchAlgorithmException; +-import java.security.PrivateKey; +-import java.security.UnrecoverableKeyException; +-import java.security.cert.X509Certificate; - -/** -- * Implements a {@link SSLEngine} using -- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>. -- * <p> -- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers -- * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}. +- * Wraps another {@link KeyManagerFactory} and caches its chains / certs for an alias for better performance when using +- * {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT}. +- * +- * Because of the caching its important that the wrapped {@link KeyManagerFactory}s {@link X509KeyManager}s always +- * return the same {@link X509Certificate} chain and {@link PrivateKey} for the same alias. - */ --public final class OpenSslEngine extends ReferenceCountedOpenSslEngine { -- OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int peerPort) { -- super(context, alloc, peerHost, peerPort, false); +-public final class OpenSslCachingX509KeyManagerFactory extends KeyManagerFactory { +- +- private final int maxCachedEntries; +- +- public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory) { +- this(factory, 1024); - } - -- @Override -- @SuppressWarnings("FinalizeDeclaration") -- protected void finalize() throws Throwable { -- super.finalize(); -- OpenSsl.releaseIfNeeded(this); +- public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory, int maxCachedEntries) { +- super(new KeyManagerFactorySpi() { +- @Override +- protected void engineInit(KeyStore keyStore, char[] chars) +- throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { +- factory.init(keyStore, chars); +- } +- +- @Override +- protected void engineInit(ManagerFactoryParameters managerFactoryParameters) +- throws InvalidAlgorithmParameterException { +- factory.init(managerFactoryParameters); +- } +- +- @Override +- protected KeyManager[] engineGetKeyManagers() { +- return factory.getKeyManagers(); +- } +- }, factory.getProvider(), factory.getAlgorithm()); +- this.maxCachedEntries = ObjectUtil.checkPositive(maxCachedEntries, "maxCachedEntries"); +- } +- +- OpenSslKeyMaterialProvider newProvider(String password) { +- X509KeyManager keyManager = ReferenceCountedOpenSslContext.chooseX509KeyManager(getKeyManagers()); +- if ("sun.security.ssl.X509KeyManagerImpl".equals(keyManager.getClass().getName())) { +- // Don't do caching if X509KeyManagerImpl is used as the returned aliases are not stable and will change +- // between invocations. +- return new OpenSslKeyMaterialProvider(keyManager, password); +- } +- return new OpenSslCachingKeyMaterialProvider( +- ReferenceCountedOpenSslContext.chooseX509KeyManager(getKeyManagers()), password, maxCachedEntries); - } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java deleted file mode 100644 -index 02131b4..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java +index f20b2d3ba0..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java +++ /dev/null -@@ -1,35 +0,0 @@ +@@ -1,81 +0,0 @@ -/* -- * Copyright 2014 The Netty Project +- * 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 @@ -1041,261 +1526,76 @@ index 02131b4..0000000 - */ -package io.netty.handler.ssl; - --interface OpenSslEngineMap { +-import io.netty.internal.tcnative.CertificateVerifier; - -- /** -- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and -- * return it. -- */ -- ReferenceCountedOpenSslEngine remove(long ssl); -- -- /** -- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}. -- */ -- void add(ReferenceCountedOpenSslEngine engine); -- -- /** -- * Get the {@link OpenSslEngine} for the given {@code ssl} address. -- */ -- ReferenceCountedOpenSslEngine get(long ssl); --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java -deleted file mode 100644 -index 38f6a7f..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java -+++ /dev/null -@@ -1,40 +0,0 @@ --/* -- * 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 javax.net.ssl.X509ExtendedKeyManager; --import javax.security.auth.x500.X500Principal; -- --final class OpenSslExtendedKeyMaterialManager extends OpenSslKeyMaterialManager { -- -- private final X509ExtendedKeyManager keyManager; -- -- OpenSslExtendedKeyMaterialManager(X509ExtendedKeyManager keyManager, String password) { -- super(keyManager, password); -- this.keyManager = keyManager; -- } -- -- @Override -- protected String chooseClientAlias(ReferenceCountedOpenSslEngine engine, String[] keyTypes, -- X500Principal[] issuer) { -- return keyManager.chooseEngineClientAlias(keyTypes, issuer, engine); -- } -- -- @Override -- protected String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) { -- return keyManager.chooseEngineServerAlias(type, null, engine); -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java -deleted file mode 100644 -index 2e48e8b..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java -+++ /dev/null -@@ -1,179 +0,0 @@ --/* -- * 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.buffer.ByteBufAllocator; --import io.netty.internal.tcnative.CertificateRequestedCallback; --import io.netty.internal.tcnative.SSL; -- --import javax.net.ssl.SSLException; --import javax.net.ssl.X509KeyManager; --import javax.security.auth.x500.X500Principal; --import java.security.PrivateKey; --import java.security.cert.X509Certificate; --import java.util.HashMap; --import java.util.HashSet; --import java.util.Map; --import java.util.Set; -- --import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.freeBio; --import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO; +-import java.security.cert.CertificateException; - -/** -- * Manages key material for {@link OpenSslEngine}s and so set the right {@link PrivateKey}s and -- * {@link X509Certificate}s. +- * A special {@link CertificateException} which allows to specify which error code is included in the +- * SSL Record. This only work when {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT} is used. - */ --class OpenSslKeyMaterialManager { -- -- // Code in this class is inspired by code of conscrypts: -- // - https://android.googlesource.com/platform/external/ -- // conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java -- // - https://android.googlesource.com/platform/external/ -- // conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java -- // -- static final String KEY_TYPE_RSA = "RSA"; -- static final String KEY_TYPE_DH_RSA = "DH_RSA"; -- static final String KEY_TYPE_EC = "EC"; -- static final String KEY_TYPE_EC_EC = "EC_EC"; -- static final String KEY_TYPE_EC_RSA = "EC_RSA"; -- -- // key type mappings for types. -- private static final Map<String, String> KEY_TYPES = new HashMap<String, String>(); -- static { -- KEY_TYPES.put("RSA", KEY_TYPE_RSA); -- KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA); -- KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA); -- KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC); -- KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA); -- KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC); -- KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA); -- } +-public final class OpenSslCertificateException extends CertificateException { +- private static final long serialVersionUID = 5542675253797129798L; - -- private final X509KeyManager keyManager; -- private final String password; +- private final int errorCode; - -- OpenSslKeyMaterialManager(X509KeyManager keyManager, String password) { -- this.keyManager = keyManager; -- this.password = password; +- /** +- * Construct a new exception with the +- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a>. +- */ +- public OpenSslCertificateException(int errorCode) { +- this((String) null, errorCode); - } - -- void setKeyMaterial(ReferenceCountedOpenSslEngine engine) throws SSLException { -- long ssl = engine.sslPointer(); -- String[] authMethods = SSL.authenticationMethods(ssl); -- Set<String> aliases = new HashSet<String>(authMethods.length); -- for (String authMethod : authMethods) { -- String type = KEY_TYPES.get(authMethod); -- if (type != null) { -- String alias = chooseServerAlias(engine, type); -- if (alias != null && aliases.add(alias)) { -- setKeyMaterial(ssl, alias); -- } -- } -- } +- /** +- * Construct a new exception with the msg and +- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> . +- */ +- public OpenSslCertificateException(String msg, int errorCode) { +- super(msg); +- this.errorCode = checkErrorCode(errorCode); - } - -- CertificateRequestedCallback.KeyMaterial keyMaterial(ReferenceCountedOpenSslEngine engine, String[] keyTypes, -- X500Principal[] issuer) throws SSLException { -- String alias = chooseClientAlias(engine, keyTypes, issuer); -- long keyBio = 0; -- long keyCertChainBio = 0; -- long pkey = 0; -- long certChain = 0; -- -- try { -- // TODO: Should we cache these and so not need to do a memory copy all the time ? -- X509Certificate[] certificates = keyManager.getCertificateChain(alias); -- if (certificates == null || certificates.length == 0) { -- return null; -- } -- -- PrivateKey key = keyManager.getPrivateKey(alias); -- keyCertChainBio = toBIO(certificates); -- certChain = SSL.parseX509Chain(keyCertChainBio); -- if (key != null) { -- keyBio = toBIO(key); -- pkey = SSL.parsePrivateKey(keyBio, password); -- } -- CertificateRequestedCallback.KeyMaterial material = new CertificateRequestedCallback.KeyMaterial( -- certChain, pkey); -- -- // Reset to 0 so we do not free these. This is needed as the client certificate callback takes ownership -- // of both the key and the certificate if they are returned from this method, and thus must not -- // be freed here. -- certChain = pkey = 0; -- return material; -- } catch (SSLException e) { -- throw e; -- } catch (Exception e) { -- throw new SSLException(e); -- } finally { -- freeBio(keyBio); -- freeBio(keyCertChainBio); -- SSL.freePrivateKey(pkey); -- SSL.freeX509Chain(certChain); -- } +- /** +- * Construct a new exception with the msg, cause and +- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> . +- */ +- public OpenSslCertificateException(String message, Throwable cause, int errorCode) { +- super(message, cause); +- this.errorCode = checkErrorCode(errorCode); - } - -- private void setKeyMaterial(long ssl, String alias) throws SSLException { -- long keyBio = 0; -- long keyCertChainBio = 0; -- long keyCertChainBio2 = 0; -- -- try { -- // TODO: Should we cache these and so not need to do a memory copy all the time ? -- X509Certificate[] certificates = keyManager.getCertificateChain(alias); -- if (certificates == null || certificates.length == 0) { -- return; -- } -- -- PrivateKey key = keyManager.getPrivateKey(alias); -- -- // Only encode one time -- PemEncoded encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, certificates); -- try { -- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); -- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); -- -- if (key != null) { -- keyBio = toBIO(key); -- } -- SSL.setCertificateBio(ssl, keyCertChainBio, keyBio, password); -- -- // We may have more then one cert in the chain so add all of them now. -- SSL.setCertificateChainBio(ssl, keyCertChainBio2, true); -- } finally { -- encoded.release(); -- } -- } catch (SSLException e) { -- throw e; -- } catch (Exception e) { -- throw new SSLException(e); -- } finally { -- freeBio(keyBio); -- freeBio(keyCertChainBio); -- freeBio(keyCertChainBio2); -- } +- /** +- * Construct a new exception with the cause and +- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> . +- */ +- public OpenSslCertificateException(Throwable cause, int errorCode) { +- this(null, cause, errorCode); - } - -- protected String chooseClientAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine, -- String[] keyTypes, X500Principal[] issuer) { -- return keyManager.chooseClientAlias(keyTypes, issuer, null); +- /** +- * Return the <a href="https://www.openssl.org/docs/man1.0.2/apps/verify.html">error code</a> to use. +- */ +- public int errorCode() { +- return errorCode; - } - -- protected String chooseServerAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine, String type) { -- return keyManager.chooseServerAlias(type, null, null); +- private static int checkErrorCode(int errorCode) { +- // Call OpenSsl.isAvailable() to ensure we try to load the native lib as CertificateVerifier.isValid(...) +- // will depend on it. If loading fails we will just skip the validation. +- if (OpenSsl.isAvailable() && !CertificateVerifier.isValid(errorCode)) { +- throw new IllegalArgumentException("errorCode '" + errorCode + +- "' invalid, see https://www.openssl.org/docs/man1.0.2/apps/verify.html."); +- } +- return errorCode; - } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java deleted file mode 100644 -index f57434b..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java +index 7f9b39a8dd..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java +++ /dev/null -@@ -1,373 +0,0 @@ +@@ -1,208 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -1313,143 +1613,88 @@ index f57434b..0000000 - */ -package io.netty.handler.ssl; - --import io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.ServerContext; -import io.netty.internal.tcnative.SSL; - -import java.io.File; +-import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; - --import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLException; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - --import static io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.newSessionContext; +-import static io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext; - -/** -- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. - * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers -- * and manually release the native memory see {@link ReferenceCountedOpenSslServerContext}. +- * and manually release the native memory see {@link ReferenceCountedOpenSslClientContext}. - */ --public final class OpenSslServerContext extends OpenSslContext { -- private final OpenSslServerSessionContext sessionContext; -- private final OpenSslKeyMaterialManager keyMaterialManager; +-public final class OpenSslClientContext extends OpenSslContext { +- private final OpenSslSessionContext sessionContext; - - /** - * Creates a new instance. -- * -- * @param certChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated -- public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException { -- this(certChainFile, keyFile, null); +- public OpenSslClientContext() throws SSLException { +- this(null, null, null, null, null, null, null, IdentityCipherSuiteFilter.INSTANCE, null, 0, 0); - } - - /** - * Creates a new instance. - * -- * @param certChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format -- * @param keyPassword the password of the {@code keyFile}. -- * {@code null} if it's not password-protected. +- * @param certChainFile an X.509 certificate chain file in PEM format. +- * {@code null} to use the system default - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated -- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException { -- this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE, -- ApplicationProtocolConfig.DISABLED, 0, 0); +- public OpenSslClientContext(File certChainFile) throws SSLException { +- this(certChainFile, null); - } - - /** - * Creates a new instance. - * -- * @param certChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format -- * @param keyPassword the password of the {@code keyFile}. -- * {@code null} if it's not password-protected. -- * @param ciphers the cipher suites to enable, in the order of preference. -- * {@code null} to use the default cipher suites. -- * @param apn Provides a means to configure parameters related to application protocol negotiation. -- * @param sessionCacheSize the size of the cache used for storing SSL session objects. -- * {@code 0} to use the default value. -- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. -- * {@code 0} to use the default value. -- * @deprecated use {@link SslContextBuilder} -- */ -- @Deprecated -- public OpenSslServerContext( -- File certChainFile, File keyFile, String keyPassword, -- Iterable<String> ciphers, ApplicationProtocolConfig apn, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- this(certChainFile, keyFile, keyPassword, ciphers, IdentityCipherSuiteFilter.INSTANCE, -- apn, sessionCacheSize, sessionTimeout); -- } -- -- /** -- * Creates a new instance. -- * -- * @param certChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format -- * @param keyPassword the password of the {@code keyFile}. -- * {@code null} if it's not password-protected. -- * @param ciphers the cipher suites to enable, in the order of preference. -- * {@code null} to use the default cipher suites. -- * @param nextProtocols the application layer protocols to accept, in the order of preference. -- * {@code null} to disable TLS NPN/ALPN extension. -- * @param sessionCacheSize the size of the cache used for storing SSL session objects. -- * {@code 0} to use the default value. -- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. -- * {@code 0} to use the default value. +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from servers. +- * {@code null} to use the default. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated -- public OpenSslServerContext( -- File certChainFile, File keyFile, String keyPassword, -- Iterable<String> ciphers, Iterable<String> nextProtocols, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- this(certChainFile, keyFile, keyPassword, ciphers, -- toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout); +- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws SSLException { +- this(null, trustManagerFactory); - } - - /** - * Creates a new instance. - * -- * @param certChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format -- * @param keyPassword the password of the {@code keyFile}. -- * {@code null} if it's not password-protected. -- * @param ciphers the cipher suites to enable, in the order of preference. -- * {@code null} to use the default cipher suites. -- * @param config Application protocol config. -- * @param sessionCacheSize the size of the cache used for storing SSL session objects. -- * {@code 0} to use the default value. -- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. -- * {@code 0} to use the default value. +- * @param certChainFile an X.509 certificate chain file in PEM format. +- * {@code null} to use the system default +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from servers. +- * {@code null} to use the default. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated -- public OpenSslServerContext( -- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, -- Iterable<String> ciphers, ApplicationProtocolConfig config, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers, -- toNegotiator(config), sessionCacheSize, sessionTimeout); +- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException { +- this(certChainFile, trustManagerFactory, null, null, null, null, null, +- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0); - } - - /** - * Creates a new instance. - * - * @param certChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format -- * @param keyPassword the password of the {@code keyFile}. -- * {@code null} if it's not password-protected. +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from servers. +- * {@code null} to use the default.. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. -- * @param apn Application protocol negotiator. +- * @param apn Provides a means to configure parameters related to application protocol negotiation. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. @@ -1457,21 +1702,20 @@ index f57434b..0000000 - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated -- public OpenSslServerContext( -- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, -- Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, -- ciphers, null, apn, sessionCacheSize, sessionTimeout); +- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers, +- ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) +- throws SSLException { +- this(certChainFile, trustManagerFactory, null, null, null, null, ciphers, IdentityCipherSuiteFilter.INSTANCE, +- apn, sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * - * @param certChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format -- * @param keyPassword the password of the {@code keyFile}. -- * {@code null} if it's not password-protected. +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from servers. +- * {@code null} to use the default.. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param cipherFilter a filter to apply over the supplied list of ciphers @@ -1483,129 +1727,38 @@ index f57434b..0000000 - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated -- public OpenSslServerContext( -- File certChainFile, File keyFile, String keyPassword, -- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- this(null, null, certChainFile, keyFile, keyPassword, null, +- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(certChainFile, trustManagerFactory, null, null, null, null, - ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. -- * - * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. -- * This provides the certificate collection used for mutual authentication. - * {@code null} to use the system default - * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s -- * that verifies the certificates sent from clients. +- * that verifies the certificates sent from servers. - * {@code null} to use the default or the results of parsing -- * {@code trustCertCollectionFile}. -- * @param keyCertChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format -- * @param keyPassword the password of the {@code keyFile}. -- * {@code null} if it's not password-protected. -- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s -- * that is used to encrypt data being sent to clients. -- * {@code null} to use the default or the results of parsing -- * {@code keyCertChainFile} and {@code keyFile}. -- * @param ciphers the cipher suites to enable, in the order of preference. -- * {@code null} to use the default cipher suites. -- * @param cipherFilter a filter to apply over the supplied list of ciphers -- * Only required if {@code provider} is {@link SslProvider#JDK} -- * @param config Provides a means to configure parameters related to application protocol negotiation. -- * @param sessionCacheSize the size of the cache used for storing SSL session objects. -- * {@code 0} to use the default value. -- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. -- * {@code 0} to use the default value. -- * @deprecated use {@link SslContextBuilder} -- */ -- @Deprecated -- public OpenSslServerContext( -- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, -- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, -- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory, -- ciphers, cipherFilter, toNegotiator(config), sessionCacheSize, sessionTimeout); -- } -- -- /** -- * Creates a new instance. -- * -- * @param certChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format -- * @param keyPassword the password of the {@code keyFile}. -- * {@code null} if it's not password-protected. -- * @param ciphers the cipher suites to enable, in the order of preference. -- * {@code null} to use the default cipher suites. -- * @param cipherFilter a filter to apply over the supplied list of ciphers -- * @param config Application protocol config. -- * @param sessionCacheSize the size of the cache used for storing SSL session objects. -- * {@code 0} to use the default value. -- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. -- * {@code 0} to use the default value. -- * @deprecated use {@link SslContextBuilder} -- */ -- @Deprecated -- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword, -- TrustManagerFactory trustManagerFactory, Iterable<String> ciphers, -- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter, -- toNegotiator(config), sessionCacheSize, sessionTimeout); -- } -- -- /** -- * Creates a new instance. -- * -- * @param certChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format -- * @param keyPassword the password of the {@code keyFile}. -- * {@code null} if it's not password-protected. -- * @param ciphers the cipher suites to enable, in the order of preference. -- * {@code null} to use the default cipher suites. -- * @param cipherFilter a filter to apply over the supplied list of ciphers -- * @param apn Application protocol negotiator. -- * @param sessionCacheSize the size of the cache used for storing SSL session objects. -- * {@code 0} to use the default value. -- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. -- * {@code 0} to use the default value. -- * @deprecated use {@link SslContextBuilder}} -- */ -- @Deprecated -- public OpenSslServerContext( -- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, -- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter, -- apn, sessionCacheSize, sessionTimeout); -- } -- -- /** -- * Creates a new instance. -- * -- * -- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. -- * This provides the certificate collection used for mutual authentication. +- * {@code trustCertCollectionFile} +- * @param keyCertChainFile an X.509 certificate chain file in PEM format. +- * This provides the public key for mutual authentication. - * {@code null} to use the system default -- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s -- * that verifies the certificates sent from clients. -- * {@code null} to use the default or the results of parsing -- * {@code trustCertCollectionFile}. -- * @param keyCertChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format. +- * This provides the private key for mutual authentication. +- * {@code null} for no mutual authentication. - * @param keyPassword the password of the {@code keyFile}. - * {@code null} if it's not password-protected. -- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s -- * that is used to encrypt data being sent to clients. +- * Ignored if {@code keyFile} is {@code null}. +- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link javax.net.ssl.KeyManager}s +- * that is used to encrypt data being sent to servers. - * {@code null} to use the default or the results of parsing - * {@code keyCertChainFile} and {@code keyFile}. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param cipherFilter a filter to apply over the supplied list of ciphers -- * Only required if {@code provider} is {@link SslProvider#JDK} -- * @param apn Application Protocol Negotiator object +- * @param apn Application Protocol Negotiator object. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. @@ -1613,44 +1766,31 @@ index f57434b..0000000 - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated -- public OpenSslServerContext( -- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, -- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, -- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, -- long sessionCacheSize, long sessionTimeout) throws SSLException { +- public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, +- File keyCertChainFile, File keyFile, String keyPassword, +- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout) +- throws SSLException { - this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, - toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), -- keyPassword, keyManagerFactory, ciphers, cipherFilter, -- apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false, false); -- } -- -- OpenSslServerContext( -- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, -- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, -- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, -- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, -- boolean enableOcsp) throws SSLException { -- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, -- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, -- enableOcsp); +- keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, null, sessionCacheSize, +- sessionTimeout, false, KeyStore.getDefaultType()); - } - -- @SuppressWarnings("deprecation") -- private OpenSslServerContext( -- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, -- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, -- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, -- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, -- boolean enableOcsp) throws SSLException { -- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, -- clientAuth, protocols, startTls, enableOcsp); -- // Create a new SSL_CTX and configure it. +- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, +- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols, +- long sessionCacheSize, long sessionTimeout, boolean enableOcsp, String keyStore) +- throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, +- ClientAuth.NONE, protocols, false, enableOcsp); - boolean success = false; - try { -- ServerContext context = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, -- keyCertChain, key, keyPassword, keyManagerFactory); -- sessionContext = context.sessionContext; -- keyMaterialManager = context.keyMaterialManager; +- OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword); +- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, +- keyCertChain, key, keyPassword, keyManagerFactory, keyStore); - success = true; - } finally { - if (!success) { @@ -1660,21 +1800,16 @@ index f57434b..0000000 - } - - @Override -- public OpenSslServerSessionContext sessionContext() { +- public OpenSslSessionContext sessionContext() { - return sessionContext; - } -- -- @Override -- OpenSslKeyMaterialManager keyMaterialManager() { -- return keyMaterialManager; -- } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java deleted file mode 100644 -index 8c92deb..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java +index f18c0643fc..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java +++ /dev/null -@@ -1,124 +0,0 @@ +@@ -1,58 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -1692,119 +1827,53 @@ index 8c92deb..0000000 - */ -package io.netty.handler.ssl; - --import io.netty.internal.tcnative.SSL; --import io.netty.internal.tcnative.SSLContext; +-import io.netty.buffer.ByteBufAllocator; - --import java.util.concurrent.locks.Lock; +-import java.security.cert.Certificate; - +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; - -/** -- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side. +- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers +- * and manually release the native memory see {@link ReferenceCountedOpenSslContext}. - */ --public final class OpenSslServerSessionContext extends OpenSslSessionContext { -- OpenSslServerSessionContext(ReferenceCountedOpenSslContext context) { -- super(context); -- } -- -- @Override -- public void setSessionTimeout(int seconds) { -- if (seconds < 0) { -- throw new IllegalArgumentException(); -- } -- Lock writerLock = context.ctxLock.writeLock(); -- writerLock.lock(); -- try { -- SSLContext.setSessionCacheTimeout(context.ctx, seconds); -- } finally { -- writerLock.unlock(); -- } -- } -- -- @Override -- public int getSessionTimeout() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return (int) SSLContext.getSessionCacheTimeout(context.ctx); -- } finally { -- readerLock.unlock(); -- } -- } -- -- @Override -- public void setSessionCacheSize(int size) { -- if (size < 0) { -- throw new IllegalArgumentException(); -- } -- Lock writerLock = context.ctxLock.writeLock(); -- writerLock.lock(); -- try { -- SSLContext.setSessionCacheSize(context.ctx, size); -- } finally { -- writerLock.unlock(); -- } +-public abstract class OpenSslContext extends ReferenceCountedOpenSslContext { +- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg, +- long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain, +- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp) +- throws SSLException { +- super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain, +- clientAuth, protocols, startTls, enableOcsp, false); - } - -- @Override -- public int getSessionCacheSize() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return (int) SSLContext.getSessionCacheSize(context.ctx); -- } finally { -- readerLock.unlock(); -- } +- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, +- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, +- long sessionTimeout, int mode, Certificate[] keyCertChain, +- ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, protocols, +- startTls, enableOcsp, false); - } - - @Override -- public void setSessionCacheEnabled(boolean enabled) { -- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF; -- -- Lock writerLock = context.ctxLock.writeLock(); -- writerLock.lock(); -- try { -- SSLContext.setSessionCacheMode(context.ctx, mode); -- } finally { -- writerLock.unlock(); -- } +- final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) { +- return new OpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode); - } - - @Override -- public boolean isSessionCacheEnabled() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER; -- } finally { -- readerLock.unlock(); -- } -- } -- -- /** -- * Set the context within which session be reused (server side only) -- * See <a href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context.html"> -- * man SSL_CTX_set_session_id_context</a> -- * -- * @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name -- * of the application and/or the hostname and/or service name -- * @return {@code true} if success, {@code false} otherwise. -- */ -- public boolean setSessionIdContext(byte[] sidCtx) { -- Lock writerLock = context.ctxLock.writeLock(); -- writerLock.lock(); -- try { -- return SSLContext.setSessionIdContext(context.ctx, sidCtx); -- } finally { -- writerLock.unlock(); -- } +- @SuppressWarnings("FinalizeDeclaration") +- protected final void finalize() throws Throwable { +- super.finalize(); +- OpenSsl.releaseIfNeeded(this); - } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java deleted file mode 100644 -index 846a968..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java +index a700dabf39..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java +++ /dev/null -@@ -1,137 +0,0 @@ +@@ -1,41 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -1822,132 +1891,36 @@ index 846a968..0000000 - */ -package io.netty.handler.ssl; - --import io.netty.util.internal.ObjectUtil; --import io.netty.internal.tcnative.SSL; --import io.netty.internal.tcnative.SSLContext; --import io.netty.internal.tcnative.SessionTicketKey; +-import io.netty.buffer.ByteBufAllocator; - --import javax.net.ssl.SSLSession; --import javax.net.ssl.SSLSessionContext; --import java.util.Arrays; --import java.util.Enumeration; --import java.util.NoSuchElementException; --import java.util.concurrent.locks.Lock; +-import javax.net.ssl.SSLEngine; - -/** -- * OpenSSL specific {@link SSLSessionContext} implementation. +- * Implements a {@link SSLEngine} using +- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>. +- * <p> +- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers +- * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}. - */ --public abstract class OpenSslSessionContext implements SSLSessionContext { -- private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration(); -- -- private final OpenSslSessionStats stats; -- final ReferenceCountedOpenSslContext context; -- -- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent -- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a -- // segfault when the user calls any of the methods here that try to pass the pointer down to the native -- // level. -- OpenSslSessionContext(ReferenceCountedOpenSslContext context) { -- this.context = context; -- stats = new OpenSslSessionStats(context); -- } -- -- @Override -- public SSLSession getSession(byte[] bytes) { -- if (bytes == null) { -- throw new NullPointerException("bytes"); -- } -- return null; +-public final class OpenSslEngine extends ReferenceCountedOpenSslEngine { +- OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int peerPort, +- boolean jdkCompatibilityMode) { +- super(context, alloc, peerHost, peerPort, jdkCompatibilityMode, false); - } - - @Override -- public Enumeration<byte[]> getIds() { -- return EMPTY; -- } -- -- /** -- * Sets the SSL session ticket keys of this context. -- * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}. -- */ -- @Deprecated -- public void setTicketKeys(byte[] keys) { -- if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) { -- throw new IllegalArgumentException("keys.length % " + SessionTicketKey.TICKET_KEY_SIZE + " != 0"); -- } -- SessionTicketKey[] tickets = new SessionTicketKey[keys.length / SessionTicketKey.TICKET_KEY_SIZE]; -- for (int i = 0, a = 0; i < tickets.length; i++) { -- byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE); -- a += SessionTicketKey.NAME_SIZE; -- byte[] hmacKey = Arrays.copyOfRange(keys, a, SessionTicketKey.HMAC_KEY_SIZE); -- i += SessionTicketKey.HMAC_KEY_SIZE; -- byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE); -- a += SessionTicketKey.AES_KEY_SIZE; -- tickets[i] = new SessionTicketKey(name, hmacKey, aesKey); -- } -- Lock writerLock = context.ctxLock.writeLock(); -- writerLock.lock(); -- try { -- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET); -- SSLContext.setSessionTicketKeys(context.ctx, tickets); -- } finally { -- writerLock.unlock(); -- } -- } -- -- /** -- * Sets the SSL session ticket keys of this context. -- */ -- public void setTicketKeys(OpenSslSessionTicketKey... keys) { -- ObjectUtil.checkNotNull(keys, "keys"); -- SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length]; -- for (int i = 0; i < ticketKeys.length; i++) { -- ticketKeys[i] = keys[i].key; -- } -- Lock writerLock = context.ctxLock.writeLock(); -- writerLock.lock(); -- try { -- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET); -- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys); -- } finally { -- writerLock.unlock(); -- } -- } -- -- /** -- * Enable or disable caching of SSL sessions. -- */ -- public abstract void setSessionCacheEnabled(boolean enabled); -- -- /** -- * Return {@code true} if caching of SSL sessions is enabled, {@code false} otherwise. -- */ -- public abstract boolean isSessionCacheEnabled(); -- -- /** -- * Returns the stats of this context. -- */ -- public OpenSslSessionStats stats() { -- return stats; -- } -- -- private static final class EmptyEnumeration implements Enumeration<byte[]> { -- @Override -- public boolean hasMoreElements() { -- return false; -- } -- -- @Override -- public byte[] nextElement() { -- throw new NoSuchElementException(); -- } +- @SuppressWarnings("FinalizeDeclaration") +- protected void finalize() throws Throwable { +- super.finalize(); +- OpenSsl.releaseIfNeeded(this); - } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java deleted file mode 100644 -index f49b95f..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java +index 02131b4b26..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java +++ /dev/null -@@ -1,253 +0,0 @@ +@@ -1,35 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -1963,252 +1936,524 @@ index f49b95f..0000000 - * License for the specific language governing permissions and limitations - * under the License. - */ -- -package io.netty.handler.ssl; - --import io.netty.internal.tcnative.SSLContext; +-interface OpenSslEngineMap { - --import java.util.concurrent.locks.Lock; +- /** +- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and +- * return it. +- */ +- ReferenceCountedOpenSslEngine remove(long ssl); - --/** -- * Stats exposed by an OpenSSL session context. +- /** +- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}. +- */ +- void add(ReferenceCountedOpenSslEngine engine); +- +- /** +- * Get the {@link OpenSslEngine} for the given {@code ssl} address. +- */ +- ReferenceCountedOpenSslEngine get(long ssl); +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java +deleted file mode 100644 +index 7acbf70cfe..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java ++++ /dev/null +@@ -1,127 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project - * -- * @see <a href="https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_number.html">SSL_CTX_sess_number</a> +- * 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. - */ --public final class OpenSslSessionStats { +-package io.netty.handler.ssl; - -- private final ReferenceCountedOpenSslContext context; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.X509ExtendedKeyManager; +-import javax.net.ssl.X509KeyManager; +-import javax.security.auth.x500.X500Principal; +-import java.security.PrivateKey; +-import java.security.cert.X509Certificate; +-import java.util.HashMap; +-import java.util.HashSet; +-import java.util.Map; +-import java.util.Set; - -- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent -- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a -- // segfault when the user calls any of the methods here that try to pass the pointer down to the native -- // level. -- OpenSslSessionStats(ReferenceCountedOpenSslContext context) { -- this.context = context; +- +-/** +- * Manages key material for {@link OpenSslEngine}s and so set the right {@link PrivateKey}s and +- * {@link X509Certificate}s. +- */ +-final class OpenSslKeyMaterialManager { +- +- // Code in this class is inspired by code of conscrypts: +- // - https://android.googlesource.com/platform/external/ +- // conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java +- // - https://android.googlesource.com/platform/external/ +- // conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java +- // +- static final String KEY_TYPE_RSA = "RSA"; +- static final String KEY_TYPE_DH_RSA = "DH_RSA"; +- static final String KEY_TYPE_EC = "EC"; +- static final String KEY_TYPE_EC_EC = "EC_EC"; +- static final String KEY_TYPE_EC_RSA = "EC_RSA"; +- +- // key type mappings for types. +- private static final Map<String, String> KEY_TYPES = new HashMap<String, String>(); +- static { +- KEY_TYPES.put("RSA", KEY_TYPE_RSA); +- KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA); +- KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA); +- KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC); +- KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA); +- KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC); +- KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA); - } - -- /** -- * Returns the current number of sessions in the internal session cache. -- */ -- public long number() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionNumber(context.ctx); -- } finally { -- readerLock.unlock(); -- } +- private final OpenSslKeyMaterialProvider provider; +- +- OpenSslKeyMaterialManager(OpenSslKeyMaterialProvider provider) { +- this.provider = provider; - } - -- /** -- * Returns the number of started SSL/TLS handshakes in client mode. -- */ -- public long connect() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionConnect(context.ctx); -- } finally { -- readerLock.unlock(); +- void setKeyMaterialServerSide(ReferenceCountedOpenSslEngine engine) throws SSLException { +- String[] authMethods = engine.authMethods(); +- if (authMethods.length == 0) { +- return; +- } +- Set<String> aliases = new HashSet<String>(authMethods.length); +- for (String authMethod : authMethods) { +- String type = KEY_TYPES.get(authMethod); +- if (type != null) { +- String alias = chooseServerAlias(engine, type); +- if (alias != null && aliases.add(alias)) { +- if (!setKeyMaterial(engine, alias)) { +- return; +- } +- } +- } - } - } - -- /** -- * Returns the number of successfully established SSL/TLS sessions in client mode. -- */ -- public long connectGood() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionConnectGood(context.ctx); -- } finally { -- readerLock.unlock(); +- void setKeyMaterialClientSide(ReferenceCountedOpenSslEngine engine, String[] keyTypes, +- X500Principal[] issuer) throws SSLException { +- String alias = chooseClientAlias(engine, keyTypes, issuer); +- // Only try to set the keymaterial if we have a match. This is also consistent with what OpenJDK does: +- // http://hg.openjdk.java.net/jdk/jdk11/file/76072a077ee1/ +- // src/java.base/share/classes/sun/security/ssl/CertificateRequest.java#l362 +- if (alias != null) { +- setKeyMaterial(engine, alias); - } - } - -- /** -- * Returns the number of start renegotiations in client mode. -- */ -- public long connectRenegotiate() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); +- private boolean setKeyMaterial(ReferenceCountedOpenSslEngine engine, String alias) throws SSLException { +- OpenSslKeyMaterial keyMaterial = null; - try { -- return SSLContext.sessionConnectRenegotiate(context.ctx); +- keyMaterial = provider.chooseKeyMaterial(engine.alloc, alias); +- return keyMaterial == null || engine.setKeyMaterial(keyMaterial); +- } catch (SSLException e) { +- throw e; +- } catch (Exception e) { +- throw new SSLException(e); - } finally { -- readerLock.unlock(); +- if (keyMaterial != null) { +- keyMaterial.release(); +- } +- } +- } +- private String chooseClientAlias(ReferenceCountedOpenSslEngine engine, +- String[] keyTypes, X500Principal[] issuer) { +- X509KeyManager manager = provider.keyManager(); +- if (manager instanceof X509ExtendedKeyManager) { +- return ((X509ExtendedKeyManager) manager).chooseEngineClientAlias(keyTypes, issuer, engine); - } +- return manager.chooseClientAlias(keyTypes, issuer, null); - } - -- /** -- * Returns the number of started SSL/TLS handshakes in server mode. -- */ -- public long accept() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionAccept(context.ctx); -- } finally { -- readerLock.unlock(); +- private String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) { +- X509KeyManager manager = provider.keyManager(); +- if (manager instanceof X509ExtendedKeyManager) { +- return ((X509ExtendedKeyManager) manager).chooseEngineServerAlias(type, null, engine); - } +- return manager.chooseServerAlias(type, null, null); - } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java +deleted file mode 100644 +index f931fcfdbb..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java ++++ /dev/null +@@ -1,154 +0,0 @@ +-/* +- * Copyright 2018 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.buffer.ByteBufAllocator; +-import io.netty.buffer.UnpooledByteBufAllocator; +-import io.netty.internal.tcnative.SSL; +- +-import javax.net.ssl.SSLException; +-import javax.net.ssl.X509KeyManager; +-import java.security.PrivateKey; +-import java.security.cert.X509Certificate; +- +-import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO; +- +-/** +- * Provides {@link OpenSslKeyMaterial} for a given alias. +- */ +-class OpenSslKeyMaterialProvider { +- +- private final X509KeyManager keyManager; +- private final String password; +- +- OpenSslKeyMaterialProvider(X509KeyManager keyManager, String password) { +- this.keyManager = keyManager; +- this.password = password; +- } +- +- static void validateKeyMaterialSupported(X509Certificate[] keyCertChain, PrivateKey key, String keyPassword) +- throws SSLException { +- validateSupported(keyCertChain); +- validateSupported(key, keyPassword); +- } +- +- private static void validateSupported(PrivateKey key, String password) throws SSLException { +- if (key == null) { +- return; +- } +- +- long pkeyBio = 0; +- long pkey = 0; - -- /** -- * Returns the number of successfully established SSL/TLS sessions in server mode. -- */ -- public long acceptGood() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); - try { -- return SSLContext.sessionAcceptGood(context.ctx); +- pkeyBio = toBIO(UnpooledByteBufAllocator.DEFAULT, key); +- pkey = SSL.parsePrivateKey(pkeyBio, password); +- } catch (Exception e) { +- throw new SSLException("PrivateKey type not supported " + key.getFormat(), e); - } finally { -- readerLock.unlock(); +- SSL.freeBIO(pkeyBio); +- if (pkey != 0) { +- SSL.freePrivateKey(pkey); +- } - } - } - -- /** -- * Returns the number of start renegotiations in server mode. -- */ -- public long acceptRenegotiate() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); +- private static void validateSupported(X509Certificate[] certificates) throws SSLException { +- if (certificates == null || certificates.length == 0) { +- return; +- } +- +- long chainBio = 0; +- long chain = 0; +- PemEncoded encoded = null; - try { -- return SSLContext.sessionAcceptRenegotiate(context.ctx); +- encoded = PemX509Certificate.toPEM(UnpooledByteBufAllocator.DEFAULT, true, certificates); +- chainBio = toBIO(UnpooledByteBufAllocator.DEFAULT, encoded.retain()); +- chain = SSL.parseX509Chain(chainBio); +- } catch (Exception e) { +- throw new SSLException("Certificate type not supported", e); - } finally { -- readerLock.unlock(); +- SSL.freeBIO(chainBio); +- if (chain != 0) { +- SSL.freeX509Chain(chain); +- } +- if (encoded != null) { +- encoded.release(); +- } - } - } - - /** -- * Returns the number of successfully reused sessions. In client mode, a session set with {@code SSL_set_session} -- * successfully reused is counted as a hit. In server mode, a session successfully retrieved from internal or -- * external cache is counted as a hit. +- * Returns the underlying {@link X509KeyManager} that is used. - */ -- public long hits() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionHits(context.ctx); -- } finally { -- readerLock.unlock(); -- } +- X509KeyManager keyManager() { +- return keyManager; - } - - /** -- * Returns the number of successfully retrieved sessions from the external session cache in server mode. +- * Returns the {@link OpenSslKeyMaterial} or {@code null} (if none) that should be used during the handshake by +- * OpenSSL. - */ -- public long cbHits() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); +- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception { +- X509Certificate[] certificates = keyManager.getCertificateChain(alias); +- if (certificates == null || certificates.length == 0) { +- return null; +- } +- +- PrivateKey key = keyManager.getPrivateKey(alias); +- PemEncoded encoded = PemX509Certificate.toPEM(allocator, true, certificates); +- long chainBio = 0; +- long pkeyBio = 0; +- long chain = 0; +- long pkey = 0; - try { -- return SSLContext.sessionCbHits(context.ctx); +- chainBio = toBIO(allocator, encoded.retain()); +- chain = SSL.parseX509Chain(chainBio); +- +- OpenSslKeyMaterial keyMaterial; +- if (key instanceof OpenSslPrivateKey) { +- keyMaterial = ((OpenSslPrivateKey) key).newKeyMaterial(chain, certificates); +- } else { +- pkeyBio = toBIO(allocator, key); +- pkey = key == null ? 0 : SSL.parsePrivateKey(pkeyBio, password); +- keyMaterial = new DefaultOpenSslKeyMaterial(chain, pkey, certificates); +- } +- +- // See the chain and pkey to 0 so we will not release it as the ownership was +- // transferred to OpenSslKeyMaterial. +- chain = 0; +- pkey = 0; +- return keyMaterial; - } finally { -- readerLock.unlock(); +- SSL.freeBIO(chainBio); +- SSL.freeBIO(pkeyBio); +- if (chain != 0) { +- SSL.freeX509Chain(chain); +- } +- if (pkey != 0) { +- SSL.freePrivateKey(pkey); +- } +- encoded.release(); - } - } - - /** -- * Returns the number of sessions proposed by clients that were not found in the internal session cache -- * in server mode. +- * Will be invoked once the provider should be destroyed. - */ -- public long misses() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionMisses(context.ctx); -- } finally { -- readerLock.unlock(); -- } +- void destroy() { +- // NOOP. - } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java +deleted file mode 100644 +index c2e4f108b7..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java ++++ /dev/null +@@ -1,191 +0,0 @@ +-/* +- * Copyright 2018 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; - -- /** -- * Returns the number of sessions proposed by clients and either found in the internal or external session cache -- * in server mode, but that were invalid due to timeout. These sessions are not included in the {@link #hits()} -- * count. -- */ -- public long timeouts() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionTimeouts(context.ctx); -- } finally { -- readerLock.unlock(); -- } +-import io.netty.internal.tcnative.SSL; +-import io.netty.util.AbstractReferenceCounted; +-import io.netty.util.IllegalReferenceCountException; +-import io.netty.util.internal.EmptyArrays; +- +-import javax.security.auth.Destroyable; +-import java.security.PrivateKey; +-import java.security.cert.X509Certificate; +- +-final class OpenSslPrivateKey extends AbstractReferenceCounted implements PrivateKey { +- +- private long privateKeyAddress; +- +- OpenSslPrivateKey(long privateKeyAddress) { +- this.privateKeyAddress = privateKeyAddress; - } - -- /** -- * Returns the number of sessions that were removed because the maximum session cache size was exceeded. -- */ -- public long cacheFull() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionCacheFull(context.ctx); -- } finally { -- readerLock.unlock(); -- } +- @Override +- public String getAlgorithm() { +- return "unknown"; - } - -- /** -- * Returns the number of times a client presented a ticket that did not match any key in the list. -- */ -- public long ticketKeyFail() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionTicketKeyFail(context.ctx); -- } finally { -- readerLock.unlock(); +- @Override +- public String getFormat() { +- // As we do not support encoding we should return null as stated in the javadocs of PrivateKey. +- return null; +- } +- +- @Override +- public byte[] getEncoded() { +- return null; +- } +- +- private long privateKeyAddress() { +- if (refCnt() <= 0) { +- throw new IllegalReferenceCountException(); - } +- return privateKeyAddress; +- } +- +- @Override +- protected void deallocate() { +- SSL.freePrivateKey(privateKeyAddress); +- privateKeyAddress = 0; +- } +- +- @Override +- public OpenSslPrivateKey retain() { +- super.retain(); +- return this; +- } +- +- @Override +- public OpenSslPrivateKey retain(int increment) { +- super.retain(increment); +- return this; +- } +- +- @Override +- public OpenSslPrivateKey touch() { +- super.touch(); +- return this; +- } +- +- @Override +- public OpenSslPrivateKey touch(Object hint) { +- return this; - } - - /** -- * Returns the number of times a client did not present a ticket and we issued a new one +- * NOTE: This is a JDK8 interface/method. Due to backwards compatibility +- * reasons it's not possible to slap the {@code @Override} annotation onto +- * this method. +- * +- * @see Destroyable#destroy() - */ -- public long ticketKeyNew() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionTicketKeyNew(context.ctx); -- } finally { -- readerLock.unlock(); -- } +- @Override +- public void destroy() { +- release(refCnt()); - } - - /** -- * Returns the number of times a client presented a ticket derived from an older key, -- * and we upgraded to the primary key. +- * NOTE: This is a JDK8 interface/method. Due to backwards compatibility +- * reasons it's not possible to slap the {@code @Override} annotation onto +- * this method. +- * +- * @see Destroyable#isDestroyed() - */ -- public long ticketKeyRenew() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionTicketKeyRenew(context.ctx); -- } finally { -- readerLock.unlock(); -- } +- @Override +- public boolean isDestroyed() { +- return refCnt() == 0; - } - - /** -- * Returns the number of times a client presented a ticket derived from the primary key. +- * Create a new {@link OpenSslKeyMaterial} which uses the private key that is held by {@link OpenSslPrivateKey}. +- * +- * When the material is created we increment the reference count of the enclosing {@link OpenSslPrivateKey} and +- * decrement it again when the reference count of the {@link OpenSslKeyMaterial} reaches {@code 0}. - */ -- public long ticketKeyResume() { -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- return SSLContext.sessionTicketKeyResume(context.ctx); -- } finally { -- readerLock.unlock(); +- OpenSslKeyMaterial newKeyMaterial(long certificateChain, X509Certificate[] chain) { +- return new OpenSslPrivateKeyMaterial(certificateChain, chain); +- } +- +- // Package-private for unit-test only +- final class OpenSslPrivateKeyMaterial extends AbstractReferenceCounted implements OpenSslKeyMaterial { +- +- // Package-private for unit-test only +- long certificateChain; +- private final X509Certificate[] x509CertificateChain; +- +- OpenSslPrivateKeyMaterial(long certificateChain, X509Certificate[] x509CertificateChain) { +- this.certificateChain = certificateChain; +- this.x509CertificateChain = x509CertificateChain == null ? +- EmptyArrays.EMPTY_X509_CERTIFICATES : x509CertificateChain; +- OpenSslPrivateKey.this.retain(); +- } +- +- @Override +- public X509Certificate[] certificateChain() { +- return x509CertificateChain.clone(); +- } +- +- @Override +- public long certificateChainAddress() { +- if (refCnt() <= 0) { +- throw new IllegalReferenceCountException(); +- } +- return certificateChain; +- } +- +- @Override +- public long privateKeyAddress() { +- if (refCnt() <= 0) { +- throw new IllegalReferenceCountException(); +- } +- return OpenSslPrivateKey.this.privateKeyAddress(); +- } +- +- @Override +- public OpenSslKeyMaterial touch(Object hint) { +- OpenSslPrivateKey.this.touch(hint); +- return this; +- } +- +- @Override +- public OpenSslKeyMaterial retain() { +- super.retain(); +- return this; +- } +- +- @Override +- public OpenSslKeyMaterial retain(int increment) { +- super.retain(increment); +- return this; +- } +- +- @Override +- public OpenSslKeyMaterial touch() { +- OpenSslPrivateKey.this.touch(); +- return this; +- } +- +- @Override +- protected void deallocate() { +- releaseChain(); +- OpenSslPrivateKey.this.release(); +- } +- +- private void releaseChain() { +- SSL.freeX509Chain(certificateChain); +- certificateChain = 0; - } - } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java deleted file mode 100644 -index 79f71a6..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java +index d9fc877269..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java +++ /dev/null -@@ -1,78 +0,0 @@ +@@ -1,62 +0,0 @@ -/* -- * Copyright 2015 The Netty Project +- * Copyright 2019 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 @@ -2224,75 +2469,59 @@ index 79f71a6..0000000 - */ -package io.netty.handler.ssl; - --import io.netty.internal.tcnative.SessionTicketKey; +-import io.netty.internal.tcnative.SSLPrivateKeyMethod; +-import io.netty.util.internal.UnstableApi; +- +-import javax.net.ssl.SSLEngine; - -/** -- * Session Ticket Key +- * Allow to customize private key signing / decrypting (when using RSA). Only supported when using BoringSSL atm. - */ --public final class OpenSslSessionTicketKey { -- -- /** -- * Size of session ticket key name -- */ -- public static final int NAME_SIZE = SessionTicketKey.NAME_SIZE; -- /** -- * Size of session ticket key HMAC key -- */ -- public static final int HMAC_KEY_SIZE = SessionTicketKey.HMAC_KEY_SIZE; -- /** -- * Size of session ticket key AES key -- */ -- public static final int AES_KEY_SIZE = SessionTicketKey.AES_KEY_SIZE; -- /** -- * Size of session ticker key -- */ -- public static final int TICKET_KEY_SIZE = SessionTicketKey.TICKET_KEY_SIZE; -- -- final SessionTicketKey key; +-@UnstableApi +-public interface OpenSslPrivateKeyMethod { +- int SSL_SIGN_RSA_PKCS1_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA1; +- int SSL_SIGN_RSA_PKCS1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA256; +- int SSL_SIGN_RSA_PKCS1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA384; +- int SSL_SIGN_RSA_PKCS1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA512; +- int SSL_SIGN_ECDSA_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SHA1; +- int SSL_SIGN_ECDSA_SECP256R1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP256R1_SHA256; +- int SSL_SIGN_ECDSA_SECP384R1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP384R1_SHA384; +- int SSL_SIGN_ECDSA_SECP521R1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP521R1_SHA512; +- int SSL_SIGN_RSA_PSS_RSAE_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA256; +- int SSL_SIGN_RSA_PSS_RSAE_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA384; +- int SSL_SIGN_RSA_PSS_RSAE_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA512; +- int SSL_SIGN_ED25519 = SSLPrivateKeyMethod.SSL_SIGN_ED25519; +- int SSL_SIGN_RSA_PKCS1_MD5_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_MD5_SHA1; - - /** -- * Construct a OpenSslSessionTicketKey. +- * Signs the input with the given key and returns the signed bytes. - * -- * @param name the name of the session ticket key -- * @param hmacKey the HMAC key of the session ticket key -- * @param aesKey the AES key of the session ticket key +- * @param engine the {@link SSLEngine} +- * @param signatureAlgorithm the algorithm to use for signing +- * @param input the digest itself +- * @return the signed data (must not be {@code null}) +- * @throws Exception thrown if an error is encountered during the signing - */ -- public OpenSslSessionTicketKey(byte[] name, byte[] hmacKey, byte[] aesKey) { -- key = new SessionTicketKey(name.clone(), hmacKey.clone(), aesKey.clone()); -- } -- -- /** -- * Get name. -- * @return the name of the session ticket key -- */ -- public byte[] name() { -- return key.getName().clone(); -- } -- -- /** -- * Get HMAC key. -- * @return the HMAC key of the session ticket key -- */ -- public byte[] hmacKey() { -- return key.getHmacKey().clone(); -- } +- byte[] sign(SSLEngine engine, int signatureAlgorithm, byte[] input) throws Exception; - - /** -- * Get AES Key. -- * @return the AES key of the session ticket key +- * Decrypts the input with the given key and returns the decrypted bytes. +- * +- * @param engine the {@link SSLEngine} +- * @param input the input which should be decrypted +- * @return the decrypted data (must not be {@code null}) +- * @throws Exception thrown if an error is encountered during the decrypting - */ -- public byte[] aesKey() { -- return key.getAesKey().clone(); -- } +- byte[] decrypt(SSLEngine engine, byte[] input) throws Exception; -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java deleted file mode 100644 -index b213573..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java +index da342de0f2..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java +++ /dev/null -@@ -1,298 +0,0 @@ +@@ -1,367 +0,0 @@ -/* -- * Copyright 2016 The Netty Project +- * Copyright 2014 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 @@ -2308,295 +2537,364 @@ index b213573..0000000 - */ -package io.netty.handler.ssl; - --import io.netty.util.internal.logging.InternalLogger; --import io.netty.util.internal.logging.InternalLoggerFactory; --import io.netty.internal.tcnative.CertificateRequestedCallback; -import io.netty.internal.tcnative.SSL; --import io.netty.internal.tcnative.SSLContext; - +-import java.io.File; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; --import java.util.HashSet; --import java.util.Set; - +-import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLException; --import javax.net.ssl.SSLHandshakeException; +-import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; --import javax.net.ssl.X509ExtendedKeyManager; --import javax.net.ssl.X509ExtendedTrustManager; --import javax.net.ssl.X509KeyManager; --import javax.net.ssl.X509TrustManager; --import javax.security.auth.x500.X500Principal; +- +-import static io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.newSessionContext; - -/** -- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. -- * <p>Instances of this class must be {@link #release() released} or else native memory will leak! -- * -- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine} -- * which depends upon the instance of this class is released. Otherwise if any method of -- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. +- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers +- * and manually release the native memory see {@link ReferenceCountedOpenSslServerContext}. - */ --public final class ReferenceCountedOpenSslClientContext extends ReferenceCountedOpenSslContext { -- private static final InternalLogger logger = -- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class); -- private final OpenSslSessionContext sessionContext; +-public final class OpenSslServerContext extends OpenSslContext { +- private final OpenSslServerSessionContext sessionContext; - -- ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, -- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, -- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, -- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, -- String[] protocols, long sessionCacheSize, long sessionTimeout, -- boolean enableOcsp) throws SSLException { -- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, -- ClientAuth.NONE, protocols, false, enableOcsp, true); -- boolean success = false; -- try { -- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, -- keyCertChain, key, keyPassword, keyManagerFactory); -- success = true; -- } finally { -- if (!success) { -- release(); -- } -- } +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException { +- this(certChainFile, keyFile, null); - } - -- @Override -- OpenSslKeyMaterialManager keyMaterialManager() { -- return null; +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException { +- this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE, +- ApplicationProtocolConfig.DISABLED, 0, 0); - } - -- @Override -- public OpenSslSessionContext sessionContext() { -- return sessionContext; +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param apn Provides a means to configure parameters related to application protocol negotiation. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, +- Iterable<String> ciphers, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(certChainFile, keyFile, keyPassword, ciphers, IdentityCipherSuiteFilter.INSTANCE, +- apn, sessionCacheSize, sessionTimeout); - } - -- static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx, -- OpenSslEngineMap engineMap, -- X509Certificate[] trustCertCollection, -- TrustManagerFactory trustManagerFactory, -- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, -- KeyManagerFactory keyManagerFactory) throws SSLException { -- if (key == null && keyCertChain != null || key != null && keyCertChain == null) { -- throw new IllegalArgumentException( -- "Either both keyCertChain and key needs to be null or none of them"); -- } -- try { -- if (!OpenSsl.useKeyManagerFactory()) { -- if (keyManagerFactory != null) { -- throw new IllegalArgumentException( -- "KeyManagerFactory not supported"); -- } -- if (keyCertChain != null/* && key != null*/) { -- setKeyMaterial(ctx, keyCertChain, key, keyPassword); -- } -- } else { -- // javadocs state that keyManagerFactory has precedent over keyCertChain -- if (keyManagerFactory == null && keyCertChain != null) { -- keyManagerFactory = buildKeyManagerFactory( -- keyCertChain, key, keyPassword, keyManagerFactory); -- } -- -- if (keyManagerFactory != null) { -- X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers()); -- OpenSslKeyMaterialManager materialManager = useExtendedKeyManager(keyManager) ? -- new OpenSslExtendedKeyMaterialManager( -- (X509ExtendedKeyManager) keyManager, keyPassword) : -- new OpenSslKeyMaterialManager(keyManager, keyPassword); -- SSLContext.setCertRequestedCallback(ctx, new OpenSslCertificateRequestedCallback( -- engineMap, materialManager)); -- } -- } -- } catch (Exception e) { -- throw new SSLException("failed to set certificate and key", e); -- } -- -- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); -- -- try { -- if (trustCertCollection != null) { -- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory); -- } else if (trustManagerFactory == null) { -- trustManagerFactory = TrustManagerFactory.getInstance( -- TrustManagerFactory.getDefaultAlgorithm()); -- trustManagerFactory.init((KeyStore) null); -- } -- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); -- -- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as -- // otherwise the context can never be collected. This is because the JNI code holds -- // a global reference to the callbacks. -- // -- // See https://github.com/netty/netty/issues/5372 -- -- // Use this to prevent an error when running on java < 7 -- if (useExtendedTrustManager(manager)) { -- SSLContext.setCertVerifyCallback(ctx, -- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager)); -- } else { -- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager)); -- } -- } catch (Exception e) { -- throw new SSLException("unable to setup trustmanager", e); -- } -- return new OpenSslClientSessionContext(thiz); +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param nextProtocols the application layer protocols to accept, in the order of preference. +- * {@code null} to disable TLS NPN/ALPN extension. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, +- Iterable<String> ciphers, Iterable<String> nextProtocols, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(certChainFile, keyFile, keyPassword, ciphers, +- toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout); - } - -- // No cache is currently supported for client side mode. -- static final class OpenSslClientSessionContext extends OpenSslSessionContext { -- OpenSslClientSessionContext(ReferenceCountedOpenSslContext context) { -- super(context); -- } -- -- @Override -- public void setSessionTimeout(int seconds) { -- if (seconds < 0) { -- throw new IllegalArgumentException(); -- } -- } -- -- @Override -- public int getSessionTimeout() { -- return 0; -- } -- -- @Override -- public void setSessionCacheSize(int size) { -- if (size < 0) { -- throw new IllegalArgumentException(); -- } -- } -- -- @Override -- public int getSessionCacheSize() { -- return 0; -- } -- -- @Override -- public void setSessionCacheEnabled(boolean enabled) { -- // ignored -- } -- -- @Override -- public boolean isSessionCacheEnabled() { -- return false; -- } +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param config Application protocol config. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, +- Iterable<String> ciphers, ApplicationProtocolConfig config, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers, +- toNegotiator(config), sessionCacheSize, sessionTimeout); - } - -- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier { -- private final X509TrustManager manager; -- -- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) { -- super(engineMap); -- this.manager = manager; -- } +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param apn Application protocol negotiator. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, +- Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, +- ciphers, null, apn, sessionCacheSize, sessionTimeout); +- } - -- @Override -- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) -- throws Exception { -- manager.checkServerTrusted(peerCerts, auth); -- } +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * @param apn Provides a means to configure parameters related to application protocol negotiation. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, +- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(null, null, certChainFile, keyFile, keyPassword, null, +- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); - } - -- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier { -- private final X509ExtendedTrustManager manager; +- /** +- * Creates a new instance. +- * +- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. +- * This provides the certificate collection used for mutual authentication. +- * {@code null} to use the system default +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from clients. +- * {@code null} to use the default or the results of parsing +- * {@code trustCertCollectionFile}. +- * @param keyCertChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s +- * that is used to encrypt data being sent to clients. +- * {@code null} to use the default or the results of parsing +- * {@code keyCertChainFile} and {@code keyFile}. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * Only required if {@code provider} is {@link SslProvider#JDK} +- * @param config Provides a means to configure parameters related to application protocol negotiation. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, +- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory, +- ciphers, cipherFilter, toNegotiator(config), sessionCacheSize, sessionTimeout); +- } - -- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) { -- super(engineMap); -- this.manager = manager; -- } +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * @param config Application protocol config. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword, +- TrustManagerFactory trustManagerFactory, Iterable<String> ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter, +- toNegotiator(config), sessionCacheSize, sessionTimeout); +- } - -- @Override -- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) -- throws Exception { -- manager.checkServerTrusted(peerCerts, auth, engine); -- } +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * @param apn Application protocol negotiator. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder}} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, +- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter, +- apn, sessionCacheSize, sessionTimeout); - } - -- private static final class OpenSslCertificateRequestedCallback implements CertificateRequestedCallback { -- private final OpenSslEngineMap engineMap; -- private final OpenSslKeyMaterialManager keyManagerHolder; +- /** +- * Creates a new instance. +- * +- * +- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. +- * This provides the certificate collection used for mutual authentication. +- * {@code null} to use the system default +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from clients. +- * {@code null} to use the default or the results of parsing +- * {@code trustCertCollectionFile}. +- * @param keyCertChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s +- * that is used to encrypt data being sent to clients. +- * {@code null} to use the default or the results of parsing +- * {@code keyCertChainFile} and {@code keyFile}. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * Only required if {@code provider} is {@link SslProvider#JDK} +- * @param apn Application Protocol Negotiator object +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, +- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, +- toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), +- keyPassword, keyManagerFactory, ciphers, cipherFilter, +- apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false, false, KeyStore.getDefaultType()); +- } - -- OpenSslCertificateRequestedCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) { -- this.engineMap = engineMap; -- this.keyManagerHolder = keyManagerHolder; -- } +- OpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp, String keyStore) throws SSLException { +- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, +- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, +- enableOcsp, keyStore); +- } - -- @Override -- public KeyMaterial requested(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) { -- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); -- try { -- final Set<String> keyTypesSet = supportedClientKeyTypes(keyTypeBytes); -- final String[] keyTypes = keyTypesSet.toArray(new String[keyTypesSet.size()]); -- final X500Principal[] issuers; -- if (asn1DerEncodedPrincipals == null) { -- issuers = null; -- } else { -- issuers = new X500Principal[asn1DerEncodedPrincipals.length]; -- for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) { -- issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]); -- } -- } -- return keyManagerHolder.keyMaterial(engine, keyTypes, issuers); -- } catch (Throwable cause) { -- logger.debug("request of key failed", cause); -- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem"); -- e.initCause(cause); -- engine.handshakeException = e; -- return null; -- } -- } +- @SuppressWarnings("deprecation") +- private OpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp, String keyStore) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, +- clientAuth, protocols, startTls, enableOcsp); - -- /** -- * Gets the supported key types for client certificates. -- * -- * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server. -- * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml. -- * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and -- * {@code X509ExtendedKeyManager.chooseEngineClientAlias}. -- */ -- private static Set<String> supportedClientKeyTypes(byte[] clientCertificateTypes) { -- Set<String> result = new HashSet<String>(clientCertificateTypes.length); -- for (byte keyTypeCode : clientCertificateTypes) { -- String keyType = clientKeyType(keyTypeCode); -- if (keyType == null) { -- // Unsupported client key type -- ignore -- continue; -- } -- result.add(keyType); +- // Create a new SSL_CTX and configure it. +- boolean success = false; +- try { +- OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword); +- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, +- keyCertChain, key, keyPassword, keyManagerFactory, keyStore); +- success = true; +- } finally { +- if (!success) { +- release(); - } -- return result; - } +- } - -- private static String clientKeyType(byte clientCertificateType) { -- // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml -- switch (clientCertificateType) { -- case CertificateRequestedCallback.TLS_CT_RSA_SIGN: -- return OpenSslKeyMaterialManager.KEY_TYPE_RSA; // RFC rsa_sign -- case CertificateRequestedCallback.TLS_CT_RSA_FIXED_DH: -- return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh -- case CertificateRequestedCallback.TLS_CT_ECDSA_SIGN: -- return OpenSslKeyMaterialManager.KEY_TYPE_EC; // RFC ecdsa_sign -- case CertificateRequestedCallback.TLS_CT_RSA_FIXED_ECDH: -- return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh -- case CertificateRequestedCallback.TLS_CT_ECDSA_FIXED_ECDH: -- return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh -- default: -- return null; -- } -- } +- @Override +- public OpenSslServerSessionContext sessionContext() { +- return sessionContext; - } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java deleted file mode 100644 -index ee049ab..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java +index 691ee0b661..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java +++ /dev/null -@@ -1,867 +0,0 @@ +@@ -1,124 +0,0 @@ -/* -- * Copyright 2016 The Netty Project +- * Copyright 2014 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 @@ -2612,864 +2910,874 @@ index ee049ab..0000000 - */ -package io.netty.handler.ssl; - --import io.netty.buffer.ByteBuf; --import io.netty.buffer.ByteBufAllocator; --import io.netty.internal.tcnative.CertificateVerifier; -import io.netty.internal.tcnative.SSL; -import io.netty.internal.tcnative.SSLContext; --import io.netty.util.AbstractReferenceCounted; --import io.netty.util.ReferenceCounted; --import io.netty.util.ResourceLeakDetector; --import io.netty.util.ResourceLeakDetectorFactory; --import io.netty.util.ResourceLeakTracker; --import io.netty.util.internal.PlatformDependent; --import io.netty.util.internal.StringUtil; --import io.netty.util.internal.SystemPropertyUtil; --import io.netty.util.internal.logging.InternalLogger; --import io.netty.util.internal.logging.InternalLoggerFactory; -- --import java.security.AccessController; --import java.security.PrivateKey; --import java.security.PrivilegedAction; --import java.security.cert.CertPathValidatorException; --import java.security.cert.Certificate; --import java.security.cert.CertificateExpiredException; --import java.security.cert.CertificateNotYetValidException; --import java.security.cert.CertificateRevokedException; --import java.security.cert.X509Certificate; --import java.util.ArrayList; --import java.util.Arrays; --import java.util.Collections; --import java.util.List; --import java.util.Map; - -import java.util.concurrent.locks.Lock; --import java.util.concurrent.locks.ReadWriteLock; --import java.util.concurrent.locks.ReentrantReadWriteLock; --import javax.net.ssl.KeyManager; --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLException; --import javax.net.ssl.SSLHandshakeException; --import javax.net.ssl.TrustManager; --import javax.net.ssl.X509ExtendedKeyManager; --import javax.net.ssl.X509ExtendedTrustManager; --import javax.net.ssl.X509KeyManager; --import javax.net.ssl.X509TrustManager; - --import static io.netty.util.internal.ObjectUtil.checkNotNull; --import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero; - -/** -- * An implementation of {@link SslContext} which works with libraries that support the -- * <a href="https://www.openssl.org/">OpenSsl</a> C library API. -- * <p>Instances of this class must be {@link #release() released} or else native memory will leak! -- * -- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine} -- * which depends upon the instance of this class is released. Otherwise if any method of -- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. +- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side. - */ --public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted { -- private static final InternalLogger logger = -- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class); -- /** -- * To make it easier for users to replace JDK implementation with OpenSsl version we also use -- * {@code jdk.tls.rejectClientInitiatedRenegotiation} to allow disabling client initiated renegotiation. -- * Java8+ uses this system property as well. -- * <p> -- * See also <a href="http://blog.ivanristic.com/2014/03/ssl-tls-improvements-in-java-8.html"> -- * Significant SSL/TLS improvements in Java 8</a> -- */ -- private static final boolean JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION = -- AccessController.doPrivileged(new PrivilegedAction<Boolean>() { -- @Override -- public Boolean run() { -- return SystemPropertyUtil.getBoolean("jdk.tls.rejectClientInitiatedRenegotiation", false); -- } -- }); +-public final class OpenSslServerSessionContext extends OpenSslSessionContext { +- OpenSslServerSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) { +- super(context, provider); +- } - -- private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE = -- AccessController.doPrivileged(new PrivilegedAction<Integer>() { -- @Override -- public Integer run() { -- return Math.max(1, -- SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize", -- 2048)); -- } -- }); +- @Override +- public void setSessionTimeout(int seconds) { +- if (seconds < 0) { +- throw new IllegalArgumentException(); +- } +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.setSessionCacheTimeout(context.ctx, seconds); +- } finally { +- writerLock.unlock(); +- } +- } - -- private static final List<String> DEFAULT_CIPHERS; -- private static final Integer DH_KEY_LENGTH; -- private static final ResourceLeakDetector<ReferenceCountedOpenSslContext> leakDetector = -- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class); +- @Override +- public int getSessionTimeout() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return (int) SSLContext.getSessionCacheTimeout(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } - -- // TODO: Maybe make configurable ? -- protected static final int VERIFY_DEPTH = 10; +- @Override +- public void setSessionCacheSize(int size) { +- if (size < 0) { +- throw new IllegalArgumentException(); +- } +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.setSessionCacheSize(context.ctx, size); +- } finally { +- writerLock.unlock(); +- } +- } - -- /** -- * The OpenSSL SSL_CTX object. -- * -- * <strong>{@link #ctxLock} must be hold while using ctx!</strong> -- */ -- protected long ctx; -- private final List<String> unmodifiableCiphers; -- private final long sessionCacheSize; -- private final long sessionTimeout; -- private final OpenSslApplicationProtocolNegotiator apn; -- private final int mode; +- @Override +- public int getSessionCacheSize() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return (int) SSLContext.getSessionCacheSize(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } - -- // Reference Counting -- private final ResourceLeakTracker<ReferenceCountedOpenSslContext> leak; -- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { -- @Override -- public ReferenceCounted touch(Object hint) { -- if (leak != null) { -- leak.record(hint); -- } +- @Override +- public void setSessionCacheEnabled(boolean enabled) { +- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF; - -- return ReferenceCountedOpenSslContext.this; +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.setSessionCacheMode(context.ctx, mode); +- } finally { +- writerLock.unlock(); - } +- } - -- @Override -- protected void deallocate() { -- destroy(); -- if (leak != null) { -- boolean closed = leak.close(ReferenceCountedOpenSslContext.this); -- assert closed; -- } +- @Override +- public boolean isSessionCacheEnabled() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER; +- } finally { +- readerLock.unlock(); - } -- }; -- -- final Certificate[] keyCertChain; -- final ClientAuth clientAuth; -- final String[] protocols; -- final boolean enableOcsp; -- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap(); -- final ReadWriteLock ctxLock = new ReentrantReadWriteLock(); -- -- private volatile boolean rejectRemoteInitiatedRenegotiation; -- private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE; +- } - -- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR = -- new OpenSslApplicationProtocolNegotiator() { -- @Override -- public ApplicationProtocolConfig.Protocol protocol() { -- return ApplicationProtocolConfig.Protocol.NONE; -- } +- /** +- * Set the context within which session be reused (server side only) +- * See <a href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context.html"> +- * man SSL_CTX_set_session_id_context</a> +- * +- * @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name +- * of the application and/or the hostname and/or service name +- * @return {@code true} if success, {@code false} otherwise. +- */ +- public boolean setSessionIdContext(byte[] sidCtx) { +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- return SSLContext.setSessionIdContext(context.ctx, sidCtx); +- } finally { +- writerLock.unlock(); +- } +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java +deleted file mode 100644 +index 5d471d34fb..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java ++++ /dev/null +@@ -1,158 +0,0 @@ +-/* +- * Copyright 2014 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; - -- @Override -- public List<String> protocols() { -- return Collections.emptyList(); -- } +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +-import io.netty.internal.tcnative.SessionTicketKey; +-import io.netty.util.internal.ObjectUtil; - -- @Override -- public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() { -- return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL; -- } +-import javax.net.ssl.SSLSession; +-import javax.net.ssl.SSLSessionContext; +-import java.util.Arrays; +-import java.util.Enumeration; +-import java.util.NoSuchElementException; +-import java.util.concurrent.locks.Lock; - -- @Override -- public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() { -- return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT; -- } -- }; +-/** +- * OpenSSL specific {@link SSLSessionContext} implementation. +- */ +-public abstract class OpenSslSessionContext implements SSLSessionContext { +- private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration(); - -- static { -- List<String> ciphers = new ArrayList<String>(); -- // XXX: Make sure to sync this list with JdkSslEngineFactory. -- Collections.addAll( -- ciphers, -- "ECDHE-ECDSA-AES256-GCM-SHA384", -- "ECDHE-ECDSA-AES128-GCM-SHA256", -- "ECDHE-RSA-AES128-GCM-SHA256", -- "ECDHE-RSA-AES128-SHA", -- "ECDHE-RSA-AES256-SHA", -- "AES128-GCM-SHA256", -- "AES128-SHA", -- "AES256-SHA"); -- DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers); +- private final OpenSslSessionStats stats; - -- if (logger.isDebugEnabled()) { -- logger.debug("Default cipher suite (OpenSSL): " + ciphers); -- } +- // The OpenSslKeyMaterialProvider is not really used by the OpenSslSessionContext but only be stored here +- // to make it easier to destroy it later because the ReferenceCountedOpenSslContext will hold a reference +- // to OpenSslSessionContext. +- private final OpenSslKeyMaterialProvider provider; - -- Integer dhLen = null; +- final ReferenceCountedOpenSslContext context; - -- try { -- String dhKeySize = AccessController.doPrivileged(new PrivilegedAction<String>() { -- @Override -- public String run() { -- return SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize"); -- } -- }); -- if (dhKeySize != null) { -- try { -- dhLen = Integer.valueOf(dhKeySize); -- } catch (NumberFormatException e) { -- logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: " -- + dhKeySize); -- } -- } -- } catch (Throwable ignore) { -- // ignore -- } -- DH_KEY_LENGTH = dhLen; +- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent +- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a +- // segfault when the user calls any of the methods here that try to pass the pointer down to the native +- // level. +- OpenSslSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) { +- this.context = context; +- this.provider = provider; +- stats = new OpenSslSessionStats(context); - } - -- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, -- ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout, -- int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols, -- boolean startTls, boolean enableOcsp, boolean leakDetection) throws SSLException { -- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain, -- clientAuth, protocols, startTls, enableOcsp, leakDetection); +- final boolean useKeyManager() { +- return provider != null; - } - -- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, -- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, -- long sessionTimeout, int mode, Certificate[] keyCertChain, -- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp, -- boolean leakDetection) throws SSLException { -- super(startTls); +- @Override +- public SSLSession getSession(byte[] bytes) { +- ObjectUtil.checkNotNull(bytes, "bytes"); +- return null; +- } - -- OpenSsl.ensureAvailability(); +- @Override +- public Enumeration<byte[]> getIds() { +- return EMPTY; +- } - -- if (enableOcsp && !OpenSsl.isOcspSupported()) { -- throw new IllegalStateException("OCSP is not supported."); +- /** +- * Sets the SSL session ticket keys of this context. +- * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}. +- */ +- @Deprecated +- public void setTicketKeys(byte[] keys) { +- if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) { +- throw new IllegalArgumentException("keys.length % " + SessionTicketKey.TICKET_KEY_SIZE + " != 0"); - } -- -- if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) { -- throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT"); +- SessionTicketKey[] tickets = new SessionTicketKey[keys.length / SessionTicketKey.TICKET_KEY_SIZE]; +- for (int i = 0, a = 0; i < tickets.length; i++) { +- byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE); +- a += SessionTicketKey.NAME_SIZE; +- byte[] hmacKey = Arrays.copyOfRange(keys, a, SessionTicketKey.HMAC_KEY_SIZE); +- i += SessionTicketKey.HMAC_KEY_SIZE; +- byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE); +- a += SessionTicketKey.AES_KEY_SIZE; +- tickets[i] = new SessionTicketKey(name, hmacKey, aesKey); - } -- leak = leakDetection ? leakDetector.track(this) : null; -- this.mode = mode; -- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE; -- this.protocols = protocols; -- this.enableOcsp = enableOcsp; -- -- if (mode == SSL.SSL_MODE_SERVER) { -- rejectRemoteInitiatedRenegotiation = -- JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION; +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET); +- SSLContext.setSessionTicketKeys(context.ctx, tickets); +- } finally { +- writerLock.unlock(); - } -- this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone(); -- final List<String> convertedCiphers; -- if (ciphers == null) { -- convertedCiphers = null; -- } else { -- convertedCiphers = new ArrayList<String>(); -- for (String c : ciphers) { -- if (c == null) { -- break; -- } +- } - -- String converted = CipherSuiteConverter.toOpenSsl(c); -- if (converted != null) { -- c = converted; -- } -- convertedCiphers.add(c); +- /** +- * Sets the SSL session ticket keys of this context. Depending on the underlying native library you may omit the +- * argument or pass an empty array and so let the native library handle the key generation and rotating for you. +- * If this is supported by the underlying native library should be checked in this case. For example +- * <a href="https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#Session-tickets/"> +- * BoringSSL</a> is known to support this. +- */ +- public void setTicketKeys(OpenSslSessionTicketKey... keys) { +- ObjectUtil.checkNotNull(keys, "keys"); +- SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length]; +- for (int i = 0; i < ticketKeys.length; i++) { +- ticketKeys[i] = keys[i].key; +- } +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET); +- if (ticketKeys.length > 0) { +- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys); - } +- } finally { +- writerLock.unlock(); - } +- } - -- unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites( -- convertedCiphers, DEFAULT_CIPHERS, OpenSsl.availableOpenSslCipherSuites())); +- /** +- * Enable or disable caching of SSL sessions. +- */ +- public abstract void setSessionCacheEnabled(boolean enabled); - -- this.apn = checkNotNull(apn, "apn"); +- /** +- * Return {@code true} if caching of SSL sessions is enabled, {@code false} otherwise. +- */ +- public abstract boolean isSessionCacheEnabled(); - -- // Create a new SSL_CTX and configure it. -- boolean success = false; -- try { -- try { -- ctx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, mode); -- } catch (Exception e) { -- throw new SSLException("failed to create an SSL_CTX", e); -- } +- /** +- * Returns the stats of this context. +- */ +- public OpenSslSessionStats stats() { +- return stats; +- } +- +- final void destroy() { +- if (provider != null) { +- provider.destroy(); +- } +- } +- +- private static final class EmptyEnumeration implements Enumeration<byte[]> { +- @Override +- public boolean hasMoreElements() { +- return false; +- } - -- SSLContext.setOptions(ctx, SSLContext.getOptions(ctx) | -- SSL.SSL_OP_NO_SSLv2 | -- SSL.SSL_OP_NO_SSLv3 | -- SSL.SSL_OP_CIPHER_SERVER_PREFERENCE | +- @Override +- public byte[] nextElement() { +- throw new NoSuchElementException(); +- } +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java +deleted file mode 100644 +index f49b95f3ba..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java ++++ /dev/null +@@ -1,253 +0,0 @@ +-/* +- * Copyright 2014 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. +- */ - -- // We do not support compression at the moment so we should explicitly disable it. -- SSL.SSL_OP_NO_COMPRESSION | +-package io.netty.handler.ssl; - -- // Disable ticket support by default to be more inline with SSLEngineImpl of the JDK. -- // This also let SSLSession.getId() work the same way for the JDK implementation and the -- // OpenSSLEngine. If tickets are supported SSLSession.getId() will only return an ID on the -- // server-side if it could make use of tickets. -- SSL.SSL_OP_NO_TICKET); +-import io.netty.internal.tcnative.SSLContext; - -- // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between -- // calling OpenSSLEngine.wrap(...). -- // See https://github.com/netty/netty-tcnative/issues/100 -- SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); +-import java.util.concurrent.locks.Lock; - -- if (DH_KEY_LENGTH != null) { -- SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH); -- } +-/** +- * Stats exposed by an OpenSSL session context. +- * +- * @see <a href="https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_number.html">SSL_CTX_sess_number</a> +- */ +-public final class OpenSslSessionStats { - -- /* List the ciphers that are permitted to negotiate. */ -- try { -- SSLContext.setCipherSuite(ctx, CipherSuiteConverter.toOpenSsl(unmodifiableCiphers)); -- } catch (SSLException e) { -- throw e; -- } catch (Exception e) { -- throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e); -- } +- private final ReferenceCountedOpenSslContext context; - -- List<String> nextProtoList = apn.protocols(); -- /* Set next protocols for next protocol negotiation extension, if specified */ -- if (!nextProtoList.isEmpty()) { -- String[] appProtocols = nextProtoList.toArray(new String[nextProtoList.size()]); -- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior()); +- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent +- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a +- // segfault when the user calls any of the methods here that try to pass the pointer down to the native +- // level. +- OpenSslSessionStats(ReferenceCountedOpenSslContext context) { +- this.context = context; +- } - -- switch (apn.protocol()) { -- case NPN: -- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior); -- break; -- case ALPN: -- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior); -- break; -- case NPN_AND_ALPN: -- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior); -- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior); -- break; -- default: -- throw new Error(); -- } -- } +- /** +- * Returns the current number of sessions in the internal session cache. +- */ +- public long number() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionNumber(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } - -- /* Set session cache size, if specified */ -- if (sessionCacheSize > 0) { -- this.sessionCacheSize = sessionCacheSize; -- SSLContext.setSessionCacheSize(ctx, sessionCacheSize); -- } else { -- // Get the default session cache size using SSLContext.setSessionCacheSize() -- this.sessionCacheSize = sessionCacheSize = SSLContext.setSessionCacheSize(ctx, 20480); -- // Revert the session cache size to the default value. -- SSLContext.setSessionCacheSize(ctx, sessionCacheSize); -- } +- /** +- * Returns the number of started SSL/TLS handshakes in client mode. +- */ +- public long connect() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionConnect(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } - -- /* Set session timeout, if specified */ -- if (sessionTimeout > 0) { -- this.sessionTimeout = sessionTimeout; -- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout); -- } else { -- // Get the default session timeout using SSLContext.setSessionCacheTimeout() -- this.sessionTimeout = sessionTimeout = SSLContext.setSessionCacheTimeout(ctx, 300); -- // Revert the session timeout to the default value. -- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout); -- } +- /** +- * Returns the number of successfully established SSL/TLS sessions in client mode. +- */ +- public long connectGood() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionConnectGood(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } - -- if (enableOcsp) { -- SSLContext.enableOcsp(ctx, isClient()); -- } -- success = true; +- /** +- * Returns the number of start renegotiations in client mode. +- */ +- public long connectRenegotiate() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionConnectRenegotiate(context.ctx); - } finally { -- if (!success) { -- release(); -- } +- readerLock.unlock(); - } - } - -- private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) { -- switch (behavior) { -- case NO_ADVERTISE: -- return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE; -- case CHOOSE_MY_LAST_PROTOCOL: -- return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL; -- default: -- throw new Error(); +- /** +- * Returns the number of started SSL/TLS handshakes in server mode. +- */ +- public long accept() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionAccept(context.ctx); +- } finally { +- readerLock.unlock(); - } - } - -- @Override -- public final List<String> cipherSuites() { -- return unmodifiableCiphers; +- /** +- * Returns the number of successfully established SSL/TLS sessions in server mode. +- */ +- public long acceptGood() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionAcceptGood(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - -- @Override -- public final long sessionCacheSize() { -- return sessionCacheSize; +- /** +- * Returns the number of start renegotiations in server mode. +- */ +- public long acceptRenegotiate() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionAcceptRenegotiate(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - -- @Override -- public final long sessionTimeout() { -- return sessionTimeout; +- /** +- * Returns the number of successfully reused sessions. In client mode, a session set with {@code SSL_set_session} +- * successfully reused is counted as a hit. In server mode, a session successfully retrieved from internal or +- * external cache is counted as a hit. +- */ +- public long hits() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionHits(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - -- @Override -- public ApplicationProtocolNegotiator applicationProtocolNegotiator() { -- return apn; +- /** +- * Returns the number of successfully retrieved sessions from the external session cache in server mode. +- */ +- public long cbHits() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionCbHits(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - -- @Override -- public final boolean isClient() { -- return mode == SSL.SSL_MODE_CLIENT; +- /** +- * Returns the number of sessions proposed by clients that were not found in the internal session cache +- * in server mode. +- */ +- public long misses() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionMisses(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - -- @Override -- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) { -- return newEngine0(alloc, peerHost, peerPort); +- /** +- * Returns the number of sessions proposed by clients and either found in the internal or external session cache +- * in server mode, but that were invalid due to timeout. These sessions are not included in the {@link #hits()} +- * count. +- */ +- public long timeouts() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTimeouts(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - -- SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) { -- return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, true); +- /** +- * Returns the number of sessions that were removed because the maximum session cache size was exceeded. +- */ +- public long cacheFull() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionCacheFull(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - -- abstract OpenSslKeyMaterialManager keyMaterialManager(); +- /** +- * Returns the number of times a client presented a ticket that did not match any key in the list. +- */ +- public long ticketKeyFail() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTicketKeyFail(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } - - /** -- * Returns a new server-side {@link SSLEngine} with the current configuration. +- * Returns the number of times a client did not present a ticket and we issued a new one - */ -- @Override -- public final SSLEngine newEngine(ByteBufAllocator alloc) { -- return newEngine(alloc, null, -1); +- public long ticketKeyNew() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTicketKeyNew(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - - /** -- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}. -- * Be aware that it is freed as soon as the {@link #finalize()} method is called. -- * At this point {@code 0} will be returned. -- * -- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it! +- * Returns the number of times a client presented a ticket derived from an older key, +- * and we upgraded to the primary key. - */ -- @Deprecated -- public final long context() { -- Lock readerLock = ctxLock.readLock(); +- public long ticketKeyRenew() { +- Lock readerLock = context.ctxLock.readLock(); - readerLock.lock(); - try { -- return ctx; +- return SSLContext.sessionTicketKeyRenew(context.ctx); - } finally { - readerLock.unlock(); - } - } - - /** -- * Returns the stats of this context. -- * -- * @deprecated use {@link #sessionContext#stats()} +- * Returns the number of times a client presented a ticket derived from the primary key. - */ -- @Deprecated -- public final OpenSslSessionStats stats() { -- return sessionContext().stats(); +- public long ticketKeyResume() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTicketKeyResume(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java +deleted file mode 100644 +index 79f71a65a3..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java ++++ /dev/null +@@ -1,78 +0,0 @@ +-/* +- * Copyright 2015 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.internal.tcnative.SessionTicketKey; +- +-/** +- * Session Ticket Key +- */ +-public final class OpenSslSessionTicketKey { - - /** -- * Specify if remote initiated renegotiation is supported or not. If not supported and the remote side tries -- * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during decoding. +- * Size of session ticket key name +- */ +- public static final int NAME_SIZE = SessionTicketKey.NAME_SIZE; +- /** +- * Size of session ticket key HMAC key +- */ +- public static final int HMAC_KEY_SIZE = SessionTicketKey.HMAC_KEY_SIZE; +- /** +- * Size of session ticket key AES key - */ -- public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) { -- this.rejectRemoteInitiatedRenegotiation = rejectRemoteInitiatedRenegotiation; -- } -- +- public static final int AES_KEY_SIZE = SessionTicketKey.AES_KEY_SIZE; - /** -- * Returns if remote initiated renegotiation is supported or not. +- * Size of session ticker key - */ -- public boolean getRejectRemoteInitiatedRenegotiation() { -- return rejectRemoteInitiatedRenegotiation; -- } +- public static final int TICKET_KEY_SIZE = SessionTicketKey.TICKET_KEY_SIZE; +- +- final SessionTicketKey key; - - /** -- * Set the size of the buffer used by the BIO for non-application based writes -- * (e.g. handshake, renegotiation, etc...). +- * Construct a OpenSslSessionTicketKey. +- * +- * @param name the name of the session ticket key +- * @param hmacKey the HMAC key of the session ticket key +- * @param aesKey the AES key of the session ticket key - */ -- public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) { -- this.bioNonApplicationBufferSize = -- checkPositiveOrZero(bioNonApplicationBufferSize, "bioNonApplicationBufferSize"); +- public OpenSslSessionTicketKey(byte[] name, byte[] hmacKey, byte[] aesKey) { +- key = new SessionTicketKey(name.clone(), hmacKey.clone(), aesKey.clone()); - } - - /** -- * Returns the size of the buffer used by the BIO for non-application based writes +- * Get name. +- * @return the name of the session ticket key - */ -- public int getBioNonApplicationBufferSize() { -- return bioNonApplicationBufferSize; +- public byte[] name() { +- return key.getName().clone(); - } - - /** -- * Sets the SSL session ticket keys of this context. -- * -- * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])} +- * Get HMAC key. +- * @return the HMAC key of the session ticket key - */ -- @Deprecated -- public final void setTicketKeys(byte[] keys) { -- sessionContext().setTicketKeys(keys); +- public byte[] hmacKey() { +- return key.getHmacKey().clone(); - } - -- @Override -- public abstract OpenSslSessionContext sessionContext(); -- - /** -- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}. -- * Be aware that it is freed as soon as the {@link #release()} method is called. -- * At this point {@code 0} will be returned. -- * -- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it! +- * Get AES Key. +- * @return the AES key of the session ticket key - */ -- @Deprecated -- public final long sslCtxPointer() { -- Lock readerLock = ctxLock.readLock(); -- readerLock.lock(); -- try { -- return ctx; -- } finally { -- readerLock.unlock(); -- } +- public byte[] aesKey() { +- return key.getAesKey().clone(); - } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java +deleted file mode 100644 +index a5a84f2793..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java ++++ /dev/null +@@ -1,240 +0,0 @@ +-/* +- * Copyright 2018 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; - -- // IMPORTANT: This method must only be called from either the constructor or the finalizer as a user MUST never -- // get access to an OpenSslSessionContext after this method was called to prevent the user from -- // producing a segfault. -- private void destroy() { -- Lock writerLock = ctxLock.writeLock(); -- writerLock.lock(); -- try { -- if (ctx != 0) { -- if (enableOcsp) { -- SSLContext.disableOcsp(ctx); -- } +-import io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.SuppressJava6Requirement; - -- SSLContext.free(ctx); -- ctx = 0; -- } -- } finally { -- writerLock.unlock(); -- } -- } +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLPeerUnverifiedException; +-import javax.net.ssl.SSLSession; +-import javax.net.ssl.SSLSessionContext; +-import javax.net.ssl.X509ExtendedTrustManager; +-import java.net.Socket; +-import java.security.Principal; +-import java.security.cert.Certificate; +-import java.security.cert.CertificateException; +-import java.security.cert.X509Certificate; +-import java.util.List; - -- protected static X509Certificate[] certificates(byte[][] chain) { -- X509Certificate[] peerCerts = new X509Certificate[chain.length]; -- for (int i = 0; i < peerCerts.length; i++) { -- peerCerts[i] = new OpenSslX509Certificate(chain[i]); -- } -- return peerCerts; -- } +-/** +- * Provide a way to use {@code TLSv1.3} with Java versions prior to 11 by adding a +- * <a href="http://mail.openjdk.java.net/pipermail/security-dev/2018-September/018242.ht...</a> for the +- * default {@link X509ExtendedTrustManager} implementations provided by the JDK that can not handle a protocol version +- * of {@code TLSv1.3}. +- */ +-@SuppressJava6Requirement(reason = "Usage guarded by java version check") +-final class OpenSslTlsv13X509ExtendedTrustManager extends X509ExtendedTrustManager { - -- protected static X509TrustManager chooseTrustManager(TrustManager[] managers) { -- for (TrustManager m : managers) { -- if (m instanceof X509TrustManager) { -- return (X509TrustManager) m; -- } -- } -- throw new IllegalStateException("no X509TrustManager found"); -- } +- private final X509ExtendedTrustManager tm; - -- protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) { -- for (KeyManager km : kms) { -- if (km instanceof X509KeyManager) { -- return (X509KeyManager) km; -- } -- } -- throw new IllegalStateException("no X509KeyManager found"); +- private OpenSslTlsv13X509ExtendedTrustManager(X509ExtendedTrustManager tm) { +- this.tm = tm; - } - -- /** -- * Translate a {@link ApplicationProtocolConfig} object to a -- * {@link OpenSslApplicationProtocolNegotiator} object. -- * -- * @param config The configuration which defines the translation -- * @return The results of the translation -- */ -- static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) { -- if (config == null) { -- return NONE_PROTOCOL_NEGOTIATOR; -- } -- -- switch (config.protocol()) { -- case NONE: -- return NONE_PROTOCOL_NEGOTIATOR; -- case ALPN: -- case NPN: -- case NPN_AND_ALPN: -- switch (config.selectedListenerFailureBehavior()) { -- case CHOOSE_MY_LAST_PROTOCOL: -- case ACCEPT: -- switch (config.selectorFailureBehavior()) { -- case CHOOSE_MY_LAST_PROTOCOL: -- case NO_ADVERTISE: -- return new OpenSslDefaultApplicationProtocolNegotiator( -- config); -- default: -- throw new UnsupportedOperationException( -- new StringBuilder("OpenSSL provider does not support ") -- .append(config.selectorFailureBehavior()) -- .append(" behavior").toString()); -- } -- default: -- throw new UnsupportedOperationException( -- new StringBuilder("OpenSSL provider does not support ") -- .append(config.selectedListenerFailureBehavior()) -- .append(" behavior").toString()); -- } -- default: -- throw new Error(); +- static X509ExtendedTrustManager wrap(X509ExtendedTrustManager tm) { +- if (PlatformDependent.javaVersion() < 11 && OpenSsl.isTlsv13Supported()) { +- return new OpenSslTlsv13X509ExtendedTrustManager(tm); - } -- } -- -- static boolean useExtendedTrustManager(X509TrustManager trustManager) { -- return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager; -- } -- -- static boolean useExtendedKeyManager(X509KeyManager keyManager) { -- return PlatformDependent.javaVersion() >= 7 && keyManager instanceof X509ExtendedKeyManager; -- } -- -- @Override -- public final int refCnt() { -- return refCnt.refCnt(); +- return tm; - } - - @Override -- public final ReferenceCounted retain() { -- refCnt.retain(); -- return this; -- } -- -- @Override -- public final ReferenceCounted retain(int increment) { -- refCnt.retain(increment); -- return this; +- public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) +- throws CertificateException { +- tm.checkClientTrusted(x509Certificates, s, socket); - } - - @Override -- public final ReferenceCounted touch() { -- refCnt.touch(); -- return this; +- public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) +- throws CertificateException { +- tm.checkServerTrusted(x509Certificates, s, socket); - } - -- @Override -- public final ReferenceCounted touch(Object hint) { -- refCnt.touch(hint); -- return this; -- } +- private static SSLEngine wrapEngine(final SSLEngine engine) { +- final SSLSession session = engine.getHandshakeSession(); +- if (session != null && SslUtils.PROTOCOL_TLS_V1_3.equals(session.getProtocol())) { +- return new JdkSslEngine(engine) { +- @Override +- public String getNegotiatedApplicationProtocol() { +- if (engine instanceof ApplicationProtocolAccessor) { +- return ((ApplicationProtocolAccessor) engine).getNegotiatedApplicationProtocol(); +- } +- return super.getNegotiatedApplicationProtocol(); +- } - -- @Override -- public final boolean release() { -- return refCnt.release(); -- } +- @Override +- public SSLSession getHandshakeSession() { +- if (PlatformDependent.javaVersion() >= 7 && session instanceof ExtendedOpenSslSession) { +- final ExtendedOpenSslSession extendedOpenSslSession = (ExtendedOpenSslSession) session; +- return new ExtendedOpenSslSession(extendedOpenSslSession) { +- @Override +- public List getRequestedServerNames() { +- return extendedOpenSslSession.getRequestedServerNames(); +- } - -- @Override -- public final boolean release(int decrement) { -- return refCnt.release(decrement); -- } +- @Override +- public String[] getPeerSupportedSignatureAlgorithms() { +- return extendedOpenSslSession.getPeerSupportedSignatureAlgorithms(); +- } - -- abstract static class AbstractCertificateVerifier extends CertificateVerifier { -- private final OpenSslEngineMap engineMap; +- @Override +- public String getProtocol() { +- return SslUtils.PROTOCOL_TLS_V1_2; +- } +- }; +- } else { +- return new SSLSession() { +- @Override +- public byte[] getId() { +- return session.getId(); +- } - -- AbstractCertificateVerifier(OpenSslEngineMap engineMap) { -- this.engineMap = engineMap; -- } +- @Override +- public SSLSessionContext getSessionContext() { +- return session.getSessionContext(); +- } - -- @Override -- public final int verify(long ssl, byte[][] chain, String auth) { -- X509Certificate[] peerCerts = certificates(chain); -- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); -- try { -- verify(engine, peerCerts, auth); -- return CertificateVerifier.X509_V_OK; -- } catch (Throwable cause) { -- logger.debug("verification of certificate failed", cause); -- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem"); -- e.initCause(cause); -- engine.handshakeException = e; +- @Override +- public long getCreationTime() { +- return session.getCreationTime(); +- } - -- // Try to extract the correct error code that should be used. -- if (cause instanceof OpenSslCertificateException) { -- // This will never return a negative error code as its validated when constructing the -- // OpenSslCertificateException. -- return ((OpenSslCertificateException) cause).errorCode(); -- } -- if (cause instanceof CertificateExpiredException) { -- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED; -- } -- if (cause instanceof CertificateNotYetValidException) { -- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID; -- } -- if (PlatformDependent.javaVersion() >= 7) { -- if (cause instanceof CertificateRevokedException) { -- return CertificateVerifier.X509_V_ERR_CERT_REVOKED; -- } +- @Override +- public long getLastAccessedTime() { +- return session.getLastAccessedTime(); +- } - -- // The X509TrustManagerImpl uses a Validator which wraps a CertPathValidatorException into -- // an CertificateException. So we need to handle the wrapped CertPathValidatorException to be -- // able to send the correct alert. -- Throwable wrapped = cause.getCause(); -- while (wrapped != null) { -- if (wrapped instanceof CertPathValidatorException) { -- CertPathValidatorException ex = (CertPathValidatorException) wrapped; -- CertPathValidatorException.Reason reason = ex.getReason(); -- if (reason == CertPathValidatorException.BasicReason.EXPIRED) { -- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED; +- @Override +- public void invalidate() { +- session.invalidate(); - } -- if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) { -- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID; +- +- @Override +- public boolean isValid() { +- return session.isValid(); - } -- if (reason == CertPathValidatorException.BasicReason.REVOKED) { -- return CertificateVerifier.X509_V_ERR_CERT_REVOKED; +- +- @Override +- public void putValue(String s, Object o) { +- session.putValue(s, o); - } -- } -- wrapped = wrapped.getCause(); -- } -- } - -- // Could not detect a specific error code to use, so fallback to a default code. -- return CertificateVerifier.X509_V_ERR_UNSPECIFIED; -- } -- } +- @Override +- public Object getValue(String s) { +- return session.getValue(s); +- } - -- abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, -- String auth) throws Exception; -- } +- @Override +- public void removeValue(String s) { +- session.removeValue(s); +- } - -- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap { -- private final Map<Long, ReferenceCountedOpenSslEngine> engines = PlatformDependent.newConcurrentHashMap(); +- @Override +- public String[] getValueNames() { +- return session.getValueNames(); +- } - -- @Override -- public ReferenceCountedOpenSslEngine remove(long ssl) { -- return engines.remove(ssl); -- } +- @Override +- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { +- return session.getPeerCertificates(); +- } - -- @Override -- public void add(ReferenceCountedOpenSslEngine engine) { -- engines.put(engine.sslPointer(), engine); -- } +- @Override +- public Certificate[] getLocalCertificates() { +- return session.getLocalCertificates(); +- } - -- @Override -- public ReferenceCountedOpenSslEngine get(long ssl) { -- return engines.get(ssl); -- } -- } +- @Override +- public javax.security.cert.X509Certificate[] getPeerCertificateChain() +- throws SSLPeerUnverifiedException { +- return session.getPeerCertificateChain(); +- } - -- static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword) -- throws SSLException { -- /* Load the certificate file and private key. */ -- long keyBio = 0; -- long keyCertChainBio = 0; -- long keyCertChainBio2 = 0; -- PemEncoded encoded = null; -- try { -- // Only encode one time -- encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain); -- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); -- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); +- @Override +- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { +- return session.getPeerPrincipal(); +- } - -- if (key != null) { -- keyBio = toBIO(key); -- } +- @Override +- public Principal getLocalPrincipal() { +- return session.getLocalPrincipal(); +- } - -- SSLContext.setCertificateBio( -- ctx, keyCertChainBio, keyBio, -- keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword); -- // We may have more then one cert in the chain so add all of them now. -- SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true); -- } catch (SSLException e) { -- throw e; -- } catch (Exception e) { -- throw new SSLException("failed to set certificate and key", e); -- } finally { -- freeBio(keyBio); -- freeBio(keyCertChainBio); -- freeBio(keyCertChainBio2); -- if (encoded != null) { -- encoded.release(); -- } -- } -- } +- @Override +- public String getCipherSuite() { +- return session.getCipherSuite(); +- } - -- static void freeBio(long bio) { -- if (bio != 0) { -- SSL.freeBIO(bio); -- } -- } +- @Override +- public String getProtocol() { +- return SslUtils.PROTOCOL_TLS_V1_2; +- } - -- /** -- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a> -- * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}. -- */ -- static long toBIO(PrivateKey key) throws Exception { -- if (key == null) { -- return 0; -- } +- @Override +- public String getPeerHost() { +- return session.getPeerHost(); +- } - -- ByteBufAllocator allocator = ByteBufAllocator.DEFAULT; -- PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key); -- try { -- return toBIO(allocator, pem.retain()); -- } finally { -- pem.release(); -- } -- } +- @Override +- public int getPeerPort() { +- return session.getPeerPort(); +- } - -- /** -- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a> -- * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}. -- */ -- static long toBIO(X509Certificate... certChain) throws Exception { -- if (certChain == null) { -- return 0; -- } +- @Override +- public int getPacketBufferSize() { +- return session.getPacketBufferSize(); +- } - -- if (certChain.length == 0) { -- throw new IllegalArgumentException("certChain can't be empty"); +- @Override +- public int getApplicationBufferSize() { +- return session.getApplicationBufferSize(); +- } +- }; +- } +- } +- }; - } +- return engine; +- } - -- ByteBufAllocator allocator = ByteBufAllocator.DEFAULT; -- PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain); -- try { -- return toBIO(allocator, pem.retain()); -- } finally { -- pem.release(); -- } +- @Override +- public void checkClientTrusted(X509Certificate[] x509Certificates, final String s, SSLEngine sslEngine) +- throws CertificateException { +- tm.checkClientTrusted(x509Certificates, s, wrapEngine(sslEngine)); - } - -- static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception { -- try { -- // We can turn direct buffers straight into BIOs. No need to -- // make a yet another copy. -- ByteBuf content = pem.content(); +- @Override +- public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) +- throws CertificateException { +- tm.checkServerTrusted(x509Certificates, s, wrapEngine(sslEngine)); +- } - -- if (content.isDirect()) { -- return newBIO(content.retainedSlice()); -- } +- @Override +- public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { +- tm.checkClientTrusted(x509Certificates, s); +- } - -- ByteBuf buffer = allocator.directBuffer(content.readableBytes()); -- try { -- buffer.writeBytes(content, content.readerIndex(), content.readableBytes()); -- return newBIO(buffer.retainedSlice()); -- } finally { -- try { -- // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we -- // need to zero out the bytes of the copy before we're releasing it. -- if (pem.isSensitive()) { -- SslUtils.zeroout(buffer); -- } -- } finally { -- buffer.release(); -- } -- } -- } finally { -- pem.release(); -- } +- @Override +- public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { +- tm.checkServerTrusted(x509Certificates, s); - } - -- private static long newBIO(ByteBuf buffer) throws Exception { -- try { -- long bio = SSL.newMemBIO(); -- int readable = buffer.readableBytes(); -- if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) { -- SSL.freeBIO(bio); -- throw new IllegalStateException("Could not write data to memory BIO"); -- } -- return bio; -- } finally { -- buffer.release(); -- } +- @Override +- public X509Certificate[] getAcceptedIssuers() { +- return tm.getAcceptedIssuers(); - } -} -diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java deleted file mode 100644 -index 27460c7..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java +index 2a86332fe1..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java +++ /dev/null -@@ -1,2037 +0,0 @@ +@@ -1,413 +0,0 @@ -/* -- * Copyright 2016 The Netty Project +- * Copyright 2018 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 @@ -3485,4638 +3793,4204 @@ index 27460c7..0000000 - */ -package io.netty.handler.ssl; - --import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; --import io.netty.internal.tcnative.Buffer; +-import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.internal.tcnative.SSL; --import io.netty.util.AbstractReferenceCounted; --import io.netty.util.ReferenceCounted; --import io.netty.util.ResourceLeakDetector; --import io.netty.util.ResourceLeakDetectorFactory; --import io.netty.util.ResourceLeakTracker; --import io.netty.util.internal.EmptyArrays; --import io.netty.util.internal.PlatformDependent; --import io.netty.util.internal.StringUtil; --import io.netty.util.internal.ThrowableUtil; --import io.netty.util.internal.UnstableApi; --import io.netty.util.internal.logging.InternalLogger; --import io.netty.util.internal.logging.InternalLoggerFactory; +-import io.netty.util.ReferenceCountUtil; +-import io.netty.util.internal.ObjectUtil; - --import java.nio.ByteBuffer; --import java.nio.ReadOnlyBufferException; --import java.security.Principal; +-import javax.net.ssl.KeyManager; +-import javax.net.ssl.KeyManagerFactory; +-import javax.net.ssl.KeyManagerFactorySpi; +-import javax.net.ssl.ManagerFactoryParameters; +-import javax.net.ssl.X509KeyManager; +-import java.io.File; +-import java.io.IOException; +-import java.io.InputStream; +-import java.io.OutputStream; +-import java.security.InvalidAlgorithmParameterException; +-import java.security.Key; +-import java.security.KeyStore; +-import java.security.KeyStoreException; +-import java.security.KeyStoreSpi; +-import java.security.NoSuchAlgorithmException; +-import java.security.PrivateKey; +-import java.security.Provider; +-import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; --import java.util.ArrayList; --import java.util.Arrays; --import java.util.Collection; +-import java.security.cert.CertificateException; +-import java.security.cert.X509Certificate; +-import java.util.Collections; +-import java.util.Date; +-import java.util.Enumeration; -import java.util.HashMap; --import java.util.List; -import java.util.Map; --import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; -- --import java.util.concurrent.locks.Lock; --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLEngineResult; --import javax.net.ssl.SSLException; --import javax.net.ssl.SSLHandshakeException; --import javax.net.ssl.SSLParameters; --import javax.net.ssl.SSLPeerUnverifiedException; --import javax.net.ssl.SSLSession; --import javax.net.ssl.SSLSessionBindingEvent; --import javax.net.ssl.SSLSessionBindingListener; --import javax.net.ssl.SSLSessionContext; --import javax.security.cert.X509Certificate; -- --import static io.netty.handler.ssl.OpenSsl.memoryAddress; --import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH; --import static io.netty.util.internal.EmptyArrays.EMPTY_CERTIFICATES; --import static io.netty.util.internal.EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES; --import static io.netty.util.internal.ObjectUtil.checkNotNull; --import static java.lang.Math.min; --import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED; --import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP; --import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP; --import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; --import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW; --import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW; --import static javax.net.ssl.SSLEngineResult.Status.CLOSED; --import static javax.net.ssl.SSLEngineResult.Status.OK; - -/** -- * Implements a {@link SSLEngine} using -- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>. -- * <p>Instances of this class must be {@link #release() released} or else native memory will leak! +- * Special {@link KeyManagerFactory} that pre-compute the keymaterial used when {@link SslProvider#OPENSSL} or +- * {@link SslProvider#OPENSSL_REFCNT} is used and so will improve handshake times and its performance. - * -- * <p>Instances of this class <strong>must</strong> be released before the {@link ReferenceCountedOpenSslContext} -- * the instance depends upon are released. Otherwise if any method of this class is called which uses the -- * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash. -- */ --public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted { -- -- private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class); -- -- private static final SSLException BEGIN_HANDSHAKE_ENGINE_CLOSED = ThrowableUtil.unknownStackTrace( -- new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "beginHandshake()"); -- private static final SSLException HANDSHAKE_ENGINE_CLOSED = ThrowableUtil.unknownStackTrace( -- new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "handshake()"); -- private static final SSLException RENEGOTIATION_UNSUPPORTED = ThrowableUtil.unknownStackTrace( -- new SSLException("renegotiation unsupported"), ReferenceCountedOpenSslEngine.class, "beginHandshake()"); -- private static final ResourceLeakDetector<ReferenceCountedOpenSslEngine> leakDetector = -- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class); -- /** -- * <a href="https://www.openssl.org/docs/man1.0.2/crypto/X509_check_host.html">The flags argument is usually 0</a>. -- */ -- private static final int DEFAULT_HOSTNAME_VALIDATION_FLAGS = 0; +- * +- * +- * Because the keymaterial is pre-computed any modification to the {@link KeyStore} is ignored after +- * {@link #init(KeyStore, char[])} is called. +- * +- * {@link #init(ManagerFactoryParameters)} is not supported by this implementation and so a call to it will always +- * result in an {@link InvalidAlgorithmParameterException}. +- */ +-public final class OpenSslX509KeyManagerFactory extends KeyManagerFactory { - -- static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14 +- private final OpenSslKeyManagerFactorySpi spi; - -- /** -- * This is the maximum overhead when encrypting plaintext as defined by -- * <a href="https://www.ietf.org/rfc/rfc5246.txt">rfc5264</a>, -- * <a href="https://www.ietf.org/rfc/rfc5289.txt">rfc5289</a> and openssl implementation itself. -- * -- * Please note that we use a padding of 16 here as openssl uses PKC#5 which uses 16 bytes while the spec itself -- * allow up to 255 bytes. 16 bytes is the max for PKC#5 (which handles it the same way as PKC#7) as we use a block -- * size of 16. See <a href="https://tools.ietf.org/html/rfc5652#section-6.3">rfc5652#section-6.3</a>. -- * -- * TLS Header (5) + 16 (IV) + 48 (MAC) + 1 (Padding_length field) + 15 (Padding) + 1 (ContentType) + -- * 2 (ProtocolVersion) + 2 (Length) -- * -- * TODO: We may need to review this calculation once TLS 1.3 becomes available. -- */ -- static final int MAX_TLS_RECORD_OVERHEAD_LENGTH = SSL_RECORD_HEADER_LENGTH + 16 + 48 + 1 + 15 + 1 + 2 + 2; +- public OpenSslX509KeyManagerFactory() { +- this(newOpenSslKeyManagerFactorySpi(null)); +- } - -- static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_PLAINTEXT_LENGTH + MAX_TLS_RECORD_OVERHEAD_LENGTH; +- public OpenSslX509KeyManagerFactory(Provider provider) { +- this(newOpenSslKeyManagerFactorySpi(provider)); +- } - -- private static final AtomicIntegerFieldUpdater<ReferenceCountedOpenSslEngine> DESTROYED_UPDATER = -- AtomicIntegerFieldUpdater.newUpdater(ReferenceCountedOpenSslEngine.class, "destroyed"); +- public OpenSslX509KeyManagerFactory(String algorithm, Provider provider) throws NoSuchAlgorithmException { +- this(newOpenSslKeyManagerFactorySpi(algorithm, provider)); +- } - -- private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL"; -- private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0); -- private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0); -- private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0); -- private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0); -- private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0); +- private OpenSslX509KeyManagerFactory(OpenSslKeyManagerFactorySpi spi) { +- super(spi, spi.kmf.getProvider(), spi.kmf.getAlgorithm()); +- this.spi = spi; +- } - -- // OpenSSL state -- private long ssl; -- private long networkBIO; -- private boolean certificateSet; +- private static OpenSslKeyManagerFactorySpi newOpenSslKeyManagerFactorySpi(Provider provider) { +- try { +- return newOpenSslKeyManagerFactorySpi(null, provider); +- } catch (NoSuchAlgorithmException e) { +- // This should never happen as we use the default algorithm. +- throw new IllegalStateException(e); +- } +- } - -- private enum HandshakeState { -- /** -- * Not started yet. -- */ -- NOT_STARTED, -- /** -- * Started via unwrap/wrap. -- */ -- STARTED_IMPLICITLY, -- /** -- * Started via {@link #beginHandshake()}. -- */ -- STARTED_EXPLICITLY, +- private static OpenSslKeyManagerFactorySpi newOpenSslKeyManagerFactorySpi(String algorithm, Provider provider) +- throws NoSuchAlgorithmException { +- if (algorithm == null) { +- algorithm = KeyManagerFactory.getDefaultAlgorithm(); +- } +- return new OpenSslKeyManagerFactorySpi( +- provider == null ? KeyManagerFactory.getInstance(algorithm) : +- KeyManagerFactory.getInstance(algorithm, provider)); +- } - -- /** -- * Handshake is finished. -- */ -- FINISHED +- OpenSslKeyMaterialProvider newProvider() { +- return spi.newProvider(); - } - -- private HandshakeState handshakeState = HandshakeState.NOT_STARTED; -- private boolean renegotiationPending; -- private boolean receivedShutdown; -- private volatile int destroyed; +- private static final class OpenSslKeyManagerFactorySpi extends KeyManagerFactorySpi { +- final KeyManagerFactory kmf; +- private volatile ProviderFactory providerFactory; +- +- OpenSslKeyManagerFactorySpi(KeyManagerFactory kmf) { +- this.kmf = ObjectUtil.checkNotNull(kmf, "kmf"); +- } - -- // Reference Counting -- private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak; -- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { - @Override -- public ReferenceCounted touch(Object hint) { -- if (leak != null) { -- leak.record(hint); +- protected synchronized void engineInit(KeyStore keyStore, char[] chars) +- throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { +- if (providerFactory != null) { +- throw new KeyStoreException("Already initialized"); +- } +- if (!keyStore.aliases().hasMoreElements()) { +- throw new KeyStoreException("No aliases found"); - } - -- return ReferenceCountedOpenSslEngine.this; +- kmf.init(keyStore, chars); +- providerFactory = new ProviderFactory(ReferenceCountedOpenSslContext.chooseX509KeyManager( +- kmf.getKeyManagers()), password(chars), Collections.list(keyStore.aliases())); - } - -- @Override -- protected void deallocate() { -- shutdown(); -- if (leak != null) { -- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this); -- assert closed; +- private static String password(char[] password) { +- if (password == null || password.length == 0) { +- return null; - } +- return new String(password); - } -- }; - -- private volatile ClientAuth clientAuth = ClientAuth.NONE; +- @Override +- protected void engineInit(ManagerFactoryParameters managerFactoryParameters) +- throws InvalidAlgorithmParameterException { +- throw new InvalidAlgorithmParameterException("Not supported"); +- } - -- // Updated once a new handshake is started and so the SSLSession reused. -- private volatile long lastAccessed = -1; +- @Override +- protected KeyManager[] engineGetKeyManagers() { +- ProviderFactory providerFactory = this.providerFactory; +- if (providerFactory == null) { +- throw new IllegalStateException("engineInit(...) not called yet"); +- } +- return new KeyManager[] { providerFactory.keyManager }; +- } - -- private String endPointIdentificationAlgorithm; -- // Store as object as AlgorithmConstraints only exists since java 7. -- private Object algorithmConstraints; -- private List<String> sniHostNames; +- OpenSslKeyMaterialProvider newProvider() { +- ProviderFactory providerFactory = this.providerFactory; +- if (providerFactory == null) { +- throw new IllegalStateException("engineInit(...) not called yet"); +- } +- return providerFactory.newProvider(); +- } - -- // Mark as volatile as accessed by checkSniHostnameMatch(...) and also not specify the SNIMatcher type to allow us -- // using it with java7. -- private volatile Collection<?> matchers; +- private static final class ProviderFactory { +- private final X509KeyManager keyManager; +- private final String password; +- private final Iterable<String> aliases; - -- // SSL Engine status variables -- private boolean isInboundDone; -- private boolean outboundClosed; +- ProviderFactory(X509KeyManager keyManager, String password, Iterable<String> aliases) { +- this.keyManager = keyManager; +- this.password = password; +- this.aliases = aliases; +- } - -- private final boolean clientMode; -- private final ByteBufAllocator alloc; -- private final OpenSslEngineMap engineMap; -- private final OpenSslApplicationProtocolNegotiator apn; -- private final boolean rejectRemoteInitiatedRenegotiation; -- private final OpenSslSession session; -- private final Certificate[] localCerts; -- private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1]; -- private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1]; -- private final OpenSslKeyMaterialManager keyMaterialManager; -- private final boolean enableOcsp; +- OpenSslKeyMaterialProvider newProvider() { +- return new OpenSslPopulatedKeyMaterialProvider(keyManager, +- password, aliases); +- } - -- // This is package-private as we set it from OpenSslContext if an exception is thrown during -- // the verification step. -- SSLHandshakeException handshakeException; +- /** +- * {@link OpenSslKeyMaterialProvider} implementation that pre-compute the {@link OpenSslKeyMaterial} for +- * all aliases. +- */ +- private static final class OpenSslPopulatedKeyMaterialProvider extends OpenSslKeyMaterialProvider { +- private final Map<String, Object> materialMap; - -- /** -- * Create a new instance. -- * @param context Reference count release responsibility is not transferred! The callee still owns this object. -- * @param alloc The allocator to use. -- * @param peerHost The peer host name. -- * @param peerPort The peer port. -- * @param leakDetection {@code true} to enable leak detection of this object. -- */ -- ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context, ByteBufAllocator alloc, String peerHost, -- int peerPort, boolean leakDetection) { -- super(peerHost, peerPort); -- OpenSsl.ensureAvailability(); -- leak = leakDetection ? leakDetector.track(this) : null; -- this.alloc = checkNotNull(alloc, "alloc"); -- apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator(); -- session = new OpenSslSession(context.sessionContext()); -- clientMode = context.isClient(); -- engineMap = context.engineMap; -- rejectRemoteInitiatedRenegotiation = context.getRejectRemoteInitiatedRenegotiation(); -- localCerts = context.keyCertChain; -- keyMaterialManager = context.keyMaterialManager(); -- enableOcsp = context.enableOcsp; +- OpenSslPopulatedKeyMaterialProvider( +- X509KeyManager keyManager, String password, Iterable<String> aliases) { +- super(keyManager, password); +- materialMap = new HashMap<String, Object>(); +- boolean initComplete = false; +- try { +- for (String alias: aliases) { +- if (alias != null && !materialMap.containsKey(alias)) { +- try { +- materialMap.put(alias, super.chooseKeyMaterial( +- UnpooledByteBufAllocator.DEFAULT, alias)); +- } catch (Exception e) { +- // Just store the exception and rethrow it when we try to choose the keymaterial +- // for this alias later on. +- materialMap.put(alias, e); +- } +- } +- } +- initComplete = true; +- } finally { +- if (!initComplete) { +- destroy(); +- } +- } +- if (materialMap.isEmpty()) { +- throw new IllegalArgumentException("aliases must be non-empty"); +- } +- } - -- Lock readerLock = context.ctxLock.readLock(); -- readerLock.lock(); -- try { -- ssl = SSL.newSSL(context.ctx, !context.isClient()); -- } finally { -- readerLock.unlock(); +- @Override +- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception { +- Object value = materialMap.get(alias); +- if (value == null) { +- // There is no keymaterial for the requested alias, return null +- return null; +- } +- if (value instanceof OpenSslKeyMaterial) { +- return ((OpenSslKeyMaterial) value).retain(); +- } +- throw (Exception) value; +- } +- +- @Override +- void destroy() { +- for (Object material: materialMap.values()) { +- ReferenceCountUtil.release(material); +- } +- materialMap.clear(); +- } +- } - } -- try { -- networkBIO = SSL.bioNewByteBuffer(ssl, context.getBioNonApplicationBufferSize()); +- } - -- // 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 : context.clientAuth); +- /** +- * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its {@link PrivateKey} directly from +- * an {@code OpenSSL engine} via the +- * <a href="https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_load_private_key.html">ENGINE_load_private_key</a> +- * function. +- */ +- public static OpenSslX509KeyManagerFactory newEngineBased(File certificateChain, String password) +- throws CertificateException, IOException, +- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { +- return newEngineBased(SslContext.toX509Certificates(certificateChain), password); +- } - -- if (context.protocols != null) { -- setEnabledProtocols(context.protocols); -- } +- /** +- * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its {@link PrivateKey} directly from +- * an {@code OpenSSL engine} via the +- * <a href="https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_load_private_key.html">ENGINE_load_private_key</a> +- * function. +- */ +- public static OpenSslX509KeyManagerFactory newEngineBased(X509Certificate[] certificateChain, String password) +- throws CertificateException, IOException, +- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { +- KeyStore store = new OpenSslKeyStore(certificateChain.clone(), false); +- store.load(null, null); +- OpenSslX509KeyManagerFactory factory = new OpenSslX509KeyManagerFactory(); +- factory.init(store, password == null ? null : password.toCharArray()); +- return factory; +- } - -- // Use SNI if peerHost was specified -- // See https://github.com/netty/netty/issues/4746 -- if (clientMode && peerHost != null) { -- SSL.setTlsExtHostName(ssl, peerHost); -- } +- /** +- * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[], String)}. +- */ +- public static OpenSslX509KeyManagerFactory newKeyless(File chain) +- throws CertificateException, IOException, +- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { +- return newKeyless(SslContext.toX509Certificates(chain)); +- } - -- if (enableOcsp) { -- SSL.enableOcsp(ssl); -- } -- } catch (Throwable cause) { -- SSL.freeSSL(ssl); -- PlatformDependent.throwException(cause); -- } +- /** +- * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[], String)}. +- */ +- public static OpenSslX509KeyManagerFactory newKeyless(InputStream chain) +- throws CertificateException, IOException, +- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { +- return newKeyless(SslContext.toX509Certificates(chain)); - } - - /** -- * Sets the OCSP response. +- * Returns a new initialized {@link OpenSslX509KeyManagerFactory} which will provide its private key by using the +- * {@link OpenSslPrivateKeyMethod}. - */ -- @UnstableApi -- public void setOcspResponse(byte[] response) { -- if (!enableOcsp) { -- throw new IllegalStateException("OCSP stapling is not enabled"); -- } +- public static OpenSslX509KeyManagerFactory newKeyless(X509Certificate... certificateChain) +- throws CertificateException, IOException, +- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { +- KeyStore store = new OpenSslKeyStore(certificateChain.clone(), true); +- store.load(null, null); +- OpenSslX509KeyManagerFactory factory = new OpenSslX509KeyManagerFactory(); +- factory.init(store, null); +- return factory; +- } - -- if (clientMode) { -- throw new IllegalStateException("Not a server SSLEngine"); -- } +- private static final class OpenSslKeyStore extends KeyStore { +- private OpenSslKeyStore(final X509Certificate[] certificateChain, final boolean keyless) { +- super(new KeyStoreSpi() { - -- synchronized (this) { -- SSL.setOcspResponse(ssl, response); +- private final Date creationDate = new Date(); +- +- @Override +- public Key engineGetKey(String alias, char[] password) throws UnrecoverableKeyException { +- if (engineContainsAlias(alias)) { +- final long privateKeyAddress; +- if (keyless) { +- privateKeyAddress = 0; +- } else { +- try { +- privateKeyAddress = SSL.loadPrivateKeyFromEngine( +- alias, password == null ? null : new String(password)); +- } catch (Exception e) { +- UnrecoverableKeyException keyException = +- new UnrecoverableKeyException("Unable to load key from engine"); +- keyException.initCause(e); +- throw keyException; +- } +- } +- return new OpenSslPrivateKey(privateKeyAddress); +- } +- return null; +- } +- +- @Override +- public Certificate[] engineGetCertificateChain(String alias) { +- return engineContainsAlias(alias)? certificateChain.clone() : null; +- } +- +- @Override +- public Certificate engineGetCertificate(String alias) { +- return engineContainsAlias(alias)? certificateChain[0] : null; +- } +- +- @Override +- public Date engineGetCreationDate(String alias) { +- return engineContainsAlias(alias)? creationDate : null; +- } +- +- @Override +- public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) +- throws KeyStoreException { +- throw new KeyStoreException("Not supported"); +- } +- +- @Override +- public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException { +- throw new KeyStoreException("Not supported"); +- } +- +- @Override +- public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException { +- throw new KeyStoreException("Not supported"); +- } +- +- @Override +- public void engineDeleteEntry(String alias) throws KeyStoreException { +- throw new KeyStoreException("Not supported"); +- } +- +- @Override +- public Enumeration<String> engineAliases() { +- return Collections.enumeration(Collections.singleton(SslContext.ALIAS)); +- } +- +- @Override +- public boolean engineContainsAlias(String alias) { +- return SslContext.ALIAS.equals(alias); +- } +- +- @Override +- public int engineSize() { +- return 1; +- } +- +- @Override +- public boolean engineIsKeyEntry(String alias) { +- return engineContainsAlias(alias); +- } +- +- @Override +- public boolean engineIsCertificateEntry(String alias) { +- return engineContainsAlias(alias); +- } +- +- @Override +- public String engineGetCertificateAlias(Certificate cert) { +- if (cert instanceof X509Certificate) { +- for (X509Certificate x509Certificate : certificateChain) { +- if (x509Certificate.equals(cert)) { +- return SslContext.ALIAS; +- } +- } +- } +- return null; +- } +- +- @Override +- public void engineStore(OutputStream stream, char[] password) { +- throw new UnsupportedOperationException(); +- } +- +- @Override +- public void engineLoad(InputStream stream, char[] password) { +- if (stream != null && password != null) { +- throw new UnsupportedOperationException(); +- } +- } +- }, null, "native"); +- +- OpenSsl.ensureAvailability(); - } - } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java +deleted file mode 100644 +index 6b945506b9..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java ++++ /dev/null +@@ -1,343 +0,0 @@ +-/* +- * 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.internal.tcnative.CertificateCallback; +-import io.netty.util.internal.SuppressJava6Requirement; +-import io.netty.util.internal.SystemPropertyUtil; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +- +-import java.security.KeyStore; +-import java.security.PrivateKey; +-import java.security.cert.X509Certificate; +- +-import java.util.Arrays; +-import java.util.Collections; +-import java.util.HashSet; +-import java.util.LinkedHashSet; +-import java.util.Set; - -- /** -- * Returns the OCSP response or {@code null} if the server didn't provide a stapled OCSP response. -- */ -- @UnstableApi -- public byte[] getOcspResponse() { -- if (!enableOcsp) { -- throw new IllegalStateException("OCSP stapling is not enabled"); -- } +-import javax.net.ssl.KeyManagerFactory; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.TrustManagerFactory; +-import javax.net.ssl.X509ExtendedTrustManager; +-import javax.net.ssl.X509TrustManager; +-import javax.security.auth.x500.X500Principal; - -- if (!clientMode) { -- throw new IllegalStateException("Not a client SSLEngine"); -- } +-/** +- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- * <p>Instances of this class must be {@link #release() released} or else native memory will leak! +- * +- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine} +- * which depends upon the instance of this class is released. Otherwise if any method of +- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. +- */ +-public final class ReferenceCountedOpenSslClientContext extends ReferenceCountedOpenSslContext { +- private static final InternalLogger logger = +- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class); +- private static final Set<String> SUPPORTED_KEY_TYPES = Collections.unmodifiableSet(new LinkedHashSet<String>( +- Arrays.asList(OpenSslKeyMaterialManager.KEY_TYPE_RSA, +- OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA, +- OpenSslKeyMaterialManager.KEY_TYPE_EC, +- OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA, +- OpenSslKeyMaterialManager.KEY_TYPE_EC_EC))); +- private static final boolean ENABLE_SESSION_TICKET = +- SystemPropertyUtil.getBoolean("jdk.tls.client.enableSessionTicketExtension", false); +- private final OpenSslSessionContext sessionContext; - -- synchronized (this) { -- return SSL.getOcspResponse(ssl); +- ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, +- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- String[] protocols, long sessionCacheSize, long sessionTimeout, +- boolean enableOcsp, String keyStore) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, +- ClientAuth.NONE, protocols, false, enableOcsp, true); +- boolean success = false; +- try { +- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, +- keyCertChain, key, keyPassword, keyManagerFactory, keyStore); +- if (ENABLE_SESSION_TICKET) { +- sessionContext.setTicketKeys(); +- } +- success = true; +- } finally { +- if (!success) { +- release(); +- } - } - } - - @Override -- public final int refCnt() { -- return refCnt.refCnt(); -- } -- -- @Override -- public final ReferenceCounted retain() { -- refCnt.retain(); -- return this; +- public OpenSslSessionContext sessionContext() { +- return sessionContext; - } - -- @Override -- public final ReferenceCounted retain(int increment) { -- refCnt.retain(increment); -- return this; -- } +- static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx, +- OpenSslEngineMap engineMap, +- X509Certificate[] trustCertCollection, +- TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, +- String keyPassword, KeyManagerFactory keyManagerFactory, +- String keyStore) throws SSLException { +- if (key == null && keyCertChain != null || key != null && keyCertChain == null) { +- throw new IllegalArgumentException( +- "Either both keyCertChain and key needs to be null or none of them"); +- } +- OpenSslKeyMaterialProvider keyMaterialProvider = null; +- try { +- try { +- if (!OpenSsl.useKeyManagerFactory()) { +- if (keyManagerFactory != null) { +- throw new IllegalArgumentException( +- "KeyManagerFactory not supported"); +- } +- if (keyCertChain != null/* && key != null*/) { +- setKeyMaterial(ctx, keyCertChain, key, keyPassword); +- } +- } else { +- // javadocs state that keyManagerFactory has precedent over keyCertChain +- if (keyManagerFactory == null && keyCertChain != null) { +- char[] keyPasswordChars = keyStorePassword(keyPassword); +- KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore); +- if (ks.aliases().hasMoreElements()) { +- keyManagerFactory = new OpenSslX509KeyManagerFactory(); +- } else { +- keyManagerFactory = new OpenSslCachingX509KeyManagerFactory( +- KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())); +- } +- keyManagerFactory.init(ks, keyPasswordChars); +- keyMaterialProvider = providerFor(keyManagerFactory, keyPassword); +- } else if (keyManagerFactory != null) { +- keyMaterialProvider = providerFor(keyManagerFactory, keyPassword); +- } - -- @Override -- public final ReferenceCounted touch() { -- refCnt.touch(); -- return this; -- } +- if (keyMaterialProvider != null) { +- OpenSslKeyMaterialManager materialManager = new OpenSslKeyMaterialManager(keyMaterialProvider); +- SSLContext.setCertificateCallback(ctx, new OpenSslClientCertificateCallback( +- engineMap, materialManager)); +- } +- } +- } catch (Exception e) { +- throw new SSLException("failed to set certificate and key", e); +- } - -- @Override -- public final ReferenceCounted touch(Object hint) { -- refCnt.touch(hint); -- return this; -- } +- // On the client side we always need to use SSL_CVERIFY_OPTIONAL (which will translate to SSL_VERIFY_PEER) +- // to ensure that when the TrustManager throws we will produce the correct alert back to the server. +- // +- // See: +- // - https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html +- // - https://github.com/netty/netty/issues/8942 +- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_OPTIONAL, VERIFY_DEPTH); - -- @Override -- public final boolean release() { -- return refCnt.release(); -- } +- try { +- if (trustCertCollection != null) { +- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore); +- } else if (trustManagerFactory == null) { +- trustManagerFactory = TrustManagerFactory.getInstance( +- TrustManagerFactory.getDefaultAlgorithm()); +- trustManagerFactory.init((KeyStore) null); +- } +- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); - -- @Override -- public final boolean release(int decrement) { -- return refCnt.release(decrement); -- } +- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as +- // otherwise the context can never be collected. This is because the JNI code holds +- // a global reference to the callbacks. +- // +- // See https://github.com/netty/netty/issues/5372 - -- @Override -- public final synchronized SSLSession getHandshakeSession() { -- // Javadocs state return value should be: -- // null if this instance is not currently handshaking, or if the current handshake has not -- // progressed far enough to create a basic SSLSession. Otherwise, this method returns the -- // SSLSession currently being negotiated. -- switch(handshakeState) { -- case NOT_STARTED: -- case FINISHED: -- return null; -- default: -- return session; +- setVerifyCallback(ctx, engineMap, manager); +- } catch (Exception e) { +- if (keyMaterialProvider != null) { +- keyMaterialProvider.destroy(); +- } +- throw new SSLException("unable to setup trustmanager", e); +- } +- OpenSslClientSessionContext context = new OpenSslClientSessionContext(thiz, keyMaterialProvider); +- keyMaterialProvider = null; +- return context; +- } finally { +- if (keyMaterialProvider != null) { +- keyMaterialProvider.destroy(); +- } - } - } - -- /** -- * Returns the pointer to the {@code SSL} object for this {@link ReferenceCountedOpenSslEngine}. -- * Be aware that it is freed as soon as the {@link #release()} or {@link #shutdown()} methods are called. -- * At this point {@code 0} will be returned. -- */ -- public final synchronized long sslPointer() { -- return ssl; +- @SuppressJava6Requirement(reason = "Guarded by java version check") +- private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap, X509TrustManager manager) { +- // Use this to prevent an error when running on java < 7 +- if (useExtendedTrustManager(manager)) { +- SSLContext.setCertVerifyCallback(ctx, +- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager)); +- } else { +- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager)); +- } - } - -- /** -- * Destroys this engine. -- */ -- public final synchronized void shutdown() { -- if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) { -- engineMap.remove(ssl); -- SSL.freeSSL(ssl); -- ssl = networkBIO = 0; -- -- isInboundDone = outboundClosed = true; +- // No cache is currently supported for client side mode. +- static final class OpenSslClientSessionContext extends OpenSslSessionContext { +- OpenSslClientSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) { +- super(context, provider); - } - -- // On shutdown clear all errors -- SSL.clearError(); -- } +- @Override +- public void setSessionTimeout(int seconds) { +- if (seconds < 0) { +- throw new IllegalArgumentException(); +- } +- } - -- /** -- * Write plaintext data to the OpenSSL internal BIO -- * -- * Calling this function with src.remaining == 0 is undefined. -- */ -- private int writePlaintextData(final ByteBuffer src, int len) { -- final int pos = src.position(); -- final int limit = src.limit(); -- final int sslWrote; +- @Override +- public int getSessionTimeout() { +- return 0; +- } - -- if (src.isDirect()) { -- sslWrote = SSL.writeToSSL(ssl, Buffer.address(src) + pos, len); -- if (sslWrote > 0) { -- src.position(pos + sslWrote); +- @Override +- public void setSessionCacheSize(int size) { +- if (size < 0) { +- throw new IllegalArgumentException(); - } -- } else { -- ByteBuf buf = alloc.directBuffer(len); -- try { -- src.limit(pos + len); +- } - -- buf.setBytes(0, src); -- src.limit(limit); +- @Override +- public int getSessionCacheSize() { +- return 0; +- } - -- sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len); -- if (sslWrote > 0) { -- src.position(pos + sslWrote); -- } else { -- src.position(pos); -- } -- } finally { -- buf.release(); -- } +- @Override +- public void setSessionCacheEnabled(boolean enabled) { +- // ignored +- } +- +- @Override +- public boolean isSessionCacheEnabled() { +- return false; - } -- return sslWrote; - } - -- /** -- * Write encrypted data to the OpenSSL network BIO. -- */ -- private ByteBuf writeEncryptedData(final ByteBuffer src, int len) { -- final int pos = src.position(); -- if (src.isDirect()) { -- SSL.bioSetByteBuffer(networkBIO, Buffer.address(src) + pos, len, false); -- } else { -- final ByteBuf buf = alloc.directBuffer(len); -- try { -- final int limit = src.limit(); -- src.limit(pos + len); -- buf.writeBytes(src); -- // Restore the original position and limit because we don't want to consume from `src`. -- src.position(pos); -- src.limit(limit); +- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier { +- private final X509TrustManager manager; - -- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false); -- return buf; -- } catch (Throwable cause) { -- buf.release(); -- PlatformDependent.throwException(cause); -- } +- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) { +- super(engineMap); +- this.manager = manager; - } -- return null; -- } - -- /** -- * Read plaintext data from the OpenSSL internal BIO -- */ -- private int readPlaintextData(final ByteBuffer dst) { -- final int sslRead; -- final int pos = dst.position(); -- if (dst.isDirect()) { -- sslRead = SSL.readFromSSL(ssl, Buffer.address(dst) + pos, dst.limit() - pos); -- if (sslRead > 0) { -- dst.position(pos + sslRead); -- } -- } else { -- final int limit = dst.limit(); -- final int len = min(MAX_ENCRYPTED_PACKET_LENGTH, limit - pos); -- final ByteBuf buf = alloc.directBuffer(len); -- try { -- sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len); -- if (sslRead > 0) { -- dst.limit(pos + sslRead); -- buf.getBytes(buf.readerIndex(), dst); -- dst.limit(limit); -- } -- } finally { -- buf.release(); -- } +- @Override +- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) +- throws Exception { +- manager.checkServerTrusted(peerCerts, auth); - } -- -- return sslRead; - } - -- @Override -- public final SSLEngineResult wrap( -- final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst) throws SSLException { -- // Throw required runtime exceptions -- if (srcs == null) { -- throw new IllegalArgumentException("srcs is null"); -- } -- if (dst == null) { -- throw new IllegalArgumentException("dst is null"); +- @SuppressJava6Requirement(reason = "Usage guarded by java version check") +- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier { +- private final X509ExtendedTrustManager manager; +- +- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) { +- super(engineMap); +- this.manager = OpenSslTlsv13X509ExtendedTrustManager.wrap(manager); - } - -- if (offset >= srcs.length || offset + length > srcs.length) { -- throw new IndexOutOfBoundsException( -- "offset: " + offset + ", length: " + length + -- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))"); +- @Override +- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) +- throws Exception { +- manager.checkServerTrusted(peerCerts, auth, engine); - } +- } - -- if (dst.isReadOnly()) { -- throw new ReadOnlyBufferException(); +- private static final class OpenSslClientCertificateCallback implements CertificateCallback { +- private final OpenSslEngineMap engineMap; +- private final OpenSslKeyMaterialManager keyManagerHolder; +- +- OpenSslClientCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) { +- this.engineMap = engineMap; +- this.keyManagerHolder = keyManagerHolder; - } - -- synchronized (this) { -- if (isOutboundDone()) { -- // All drained in the outbound buffer -- return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_UNWRAP_CLOSED; +- @Override +- public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception { +- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); +- // May be null if it was destroyed in the meantime. +- if (engine == null) { +- return; - } -- -- int bytesProduced = 0; -- ByteBuf bioReadCopyBuf = null; - try { -- // Setup the BIO buffer so that we directly write the encryption results into dst. -- if (dst.isDirect()) { -- SSL.bioSetByteBuffer(networkBIO, Buffer.address(dst) + dst.position(), dst.remaining(), -- true); +- final Set<String> keyTypesSet = supportedClientKeyTypes(keyTypeBytes); +- final String[] keyTypes = keyTypesSet.toArray(new String[0]); +- final X500Principal[] issuers; +- if (asn1DerEncodedPrincipals == null) { +- issuers = null; - } else { -- bioReadCopyBuf = alloc.directBuffer(dst.remaining()); -- SSL.bioSetByteBuffer(networkBIO, memoryAddress(bioReadCopyBuf), bioReadCopyBuf.writableBytes(), -- true); -- } -- -- int bioLengthBefore = SSL.bioLengthByteBuffer(networkBIO); -- -- // Explicit use outboundClosed as we want to drain any bytes that are still present. -- if (outboundClosed) { -- // There is something left to drain. -- // See https://github.com/netty/netty/issues/6260 -- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); -- if (bytesProduced <= 0) { -- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0); -- } -- // It is possible when the outbound was closed there was not enough room in the non-application -- // buffers to hold the close_notify. We should keep trying to close until we consume all the data -- // OpenSSL can give us. -- if (!doSSLShutdown()) { -- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, bytesProduced); +- issuers = new X500Principal[asn1DerEncodedPrincipals.length]; +- for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) { +- issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]); - } -- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO); -- return newResultMayFinishHandshake(NEED_WRAP, 0, bytesProduced); - } +- keyManagerHolder.setKeyMaterialClientSide(engine, keyTypes, issuers); +- } catch (Throwable cause) { +- logger.debug("request of key failed", cause); +- engine.initHandshakeException(cause); +- } +- } - -- // Flush any data that may be implicitly generated by OpenSSL (handshake, close, etc..). -- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING; -- // Prepare OpenSSL to work in server mode and receive handshake -- if (handshakeState != HandshakeState.FINISHED) { -- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) { -- // Update accepted so we know we triggered the handshake via wrap -- handshakeState = HandshakeState.STARTED_IMPLICITLY; -- } -- -- // Flush any data that may have been written implicitly during the handshake by OpenSSL. -- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); -- -- if (bytesProduced > 0 && handshakeException != null) { -- // TODO(scott): It is possible that when the handshake failed there was not enough room in the -- // non-application buffers to hold the alert. We should get all the data before progressing on. -- // However I'm not aware of a way to do this with the OpenSSL APIs. -- // See https://github.com/netty/netty/issues/6385. -- -- // We produced / consumed some data during the handshake, signal back to the caller. -- // If there is a handshake exception and we have produced data, we should send the data before -- // we allow handshake() to throw the handshake exception. -- return newResult(NEED_WRAP, 0, bytesProduced); -- } -- -- status = handshake(); +- /** +- * Gets the supported key types for client certificates. +- * +- * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server. +- * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml. +- * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and +- * {@code X509ExtendedKeyManager.chooseEngineClientAlias}. +- */ +- private static Set<String> supportedClientKeyTypes(byte[] clientCertificateTypes) { +- if (clientCertificateTypes == null) { +- // Try all of the supported key types. +- return SUPPORTED_KEY_TYPES; +- } +- Set<String> result = new HashSet<String>(clientCertificateTypes.length); +- for (byte keyTypeCode : clientCertificateTypes) { +- String keyType = clientKeyType(keyTypeCode); +- if (keyType == null) { +- // Unsupported client key type -- ignore +- continue; +- } +- result.add(keyType); +- } +- return result; +- } - -- if (renegotiationPending && status == FINISHED) { -- // If renegotiationPending is true that means when we attempted to start renegotiation -- // the BIO buffer didn't have enough space to hold the HelloRequest which prompts the -- // client to initiate a renegotiation. At this point the HelloRequest has been written -- // so we can actually start the handshake process. -- renegotiationPending = false; -- SSL.setState(ssl, SSL.SSL_ST_ACCEPT); -- handshakeState = HandshakeState.STARTED_EXPLICITLY; -- status = handshake(); -- } +- private static String clientKeyType(byte clientCertificateType) { +- // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml +- switch (clientCertificateType) { +- case CertificateCallback.TLS_CT_RSA_SIGN: +- return OpenSslKeyMaterialManager.KEY_TYPE_RSA; // RFC rsa_sign +- case CertificateCallback.TLS_CT_RSA_FIXED_DH: +- return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh +- case CertificateCallback.TLS_CT_ECDSA_SIGN: +- return OpenSslKeyMaterialManager.KEY_TYPE_EC; // RFC ecdsa_sign +- case CertificateCallback.TLS_CT_RSA_FIXED_ECDH: +- return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh +- case CertificateCallback.TLS_CT_ECDSA_FIXED_ECDH: +- return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh +- default: +- return null; +- } +- } +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java +deleted file mode 100644 +index 27eb43574c..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java ++++ /dev/null +@@ -1,968 +0,0 @@ +-/* +- * 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; - -- // Handshake may have generated more data, for example if the internal SSL buffer is small -- // we may have freed up space by flushing above. -- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO); +-import io.netty.buffer.ByteBuf; +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.internal.tcnative.CertificateVerifier; +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +-import io.netty.internal.tcnative.SSLPrivateKeyMethod; +-import io.netty.util.AbstractReferenceCounted; +-import io.netty.util.ReferenceCounted; +-import io.netty.util.ResourceLeakDetector; +-import io.netty.util.ResourceLeakDetectorFactory; +-import io.netty.util.ResourceLeakTracker; +-import io.netty.util.internal.ObjectUtil; +-import io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.StringUtil; +-import io.netty.util.internal.SuppressJava6Requirement; +-import io.netty.util.internal.SystemPropertyUtil; +-import io.netty.util.internal.UnstableApi; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; - -- if (bytesProduced > 0) { -- // If we have filled up the dst buffer and we have not finished the handshake we should try to -- // wrap again. Otherwise we should only try to wrap again if there is still data pending in -- // SSL buffers. -- return newResult(mayFinishHandshake(status != FINISHED ? -- bytesProduced == bioLengthBefore ? NEED_WRAP : -- getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) : FINISHED), -- 0, bytesProduced); -- } +-import java.security.PrivateKey; +-import java.security.SignatureException; +-import java.security.cert.CertPathValidatorException; +-import java.security.cert.Certificate; +-import java.security.cert.CertificateExpiredException; +-import java.security.cert.CertificateNotYetValidException; +-import java.security.cert.CertificateRevokedException; +-import java.security.cert.X509Certificate; +-import java.util.Arrays; +-import java.util.Collections; +-import java.util.List; +-import java.util.Map; +-import java.util.concurrent.Executor; +-import java.util.concurrent.locks.Lock; +-import java.util.concurrent.locks.ReadWriteLock; +-import java.util.concurrent.locks.ReentrantReadWriteLock; - -- if (status == NEED_UNWRAP) { -- // Signal if the outbound is done or not. -- return isOutboundDone() ? NEED_UNWRAP_CLOSED : NEED_UNWRAP_OK; -- } +-import javax.net.ssl.KeyManager; +-import javax.net.ssl.KeyManagerFactory; +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.SSLHandshakeException; +-import javax.net.ssl.TrustManager; +-import javax.net.ssl.X509ExtendedTrustManager; +-import javax.net.ssl.X509KeyManager; +-import javax.net.ssl.X509TrustManager; - -- // Explicit use outboundClosed and not outboundClosed() as we want to drain any bytes that are -- // still present. -- if (outboundClosed) { -- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); -- return newResultMayFinishHandshake(status, 0, bytesProduced); -- } -- } +-import static io.netty.handler.ssl.OpenSsl.DEFAULT_CIPHERS; +-import static io.netty.handler.ssl.OpenSsl.availableJavaCipherSuites; +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero; - -- int srcsLen = 0; -- final int endOffset = offset + length; -- for (int i = offset; i < endOffset; ++i) { -- final ByteBuffer src = srcs[i]; -- if (src == null) { -- throw new IllegalArgumentException("srcs[" + i + "] is null"); -- } -- if (srcsLen == MAX_PLAINTEXT_LENGTH) { -- continue; -- } +-/** +- * An implementation of {@link SslContext} which works with libraries that support the +- * <a href="https://www.openssl.org/">OpenSsl</a> C library API. +- * <p>Instances of this class must be {@link #release() released} or else native memory will leak! +- * +- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine} +- * which depends upon the instance of this class is released. Otherwise if any method of +- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. +- */ +-public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted { +- private static final InternalLogger logger = +- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class); - -- srcsLen += src.remaining(); -- if (srcsLen > MAX_PLAINTEXT_LENGTH || srcsLen < 0) { -- // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to MAX_PLAINTEXT_LENGTH. -- // This also help us to guard against overflow. -- // We not break out here as we still need to check for null entries in srcs[]. -- srcsLen = MAX_PLAINTEXT_LENGTH; -- } -- } +- private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE = Math.max(1, +- SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize", +- 2048)); +- static final boolean USE_TASKS = +- SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.useTasks", false); +- private static final Integer DH_KEY_LENGTH; +- private static final ResourceLeakDetector<ReferenceCountedOpenSslContext> leakDetector = +- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class); - -- // we will only produce a single TLS packet, and we don't aggregate src buffers, -- // so we always fix the number of buffers to 1 when checking if the dst buffer is large enough. -- if (dst.remaining() < calculateOutNetBufSize(srcsLen, 1)) { -- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0); -- } +- // TODO: Maybe make configurable ? +- protected static final int VERIFY_DEPTH = 10; - -- // There was no pending data in the network BIO -- encrypt any application data -- int bytesConsumed = 0; -- // Flush any data that may have been written implicitly by OpenSSL in case a shutdown/alert occurs. -- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); -- for (; offset < endOffset; ++offset) { -- final ByteBuffer src = srcs[offset]; -- final int remaining = src.remaining(); -- if (remaining == 0) { -- continue; -- } +- /** +- * The OpenSSL SSL_CTX object. +- * +- * <strong>{@link #ctxLock} must be hold while using ctx!</strong> +- */ +- protected long ctx; +- private final List<String> unmodifiableCiphers; +- private final long sessionCacheSize; +- private final long sessionTimeout; +- private final OpenSslApplicationProtocolNegotiator apn; +- private final int mode; - -- // Write plaintext application data to the SSL engine -- int bytesWritten = writePlaintextData(src, min(remaining, MAX_PLAINTEXT_LENGTH - bytesConsumed)); +- // Reference Counting +- private final ResourceLeakTracker<ReferenceCountedOpenSslContext> leak; +- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { +- @Override +- public ReferenceCounted touch(Object hint) { +- if (leak != null) { +- leak.record(hint); +- } - -- if (bytesWritten > 0) { -- bytesConsumed += bytesWritten; +- return ReferenceCountedOpenSslContext.this; +- } - -- // Determine how much encrypted data was generated: -- final int pendingNow = SSL.bioLengthByteBuffer(networkBIO); -- bytesProduced += bioLengthBefore - pendingNow; -- bioLengthBefore = pendingNow; +- @Override +- protected void deallocate() { +- destroy(); +- if (leak != null) { +- boolean closed = leak.close(ReferenceCountedOpenSslContext.this); +- assert closed; +- } +- } +- }; - -- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced); -- } else { -- int sslError = SSL.getError(ssl, bytesWritten); -- if (sslError == SSL.SSL_ERROR_ZERO_RETURN) { -- // This means the connection was shutdown correctly, close inbound and outbound -- if (!receivedShutdown) { -- closeAll(); +- final Certificate[] keyCertChain; +- final ClientAuth clientAuth; +- final String[] protocols; +- final boolean enableOcsp; +- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap(); +- final ReadWriteLock ctxLock = new ReentrantReadWriteLock(); - -- bytesProduced += bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO); +- private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE; - -- // If we have filled up the dst buffer and we have not finished the handshake we should -- // try to wrap again. Otherwise we should only try to wrap again if there is still data -- // pending in SSL buffers. -- SSLEngineResult.HandshakeStatus hs = mayFinishHandshake( -- status != FINISHED ? bytesProduced == dst.remaining() ? NEED_WRAP -- : getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) -- : FINISHED); -- return newResult(hs, bytesConsumed, bytesProduced); -- } +- @SuppressWarnings("deprecation") +- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR = +- new OpenSslApplicationProtocolNegotiator() { +- @Override +- public ApplicationProtocolConfig.Protocol protocol() { +- return ApplicationProtocolConfig.Protocol.NONE; +- } - -- return newResult(NOT_HANDSHAKING, bytesConsumed, bytesProduced); -- } else if (sslError == SSL.SSL_ERROR_WANT_READ) { -- // If there is no pending data to read from BIO we should go back to event loop and try -- // to read more data [1]. It is also possible that event loop will detect the socket has -- // been closed. [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html -- return newResult(NEED_UNWRAP, bytesConsumed, bytesProduced); -- } else if (sslError == SSL.SSL_ERROR_WANT_WRITE) { -- // SSL_ERROR_WANT_WRITE typically means that the underlying transport is not writable -- // and we should set the "want write" flag on the selector and try again when the -- // underlying transport is writable [1]. However we are not directly writing to the -- // underlying transport and instead writing to a BIO buffer. The OpenSsl documentation -- // says we should do the following [1]: -- // -- // "When using a buffering BIO, like a BIO pair, data must be written into or retrieved -- // out of the BIO before being able to continue." -- // -- // So we attempt to drain the BIO buffer below, but if there is no data this condition -- // is undefined and we assume their is a fatal error with the openssl engine and close. -- // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html -- return newResult(NEED_WRAP, bytesConsumed, bytesProduced); -- } else { -- // Everything else is considered as error -- throw shutdownWithError("SSL_write"); -- } -- } +- @Override +- public List<String> protocols() { +- return Collections.emptyList(); - } -- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced); -- } finally { -- SSL.bioClearByteBuffer(networkBIO); -- if (bioReadCopyBuf == null) { -- dst.position(dst.position() + bytesProduced); -- } else { -- assert bioReadCopyBuf.readableBytes() <= dst.remaining() : "The destination buffer " + dst + -- " didn't have enough remaining space to hold the encrypted content in " + bioReadCopyBuf; -- dst.put(bioReadCopyBuf.internalNioBuffer(bioReadCopyBuf.readerIndex(), bytesProduced)); -- bioReadCopyBuf.release(); +- +- @Override +- public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() { +- return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL; - } -- } -- } -- } - -- private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int bytesConsumed, int bytesProduced) { -- return newResult(OK, hs, bytesConsumed, bytesProduced); -- } +- @Override +- public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() { +- return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT; +- } +- }; - -- private SSLEngineResult newResult(SSLEngineResult.Status status, SSLEngineResult.HandshakeStatus hs, -- int bytesConsumed, int bytesProduced) { -- // If isOutboundDone, then the data from the network BIO -- // was the close_notify message and all was consumed we are not required to wait -- // for the receipt the peer's close_notify message -- shutdown. -- if (isOutboundDone()) { -- if (isInboundDone()) { -- // If the inbound was done as well, we need to ensure we return NOT_HANDSHAKING to signal we are done. -- hs = NOT_HANDSHAKING; +- static { +- Integer dhLen = null; - -- // As the inbound and the outbound is done we can shutdown the engine now. -- shutdown(); +- try { +- String dhKeySize = SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize"); +- if (dhKeySize != null) { +- try { +- dhLen = Integer.valueOf(dhKeySize); +- } catch (NumberFormatException e) { +- logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: " +- + dhKeySize); +- } - } -- return new SSLEngineResult(CLOSED, hs, bytesConsumed, bytesProduced); +- } catch (Throwable ignore) { +- // ignore - } -- return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced); +- DH_KEY_LENGTH = dhLen; - } - -- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus hs, -- int bytesConsumed, int bytesProduced) throws SSLException { -- return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED), -- bytesConsumed, bytesProduced); +- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, +- ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout, +- int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols, +- boolean startTls, boolean enableOcsp, boolean leakDetection) throws SSLException { +- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain, +- clientAuth, protocols, startTls, enableOcsp, leakDetection); - } - -- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status, -- SSLEngineResult.HandshakeStatus hs, -- int bytesConsumed, int bytesProduced) throws SSLException { -- return newResult(status, mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED), -- bytesConsumed, bytesProduced); -- } +- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, +- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, +- long sessionTimeout, int mode, Certificate[] keyCertChain, +- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp, +- boolean leakDetection) throws SSLException { +- super(startTls); - -- /** -- * Log the error, shutdown the engine and throw an exception. -- */ -- private SSLException shutdownWithError(String operations) { -- String err = SSL.getLastError(); -- return shutdownWithError(operations, err); -- } +- OpenSsl.ensureAvailability(); - -- private SSLException shutdownWithError(String operation, String err) { -- if (logger.isDebugEnabled()) { -- logger.debug("{} failed: OpenSSL error: {}", operation, err); +- if (enableOcsp && !OpenSsl.isOcspSupported()) { +- throw new IllegalStateException("OCSP is not supported."); - } - -- // There was an internal error -- shutdown -- shutdown(); -- if (handshakeState == HandshakeState.FINISHED) { -- return new SSLException(err); +- if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) { +- throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT"); - } -- return new SSLHandshakeException(err); -- } +- leak = leakDetection ? leakDetector.track(this) : null; +- this.mode = mode; +- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE; +- this.protocols = protocols; +- this.enableOcsp = enableOcsp; - -- public final SSLEngineResult unwrap( -- final ByteBuffer[] srcs, int srcsOffset, final int srcsLength, -- final ByteBuffer[] dsts, int dstsOffset, final int dstsLength) throws SSLException { +- this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone(); - -- // Throw required runtime exceptions -- if (srcs == null) { -- throw new NullPointerException("srcs"); -- } -- if (srcsOffset >= srcs.length -- || srcsOffset + srcsLength > srcs.length) { -- throw new IndexOutOfBoundsException( -- "offset: " + srcsOffset + ", length: " + srcsLength + -- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))"); -- } -- if (dsts == null) { -- throw new IllegalArgumentException("dsts is null"); -- } -- if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) { -- throw new IndexOutOfBoundsException( -- "offset: " + dstsOffset + ", length: " + dstsLength + -- " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))"); -- } -- long capacity = 0; -- final int dstsEndOffset = dstsOffset + dstsLength; -- for (int i = dstsOffset; i < dstsEndOffset; i ++) { -- ByteBuffer dst = dsts[i]; -- if (dst == null) { -- throw new IllegalArgumentException("dsts[" + i + "] is null"); -- } -- if (dst.isReadOnly()) { -- throw new ReadOnlyBufferException(); +- unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites( +- ciphers, DEFAULT_CIPHERS, availableJavaCipherSuites())); +- +- this.apn = checkNotNull(apn, "apn"); +- +- // Create a new SSL_CTX and configure it. +- boolean success = false; +- try { +- try { +- int protocolOpts = SSL.SSL_PROTOCOL_SSLV3 | SSL.SSL_PROTOCOL_TLSV1 | +- SSL.SSL_PROTOCOL_TLSV1_1 | SSL.SSL_PROTOCOL_TLSV1_2; +- if (OpenSsl.isTlsv13Supported()) { +- protocolOpts |= SSL.SSL_PROTOCOL_TLSV1_3; +- } +- ctx = SSLContext.make(protocolOpts, mode); +- } catch (Exception e) { +- throw new SSLException("failed to create an SSL_CTX", e); - } -- capacity += dst.remaining(); -- } - -- final int srcsEndOffset = srcsOffset + srcsLength; -- long len = 0; -- for (int i = srcsOffset; i < srcsEndOffset; i++) { -- ByteBuffer src = srcs[i]; -- if (src == null) { -- throw new IllegalArgumentException("srcs[" + i + "] is null"); +- boolean tlsv13Supported = OpenSsl.isTlsv13Supported(); +- StringBuilder cipherBuilder = new StringBuilder(); +- StringBuilder cipherTLSv13Builder = new StringBuilder(); +- +- /* List the ciphers that are permitted to negotiate. */ +- try { +- if (unmodifiableCiphers.isEmpty()) { +- // Set non TLSv1.3 ciphers. +- SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, false); +- if (tlsv13Supported) { +- // Set TLSv1.3 ciphers. +- SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, true); +- } +- } else { +- CipherSuiteConverter.convertToCipherStrings( +- unmodifiableCiphers, cipherBuilder, cipherTLSv13Builder, OpenSsl.isBoringSSL()); +- +- // Set non TLSv1.3 ciphers. +- SSLContext.setCipherSuite(ctx, cipherBuilder.toString(), false); +- if (tlsv13Supported) { +- // Set TLSv1.3 ciphers. +- SSLContext.setCipherSuite(ctx, cipherTLSv13Builder.toString(), true); +- } +- } +- } catch (SSLException e) { +- throw e; +- } catch (Exception e) { +- throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e); - } -- len += src.remaining(); -- } - -- synchronized (this) { -- if (isInboundDone()) { -- return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_WRAP_CLOSED; +- int options = SSLContext.getOptions(ctx) | +- SSL.SSL_OP_NO_SSLv2 | +- SSL.SSL_OP_NO_SSLv3 | +- // Disable TLSv1.3 by default for now. Even if TLSv1.3 is not supported this will +- // work fine as in this case SSL_OP_NO_TLSv1_3 will be 0. +- SSL.SSL_OP_NO_TLSv1_3 | +- +- SSL.SSL_OP_CIPHER_SERVER_PREFERENCE | +- +- // We do not support compression at the moment so we should explicitly disable it. +- SSL.SSL_OP_NO_COMPRESSION | +- +- // Disable ticket support by default to be more inline with SSLEngineImpl of the JDK. +- // This also let SSLSession.getId() work the same way for the JDK implementation and the +- // OpenSSLEngine. If tickets are supported SSLSession.getId() will only return an ID on the +- // server-side if it could make use of tickets. +- SSL.SSL_OP_NO_TICKET; +- +- if (cipherBuilder.length() == 0) { +- // No ciphers that are compatible with SSLv2 / SSLv3 / TLSv1 / TLSv1.1 / TLSv1.2 +- options |= SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 +- | SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2; - } - -- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING; -- // Prepare OpenSSL to work in server mode and receive handshake -- if (handshakeState != HandshakeState.FINISHED) { -- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) { -- // Update accepted so we know we triggered the handshake via wrap -- handshakeState = HandshakeState.STARTED_IMPLICITLY; -- } +- SSLContext.setOptions(ctx, options); +- +- // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between +- // calling OpenSSLEngine.wrap(...). +- // See https://github.com/netty/netty-tcnative/issues/100 +- SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - -- status = handshake(); -- if (status == NEED_WRAP) { -- return NEED_WRAP_OK; -- } -- // Check if the inbound is considered to be closed if so let us try to wrap again. -- if (isInboundDone) { -- return NEED_WRAP_CLOSED; -- } +- if (DH_KEY_LENGTH != null) { +- SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH); - } - -- if (len < SSL_RECORD_HEADER_LENGTH) { -- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0); +- List<String> nextProtoList = apn.protocols(); +- /* Set next protocols for next protocol negotiation extension, if specified */ +- if (!nextProtoList.isEmpty()) { +- String[] appProtocols = nextProtoList.toArray(new String[0]); +- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior()); +- +- switch (apn.protocol()) { +- case NPN: +- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior); +- break; +- case ALPN: +- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior); +- break; +- case NPN_AND_ALPN: +- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior); +- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior); +- break; +- default: +- throw new Error(); +- } - } - -- int packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset); +- /* Set session cache size, if specified */ +- if (sessionCacheSize <= 0) { +- // Get the default session cache size using SSLContext.setSessionCacheSize() +- sessionCacheSize = SSLContext.setSessionCacheSize(ctx, 20480); +- } +- this.sessionCacheSize = sessionCacheSize; +- SSLContext.setSessionCacheSize(ctx, sessionCacheSize); - -- if (packetLength == SslUtils.NOT_ENCRYPTED) { -- throw new NotSslRecordException("not an SSL/TLS record"); +- /* Set session timeout, if specified */ +- if (sessionTimeout <= 0) { +- // Get the default session timeout using SSLContext.setSessionCacheTimeout() +- sessionTimeout = SSLContext.setSessionCacheTimeout(ctx, 300); - } +- this.sessionTimeout = sessionTimeout; +- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout); - -- if (packetLength - SSL_RECORD_HEADER_LENGTH > capacity) { -- // No enough space in the destination buffer so signal the caller -- // that the buffer needs to be increased. -- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0); +- if (enableOcsp) { +- SSLContext.enableOcsp(ctx, isClient()); - } - -- if (len < packetLength) { -- // We either have no enough data to read the packet length at all or not enough for reading -- // the whole packet. -- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0); +- SSLContext.setUseTasks(ctx, USE_TASKS); +- success = true; +- } finally { +- if (!success) { +- release(); - } +- } +- } - -- // This must always be the case when we reached here as if not we returned BUFFER_UNDERFLOW. -- assert srcsOffset < srcsEndOffset; +- private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) { +- switch (behavior) { +- case NO_ADVERTISE: +- return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE; +- case CHOOSE_MY_LAST_PROTOCOL: +- return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL; +- default: +- throw new Error(); +- } +- } - -- // This must always be the case if we reached here. -- assert capacity > 0; +- @Override +- public final List<String> cipherSuites() { +- return unmodifiableCiphers; +- } - -- // Number of produced bytes -- int bytesProduced = 0; -- int bytesConsumed = 0; -- try { -- for (; srcsOffset < srcsEndOffset; ++srcsOffset) { -- ByteBuffer src = srcs[srcsOffset]; -- int remaining = src.remaining(); -- if (remaining == 0) { -- // We must skip empty buffers as BIO_write will return 0 if asked to write something -- // with length 0. -- continue; -- } -- // Write more encrypted data into the BIO. Ensure we only read one packet at a time as -- // stated in the SSLEngine javadocs. -- int pendingEncryptedBytes = min(packetLength, remaining); -- ByteBuf bioWriteCopyBuf = writeEncryptedData(src, pendingEncryptedBytes); -- try { -- readLoop: -- for (; dstsOffset < dstsEndOffset; ++dstsOffset) { -- ByteBuffer dst = dsts[dstsOffset]; -- if (!dst.hasRemaining()) { -- // No space left in the destination buffer, skip it. -- continue; -- } +- @Override +- public final long sessionCacheSize() { +- return sessionCacheSize; +- } - -- int bytesRead = readPlaintextData(dst); -- // We are directly using the ByteBuffer memory for the write, and so we only know what -- // has been consumed after we let SSL decrypt the data. At this point we should update -- // the number of bytes consumed, update the ByteBuffer position, and release temp -- // ByteBuf. -- int localBytesConsumed = pendingEncryptedBytes - SSL.bioLengthByteBuffer(networkBIO); -- bytesConsumed += localBytesConsumed; -- packetLength -= localBytesConsumed; -- pendingEncryptedBytes -= localBytesConsumed; -- src.position(src.position() + localBytesConsumed); +- @Override +- public final long sessionTimeout() { +- return sessionTimeout; +- } - -- if (bytesRead > 0) { -- bytesProduced += bytesRead; +- @Override +- public ApplicationProtocolNegotiator applicationProtocolNegotiator() { +- return apn; +- } - -- if (!dst.hasRemaining()) { -- // Move to the next dst buffer as this one is full. -- continue; -- } -- if (packetLength == 0) { -- // We read everything return now. -- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, -- bytesConsumed, bytesProduced); -- } -- // try to write again to the BIO. stop reading from it by break out of the readLoop. -- break; -- } else { -- int sslError = SSL.getError(ssl, bytesRead); -- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) { -- // break to the outer loop as we want to read more data which means we need to -- // write more to the BIO. -- break readLoop; -- } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) { -- // This means the connection was shutdown correctly, close inbound and outbound -- if (!receivedShutdown) { -- closeAll(); -- } -- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, -- bytesConsumed, bytesProduced); -- } else { -- return sslReadErrorResult(SSL.getLastErrorNumber(), bytesConsumed, -- bytesProduced); -- } -- } -- } +- @Override +- public final boolean isClient() { +- return mode == SSL.SSL_MODE_CLIENT; +- } - -- // Either we have no more dst buffers to put the data, or no more data to generate; we are done. -- if (dstsOffset >= dstsEndOffset || packetLength == 0) { -- break; -- } -- } finally { -- if (bioWriteCopyBuf != null) { -- bioWriteCopyBuf.release(); -- } -- } -- } -- } finally { -- SSL.bioClearByteBuffer(networkBIO); -- rejectRemoteInitiatedRenegotiation(); -- } +- @Override +- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) { +- return newEngine0(alloc, peerHost, peerPort, true); +- } - -- // Check to see if we received a close_notify message from the peer. -- if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) { -- closeAll(); -- } +- @Override +- protected final SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) { +- return new SslHandler(newEngine0(alloc, null, -1, false), startTls); +- } - -- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced); -- } +- @Override +- protected final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls) { +- return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), startTls); - } - -- private SSLEngineResult sslReadErrorResult(int err, int bytesConsumed, int bytesProduced) throws SSLException { -- String errStr = SSL.getErrorString(err); +- @Override +- protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor executor) { +- return new SslHandler(newEngine0(alloc, null, -1, false), startTls, executor); +- } - -- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the -- // BIO first or can just shutdown and throw it now. -- // This is needed so we ensure close_notify etc is correctly send to the remote peer. -- // See https://github.com/netty/netty/issues/3900 -- if (SSL.bioLengthNonApplication(networkBIO) > 0) { -- if (handshakeException == null && handshakeState != HandshakeState.FINISHED) { -- // we seems to have data left that needs to be transfered and so the user needs -- // call wrap(...). Store the error so we can pick it up later. -- handshakeException = new SSLHandshakeException(errStr); -- } -- return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced); -- } -- throw shutdownWithError("SSL_read", errStr); +- @Override +- protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, +- boolean startTls, Executor executor) { +- return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), executor); - } - -- private void closeAll() throws SSLException { -- receivedShutdown = true; -- closeOutbound(); -- closeInbound(); +- SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) { +- return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode, true); - } - -- private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException { -- if (rejectRemoteInitiatedRenegotiation && SSL.getHandshakeCount(ssl) > 1) { -- // TODO: In future versions me may also want to send a fatal_alert to the client and so notify it -- // that the renegotiation failed. -- shutdown(); -- throw new SSLHandshakeException("remote-initiated renegotiation not allowed"); -- } +- /** +- * Returns a new server-side {@link SSLEngine} with the current configuration. +- */ +- @Override +- public final SSLEngine newEngine(ByteBufAllocator alloc) { +- return newEngine(alloc, null, -1); - } - -- public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException { -- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length); +- /** +- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}. +- * Be aware that it is freed as soon as the {@link #finalize()} method is called. +- * At this point {@code 0} will be returned. +- * +- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it! +- */ +- @Deprecated +- public final long context() { +- return sslCtxPointer(); - } - -- private ByteBuffer[] singleSrcBuffer(ByteBuffer src) { -- singleSrcBuffer[0] = src; -- return singleSrcBuffer; +- /** +- * Returns the stats of this context. +- * +- * @deprecated use {@link #sessionContext#stats()} +- */ +- @Deprecated +- public final OpenSslSessionStats stats() { +- return sessionContext().stats(); - } - -- private void resetSingleSrcBuffer() { -- singleSrcBuffer[0] = null; +- /** +- * {@deprecated Renegotiation is not supported} +- * Specify if remote initiated renegotiation is supported or not. If not supported and the remote side tries +- * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during decoding. +- */ +- @Deprecated +- public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) { +- if (!rejectRemoteInitiatedRenegotiation) { +- throw new UnsupportedOperationException("Renegotiation is not supported"); +- } - } - -- private ByteBuffer[] singleDstBuffer(ByteBuffer src) { -- singleDstBuffer[0] = src; -- return singleDstBuffer; +- /** +- * {@deprecated Renegotiation is not supported} +- * @return {@code true} because renegotiation is not supported. +- */ +- @Deprecated +- public boolean getRejectRemoteInitiatedRenegotiation() { +- return true; - } - -- private void resetSingleDstBuffer() { -- singleDstBuffer[0] = null; +- /** +- * Set the size of the buffer used by the BIO for non-application based writes +- * (e.g. handshake, renegotiation, etc...). +- */ +- public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) { +- this.bioNonApplicationBufferSize = +- checkPositiveOrZero(bioNonApplicationBufferSize, "bioNonApplicationBufferSize"); +- } +- +- /** +- * Returns the size of the buffer used by the BIO for non-application based writes +- */ +- public int getBioNonApplicationBufferSize() { +- return bioNonApplicationBufferSize; +- } +- +- /** +- * Sets the SSL session ticket keys of this context. +- * +- * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])} +- */ +- @Deprecated +- public final void setTicketKeys(byte[] keys) { +- sessionContext().setTicketKeys(keys); - } - - @Override -- public final synchronized SSLEngineResult unwrap( -- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException { +- public abstract OpenSslSessionContext sessionContext(); +- +- /** +- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}. +- * Be aware that it is freed as soon as the {@link #release()} method is called. +- * At this point {@code 0} will be returned. +- * +- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it! +- */ +- @Deprecated +- public final long sslCtxPointer() { +- Lock readerLock = ctxLock.readLock(); +- readerLock.lock(); - try { -- return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length); +- return SSLContext.getSslCtx(ctx); - } finally { -- resetSingleSrcBuffer(); +- readerLock.unlock(); - } - } - -- @Override -- public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException { +- /** +- * Set the {@link OpenSslPrivateKeyMethod} to use. This allows to offload private-key operations +- * if needed. +- * +- * This method is currently only supported when {@code BoringSSL} is used. +- * +- * @param method method to use. +- */ +- @UnstableApi +- public final void setPrivateKeyMethod(OpenSslPrivateKeyMethod method) { +- ObjectUtil.checkNotNull(method, "method"); +- Lock writerLock = ctxLock.writeLock(); +- writerLock.lock(); - try { -- return wrap(singleSrcBuffer(src), dst); +- SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, method)); - } finally { -- resetSingleSrcBuffer(); +- writerLock.unlock(); - } - } - -- @Override -- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException { +- public final void setUseTasks(boolean useTasks) { +- Lock writerLock = ctxLock.writeLock(); +- writerLock.lock(); - try { -- return unwrap(singleSrcBuffer(src), singleDstBuffer(dst)); +- SSLContext.setUseTasks(ctx, useTasks); - } finally { -- resetSingleSrcBuffer(); -- resetSingleDstBuffer(); +- writerLock.unlock(); - } - } - -- @Override -- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException { +- // IMPORTANT: This method must only be called from either the constructor or the finalizer as a user MUST never +- // get access to an OpenSslSessionContext after this method was called to prevent the user from +- // producing a segfault. +- private void destroy() { +- Lock writerLock = ctxLock.writeLock(); +- writerLock.lock(); - try { -- return unwrap(singleSrcBuffer(src), dsts); -- } finally { -- resetSingleSrcBuffer(); -- } -- } -- -- @Override -- public final Runnable getDelegatedTask() { -- // Currently, we do not delegate SSL computation tasks -- // TODO: in the future, possibly create tasks to do encrypt / decrypt async -- -- return null; -- } -- -- @Override -- public final synchronized void closeInbound() throws SSLException { -- if (isInboundDone) { -- return; -- } -- -- isInboundDone = true; +- if (ctx != 0) { +- if (enableOcsp) { +- SSLContext.disableOcsp(ctx); +- } - -- if (isOutboundDone()) { -- // Only call shutdown if there is no outbound data pending. -- // See https://github.com/netty/netty/issues/6167 -- shutdown(); -- } +- SSLContext.free(ctx); +- ctx = 0; - -- if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown) { -- throw new SSLException( -- "Inbound closed before receiving peer's close_notify: possible truncation attack?"); +- OpenSslSessionContext context = sessionContext(); +- if (context != null) { +- context.destroy(); +- } +- } +- } finally { +- writerLock.unlock(); - } - } - -- @Override -- public final synchronized boolean isInboundDone() { -- return isInboundDone; +- protected static X509Certificate[] certificates(byte[][] chain) { +- X509Certificate[] peerCerts = new X509Certificate[chain.length]; +- for (int i = 0; i < peerCerts.length; i++) { +- peerCerts[i] = new OpenSslX509Certificate(chain[i]); +- } +- return peerCerts; - } - -- @Override -- public final synchronized void closeOutbound() { -- if (outboundClosed) { -- return; +- protected static X509TrustManager chooseTrustManager(TrustManager[] managers) { +- for (TrustManager m : managers) { +- if (m instanceof X509TrustManager) { +- if (PlatformDependent.javaVersion() >= 7) { +- return OpenSslX509TrustManagerWrapper.wrapIfNeeded((X509TrustManager) m); +- } +- return (X509TrustManager) m; +- } - } +- throw new IllegalStateException("no X509TrustManager found"); +- } - -- outboundClosed = true; -- -- if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) { -- int mode = SSL.getShutdown(ssl); -- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) { -- doSSLShutdown(); +- protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) { +- for (KeyManager km : kms) { +- if (km instanceof X509KeyManager) { +- return (X509KeyManager) km; - } -- } else { -- // engine closing before initial handshake -- shutdown(); - } +- throw new IllegalStateException("no X509KeyManager found"); - } - - /** -- * Attempt to call {@link SSL#shutdownSSL(long)}. -- * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not attempted or returned an error. +- * Translate a {@link ApplicationProtocolConfig} object to a +- * {@link OpenSslApplicationProtocolNegotiator} object. +- * +- * @param config The configuration which defines the translation +- * @return The results of the translation - */ -- private boolean doSSLShutdown() { -- if (SSL.isInInit(ssl) != 0) { -- // Only try to call SSL_shutdown if we are not in the init state anymore. -- // Otherwise we will see 'error:140E0197:SSL routines:SSL_shutdown:shutdown while in init' in our logs. -- // -- // See also http://hg.nginx.org/nginx/rev/062c189fee20 -- return false; +- @SuppressWarnings("deprecation") +- static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) { +- if (config == null) { +- return NONE_PROTOCOL_NEGOTIATOR; - } -- int err = SSL.shutdownSSL(ssl); -- if (err < 0) { -- int sslErr = SSL.getError(ssl, err); -- if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) { -- if (logger.isDebugEnabled()) { -- logger.debug("SSL_shutdown failed: OpenSSL error: {}", SSL.getLastError()); +- +- switch (config.protocol()) { +- case NONE: +- return NONE_PROTOCOL_NEGOTIATOR; +- case ALPN: +- case NPN: +- case NPN_AND_ALPN: +- switch (config.selectedListenerFailureBehavior()) { +- case CHOOSE_MY_LAST_PROTOCOL: +- case ACCEPT: +- switch (config.selectorFailureBehavior()) { +- case CHOOSE_MY_LAST_PROTOCOL: +- case NO_ADVERTISE: +- return new OpenSslDefaultApplicationProtocolNegotiator( +- config); +- default: +- throw new UnsupportedOperationException( +- new StringBuilder("OpenSSL provider does not support ") +- .append(config.selectorFailureBehavior()) +- .append(" behavior").toString()); +- } +- default: +- throw new UnsupportedOperationException( +- new StringBuilder("OpenSSL provider does not support ") +- .append(config.selectedListenerFailureBehavior()) +- .append(" behavior").toString()); - } -- // There was an internal error -- shutdown -- shutdown(); -- return false; -- } -- SSL.clearError(); +- default: +- throw new Error(); - } -- return true; - } - -- @Override -- public final synchronized boolean isOutboundDone() { -- // Check if there is anything left in the outbound buffer. -- // We need to ensure we only call SSL.pendingWrittenBytesInBIO(...) if the engine was not destroyed yet. -- return outboundClosed && (networkBIO == 0 || SSL.bioLengthNonApplication(networkBIO) == 0); +- @SuppressJava6Requirement(reason = "Guarded by java version check") +- static boolean useExtendedTrustManager(X509TrustManager trustManager) { +- return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager; - } - - @Override -- public final String[] getSupportedCipherSuites() { -- return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[OpenSsl.AVAILABLE_CIPHER_SUITES.size()]); +- public final int refCnt() { +- return refCnt.refCnt(); - } - - @Override -- public final String[] getEnabledCipherSuites() { -- final String[] enabled; -- synchronized (this) { -- if (!isDestroyed()) { -- enabled = SSL.getCiphers(ssl); -- } else { -- return EmptyArrays.EMPTY_STRINGS; -- } -- } -- if (enabled == null) { -- return EmptyArrays.EMPTY_STRINGS; -- } else { -- synchronized (this) { -- for (int i = 0; i < enabled.length; i++) { -- String mapped = toJavaCipherSuite(enabled[i]); -- if (mapped != null) { -- enabled[i] = mapped; -- } -- } -- } -- return enabled; -- } +- public final ReferenceCounted retain() { +- refCnt.retain(); +- return this; - } - - @Override -- public final void setEnabledCipherSuites(String[] cipherSuites) { -- checkNotNull(cipherSuites, "cipherSuites"); -- -- final StringBuilder buf = new StringBuilder(); -- for (String c: cipherSuites) { -- if (c == null) { -- break; -- } -- -- String converted = CipherSuiteConverter.toOpenSsl(c); -- if (converted == null) { -- converted = c; -- } -- -- if (!OpenSsl.isCipherSuiteAvailable(converted)) { -- throw new IllegalArgumentException("unsupported cipher suite: " + c + '(' + converted + ')'); -- } -- -- buf.append(converted); -- buf.append(':'); -- } -- -- if (buf.length() == 0) { -- throw new IllegalArgumentException("empty cipher suites"); -- } -- buf.setLength(buf.length() - 1); -- -- final String cipherSuiteSpec = buf.toString(); -- -- synchronized (this) { -- if (!isDestroyed()) { -- try { -- SSL.setCipherSuites(ssl, cipherSuiteSpec); -- } catch (Exception e) { -- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e); -- } -- } else { -- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec); -- } -- } +- public final ReferenceCounted retain(int increment) { +- refCnt.retain(increment); +- return this; - } - - @Override -- public final String[] getSupportedProtocols() { -- return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[OpenSsl.SUPPORTED_PROTOCOLS_SET.size()]); +- public final ReferenceCounted touch() { +- refCnt.touch(); +- return this; - } - - @Override -- public final String[] getEnabledProtocols() { -- List<String> enabled = new ArrayList<String>(6); -- // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is always enabled -- enabled.add(OpenSsl.PROTOCOL_SSL_V2_HELLO); -- -- int opts; -- synchronized (this) { -- if (!isDestroyed()) { -- opts = SSL.getOptions(ssl); -- } else { -- return enabled.toArray(new String[1]); -- } -- } -- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, OpenSsl.PROTOCOL_TLS_V1)) { -- enabled.add(OpenSsl.PROTOCOL_TLS_V1); -- } -- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, OpenSsl.PROTOCOL_TLS_V1_1)) { -- enabled.add(OpenSsl.PROTOCOL_TLS_V1_1); -- } -- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, OpenSsl.PROTOCOL_TLS_V1_2)) { -- enabled.add(OpenSsl.PROTOCOL_TLS_V1_2); -- } -- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, OpenSsl.PROTOCOL_SSL_V2)) { -- enabled.add(OpenSsl.PROTOCOL_SSL_V2); -- } -- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, OpenSsl.PROTOCOL_SSL_V3)) { -- enabled.add(OpenSsl.PROTOCOL_SSL_V3); -- } -- return enabled.toArray(new String[enabled.size()]); +- public final ReferenceCounted touch(Object hint) { +- refCnt.touch(hint); +- return this; - } - -- private static boolean isProtocolEnabled(int opts, int disableMask, String protocolString) { -- // We also need to check if the actual protocolString is supported as depending on the openssl API -- // implementations it may use a disableMask of 0 (BoringSSL is doing this for example). -- return (opts & disableMask) == 0 && OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString); +- @Override +- public final boolean release() { +- return refCnt.release(); - } - - @Override -- public final void setEnabledProtocols(String[] protocols) { -- if (protocols == null) { -- // This is correct from the API docs -- throw new IllegalArgumentException(); +- public final boolean release(int decrement) { +- return refCnt.release(decrement); +- } +- +- abstract static class AbstractCertificateVerifier extends CertificateVerifier { +- private final OpenSslEngineMap engineMap; +- +- AbstractCertificateVerifier(OpenSslEngineMap engineMap) { +- this.engineMap = engineMap; - } -- boolean sslv2 = false; -- boolean sslv3 = false; -- boolean tlsv1 = false; -- boolean tlsv1_1 = false; -- boolean tlsv1_2 = false; -- for (String p: protocols) { -- if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) { -- throw new IllegalArgumentException("Protocol " + p + " is not supported."); -- } -- if (p.equals(OpenSsl.PROTOCOL_SSL_V2)) { -- sslv2 = true; -- } else if (p.equals(OpenSsl.PROTOCOL_SSL_V3)) { -- sslv3 = true; -- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1)) { -- tlsv1 = true; -- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_1)) { -- tlsv1_1 = true; -- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_2)) { -- tlsv1_2 = true; +- +- @Override +- public final int verify(long ssl, byte[][] chain, String auth) { +- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); +- if (engine == null) { +- // May be null if it was destroyed in the meantime. +- return CertificateVerifier.X509_V_ERR_UNSPECIFIED; - } -- } -- synchronized (this) { -- if (!isDestroyed()) { -- // Clear out options which disable protocols -- SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 | -- SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2); +- X509Certificate[] peerCerts = certificates(chain); +- try { +- verify(engine, peerCerts, auth); +- return CertificateVerifier.X509_V_OK; +- } catch (Throwable cause) { +- logger.debug("verification of certificate failed", cause); +- engine.initHandshakeException(cause); - -- int opts = 0; -- if (!sslv2) { -- opts |= SSL.SSL_OP_NO_SSLv2; -- } -- if (!sslv3) { -- opts |= SSL.SSL_OP_NO_SSLv3; +- // Try to extract the correct error code that should be used. +- if (cause instanceof OpenSslCertificateException) { +- // This will never return a negative error code as its validated when constructing the +- // OpenSslCertificateException. +- return ((OpenSslCertificateException) cause).errorCode(); - } -- if (!tlsv1) { -- opts |= SSL.SSL_OP_NO_TLSv1; +- if (cause instanceof CertificateExpiredException) { +- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED; - } -- if (!tlsv1_1) { -- opts |= SSL.SSL_OP_NO_TLSv1_1; +- if (cause instanceof CertificateNotYetValidException) { +- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID; - } -- if (!tlsv1_2) { -- opts |= SSL.SSL_OP_NO_TLSv1_2; +- if (PlatformDependent.javaVersion() >= 7) { +- return translateToError(cause); - } - -- // Disable protocols we do not want -- SSL.setOptions(ssl, opts); -- } else { -- throw new IllegalStateException("failed to enable protocols: " + Arrays.asList(protocols)); +- // Could not detect a specific error code to use, so fallback to a default code. +- return CertificateVerifier.X509_V_ERR_UNSPECIFIED; - } - } -- } -- -- @Override -- public final SSLSession getSession() { -- return session; -- } -- -- @Override -- public final synchronized void beginHandshake() throws SSLException { -- switch (handshakeState) { -- case STARTED_IMPLICITLY: -- checkEngineClosed(BEGIN_HANDSHAKE_ENGINE_CLOSED); - -- // A user did not start handshake by calling this method by him/herself, -- // but handshake has been started already by wrap() or unwrap() implicitly. -- // Because it's the user's first time to call this method, it is unfair to -- // raise an exception. From the user's standpoint, he or she never asked -- // for renegotiation. +- @SuppressJava6Requirement(reason = "Usage guarded by java version check") +- private static int translateToError(Throwable cause) { +- if (cause instanceof CertificateRevokedException) { +- return CertificateVerifier.X509_V_ERR_CERT_REVOKED; +- } - -- handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this method is invoked by the user, -- // we should raise an exception. -- break; -- case STARTED_EXPLICITLY: -- // Nothing to do as the handshake is not done yet. -- break; -- case FINISHED: -- if (clientMode) { -- // Only supported for server mode at the moment. -- throw RENEGOTIATION_UNSUPPORTED; -- } -- // For renegotiate on the server side we need to issue the following command sequence with openssl: -- // -- // SSL_renegotiate(ssl) -- // SSL_do_handshake(ssl) -- // ssl->state = SSL_ST_ACCEPT -- // SSL_do_handshake(ssl) -- // -- // Because of this we fall-through to call handshake() after setting the state, as this will also take -- // care of updating the internal OpenSslSession object. -- // -- // See also: -- // https://github.com/apache/httpd/blob/2.4.16/modules/ssl/ssl_engine_kernel.c#L812 -- // http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html -- int status; -- if ((status = SSL.renegotiate(ssl)) != 1 || (status = SSL.doHandshake(ssl)) != 1) { -- int err = SSL.getError(ssl, status); -- if (err == SSL.SSL_ERROR_WANT_READ || err == SSL.SSL_ERROR_WANT_WRITE) { -- // If the internal SSL buffer is small it is possible that doHandshake may "fail" because -- // there is not enough room to write, so we should wait until the renegotiation has been. -- renegotiationPending = true; -- handshakeState = HandshakeState.STARTED_EXPLICITLY; -- lastAccessed = System.currentTimeMillis(); -- return; -- } else { -- throw shutdownWithError("renegotiation failed"); +- // The X509TrustManagerImpl uses a Validator which wraps a CertPathValidatorException into +- // an CertificateException. So we need to handle the wrapped CertPathValidatorException to be +- // able to send the correct alert. +- Throwable wrapped = cause.getCause(); +- while (wrapped != null) { +- if (wrapped instanceof CertPathValidatorException) { +- CertPathValidatorException ex = (CertPathValidatorException) wrapped; +- CertPathValidatorException.Reason reason = ex.getReason(); +- if (reason == CertPathValidatorException.BasicReason.EXPIRED) { +- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED; +- } +- if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) { +- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID; +- } +- if (reason == CertPathValidatorException.BasicReason.REVOKED) { +- return CertificateVerifier.X509_V_ERR_CERT_REVOKED; - } - } +- wrapped = wrapped.getCause(); +- } +- return CertificateVerifier.X509_V_ERR_UNSPECIFIED; +- } - -- SSL.setState(ssl, SSL.SSL_ST_ACCEPT); +- abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, +- String auth) throws Exception; +- } - -- lastAccessed = System.currentTimeMillis(); +- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap { +- private final Map<Long, ReferenceCountedOpenSslEngine> engines = PlatformDependent.newConcurrentHashMap(); - -- // fall-through -- case NOT_STARTED: -- handshakeState = HandshakeState.STARTED_EXPLICITLY; -- handshake(); -- break; -- default: -- throw new Error(); +- @Override +- public ReferenceCountedOpenSslEngine remove(long ssl) { +- return engines.remove(ssl); - } -- } - -- private void checkEngineClosed(SSLException cause) throws SSLException { -- if (isDestroyed()) { -- throw cause; +- @Override +- public void add(ReferenceCountedOpenSslEngine engine) { +- engines.put(engine.sslPointer(), engine); - } -- } - -- private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingStatus) { -- // Depending on if there is something left in the BIO we need to WRAP or UNWRAP -- return pendingStatus > 0 ? NEED_WRAP : NEED_UNWRAP; +- @Override +- public ReferenceCountedOpenSslEngine get(long ssl) { +- return engines.get(ssl); +- } - } - -- private static boolean isEmpty(Object[] arr) { -- return arr == null || arr.length == 0; -- } +- static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword) +- throws SSLException { +- /* Load the certificate file and private key. */ +- long keyBio = 0; +- long keyCertChainBio = 0; +- long keyCertChainBio2 = 0; +- PemEncoded encoded = null; +- try { +- // Only encode one time +- encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain); +- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); +- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); - -- private static boolean isEmpty(byte[] cert) { -- return cert == null || cert.length == 0; -- } +- if (key != null) { +- keyBio = toBIO(ByteBufAllocator.DEFAULT, key); +- } - -- private SSLEngineResult.HandshakeStatus handshake() throws SSLException { -- if (handshakeState == HandshakeState.FINISHED) { -- return FINISHED; +- SSLContext.setCertificateBio( +- ctx, keyCertChainBio, keyBio, +- keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword); +- // We may have more then one cert in the chain so add all of them now. +- SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true); +- } catch (SSLException e) { +- throw e; +- } catch (Exception e) { +- throw new SSLException("failed to set certificate and key", e); +- } finally { +- freeBio(keyBio); +- freeBio(keyCertChainBio); +- freeBio(keyCertChainBio2); +- if (encoded != null) { +- encoded.release(); +- } - } -- checkEngineClosed(HANDSHAKE_ENGINE_CLOSED); +- } - -- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the -- // BIO first or can just shutdown and throw it now. -- // This is needed so we ensure close_notify etc is correctly send to the remote peer. -- // See https://github.com/netty/netty/issues/3900 -- SSLHandshakeException exception = handshakeException; -- if (exception != null) { -- if (SSL.bioLengthNonApplication(networkBIO) > 0) { -- // There is something pending, we need to consume it first via a WRAP so we don't loose anything. -- return NEED_WRAP; -- } -- // No more data left to send to the remote peer, so null out the exception field, shutdown and throw -- // the exception. -- handshakeException = null; -- shutdown(); -- throw exception; +- static void freeBio(long bio) { +- if (bio != 0) { +- SSL.freeBIO(bio); - } +- } - -- // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the AbstractCertificateVerifier. -- engineMap.add(this); -- if (lastAccessed == -1) { -- lastAccessed = System.currentTimeMillis(); +- /** +- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a> +- * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}. +- */ +- static long toBIO(ByteBufAllocator allocator, PrivateKey key) throws Exception { +- if (key == null) { +- return 0; - } - -- if (!certificateSet && keyMaterialManager != null) { -- certificateSet = true; -- keyMaterialManager.setKeyMaterial(this); +- PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key); +- try { +- return toBIO(allocator, pem.retain()); +- } finally { +- pem.release(); - } +- } - -- int code = SSL.doHandshake(ssl); -- if (code <= 0) { -- // Check if we have a pending exception that was created during the handshake and if so throw it after -- // shutdown the connection. -- if (handshakeException != null) { -- exception = handshakeException; -- handshakeException = null; -- shutdown(); -- throw exception; -- } +- /** +- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a> +- * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}. +- */ +- static long toBIO(ByteBufAllocator allocator, X509Certificate... certChain) throws Exception { +- if (certChain == null) { +- return 0; +- } - -- int sslError = SSL.getError(ssl, code); -- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) { -- return pendingStatus(SSL.bioLengthNonApplication(networkBIO)); -- } else { -- // Everything else is considered as error -- throw shutdownWithError("SSL_do_handshake"); -- } +- if (certChain.length == 0) { +- throw new IllegalArgumentException("certChain can't be empty"); - } -- // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means the handshake was finished. -- session.handshakeFinished(); -- engineMap.remove(ssl); -- return FINISHED; -- } - -- private SSLEngineResult.HandshakeStatus mayFinishHandshake(SSLEngineResult.HandshakeStatus status) -- throws SSLException { -- if (status == NOT_HANDSHAKING && handshakeState != HandshakeState.FINISHED) { -- // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call -- // SSL_do_handshake() again -- return handshake(); +- PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain); +- try { +- return toBIO(allocator, pem.retain()); +- } finally { +- pem.release(); - } -- return status; - } - -- @Override -- public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() { -- // Check if we are in the initial handshake phase or shutdown phase -- return needPendingStatus() ? pendingStatus(SSL.bioLengthNonApplication(networkBIO)) : NOT_HANDSHAKING; -- } +- static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception { +- try { +- // We can turn direct buffers straight into BIOs. No need to +- // make a yet another copy. +- ByteBuf content = pem.content(); - -- private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) { -- // Check if we are in the initial handshake phase or shutdown phase -- return needPendingStatus() ? pendingStatus(pending) : NOT_HANDSHAKING; +- if (content.isDirect()) { +- return newBIO(content.retainedSlice()); +- } +- +- ByteBuf buffer = allocator.directBuffer(content.readableBytes()); +- try { +- buffer.writeBytes(content, content.readerIndex(), content.readableBytes()); +- return newBIO(buffer.retainedSlice()); +- } finally { +- try { +- // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we +- // need to zero out the bytes of the copy before we're releasing it. +- if (pem.isSensitive()) { +- SslUtils.zeroout(buffer); +- } +- } finally { +- buffer.release(); +- } +- } +- } finally { +- pem.release(); +- } - } - -- private boolean needPendingStatus() { -- return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed() -- && (handshakeState != HandshakeState.FINISHED || isInboundDone() || isOutboundDone()); +- private static long newBIO(ByteBuf buffer) throws Exception { +- try { +- long bio = SSL.newMemBIO(); +- int readable = buffer.readableBytes(); +- if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) { +- SSL.freeBIO(bio); +- throw new IllegalStateException("Could not write data to memory BIO"); +- } +- return bio; +- } finally { +- buffer.release(); +- } - } - - /** -- * Converts the specified OpenSSL cipher suite to the Java cipher suite. +- * Returns the {@link OpenSslKeyMaterialProvider} that should be used for OpenSSL. Depending on the given +- * {@link KeyManagerFactory} this may cache the {@link OpenSslKeyMaterial} for better performance if it can +- * ensure that the same material is always returned for the same alias. - */ -- private String toJavaCipherSuite(String openSslCipherSuite) { -- if (openSslCipherSuite == null) { -- return null; +- static OpenSslKeyMaterialProvider providerFor(KeyManagerFactory factory, String password) { +- if (factory instanceof OpenSslX509KeyManagerFactory) { +- return ((OpenSslX509KeyManagerFactory) factory).newProvider(); - } - -- String prefix = toJavaCipherSuitePrefix(SSL.getVersion(ssl)); -- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix); +- if (factory instanceof OpenSslCachingX509KeyManagerFactory) { +- // The user explicit used OpenSslCachingX509KeyManagerFactory which signals us that its fine to cache. +- return ((OpenSslCachingX509KeyManagerFactory) factory).newProvider(password); +- } +- // We can not be sure if the material may change at runtime so we will not cache it. +- return new OpenSslKeyMaterialProvider(chooseX509KeyManager(factory.getKeyManagers()), password); - } - -- /** -- * Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string. -- */ -- private static String toJavaCipherSuitePrefix(String protocolVersion) { -- final char c; -- if (protocolVersion == null || protocolVersion.isEmpty()) { -- c = 0; -- } else { -- c = protocolVersion.charAt(0); +- private static final class PrivateKeyMethod implements SSLPrivateKeyMethod { +- +- private final OpenSslEngineMap engineMap; +- private final OpenSslPrivateKeyMethod keyMethod; +- PrivateKeyMethod(OpenSslEngineMap engineMap, OpenSslPrivateKeyMethod keyMethod) { +- this.engineMap = engineMap; +- this.keyMethod = keyMethod; - } - -- switch (c) { -- case 'T': -- return "TLS"; -- case 'S': -- return "SSL"; -- default: -- return "UNKNOWN"; +- private ReferenceCountedOpenSslEngine retrieveEngine(long ssl) throws SSLException { +- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); +- if (engine == null) { +- throw new SSLException("Could not find a " + +- StringUtil.simpleClassName(ReferenceCountedOpenSslEngine.class) + " for sslPointer " + ssl); +- } +- return engine; - } -- } - -- @Override -- public final void setUseClientMode(boolean clientMode) { -- if (clientMode != this.clientMode) { -- throw new UnsupportedOperationException(); +- @Override +- public byte[] sign(long ssl, int signatureAlgorithm, byte[] digest) throws Exception { +- ReferenceCountedOpenSslEngine engine = retrieveEngine(ssl); +- try { +- return verifyResult(keyMethod.sign(engine, signatureAlgorithm, digest)); +- } catch (Exception e) { +- engine.initHandshakeException(e); +- throw e; +- } - } -- } - -- @Override -- public final boolean getUseClientMode() { -- return clientMode; -- } +- @Override +- public byte[] decrypt(long ssl, byte[] input) throws Exception { +- ReferenceCountedOpenSslEngine engine = retrieveEngine(ssl); +- try { +- return verifyResult(keyMethod.decrypt(engine, input)); +- } catch (Exception e) { +- engine.initHandshakeException(e); +- throw e; +- } +- } - -- @Override -- public final void setNeedClientAuth(boolean b) { -- setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE); +- private static byte[] verifyResult(byte[] result) throws SignatureException { +- if (result == null) { +- throw new SignatureException(); +- } +- return result; +- } - } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java +deleted file mode 100644 +index b404a1076b..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java ++++ /dev/null +@@ -1,2467 +0,0 @@ +-/* +- * 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; - -- @Override -- public final boolean getNeedClientAuth() { -- return clientAuth == ClientAuth.REQUIRE; -- } +-import io.netty.buffer.ByteBuf; +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.internal.tcnative.Buffer; +-import io.netty.internal.tcnative.SSL; +-import io.netty.util.AbstractReferenceCounted; +-import io.netty.util.CharsetUtil; +-import io.netty.util.ReferenceCounted; +-import io.netty.util.ResourceLeakDetector; +-import io.netty.util.ResourceLeakDetectorFactory; +-import io.netty.util.ResourceLeakTracker; +-import io.netty.util.internal.EmptyArrays; +-import io.netty.util.internal.ObjectUtil; +-import io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.StringUtil; +-import io.netty.util.internal.SuppressJava6Requirement; +-import io.netty.util.internal.ThrowableUtil; +-import io.netty.util.internal.UnstableApi; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; - -- @Override -- public final void setWantClientAuth(boolean b) { -- setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE); -- } +-import java.nio.ByteBuffer; +-import java.nio.ReadOnlyBufferException; +-import java.security.Principal; +-import java.security.cert.Certificate; +-import java.util.ArrayList; +-import java.util.Arrays; +-import java.util.Collection; +-import java.util.Collections; +-import java.util.HashMap; +-import java.util.LinkedHashSet; +-import java.util.List; +-import java.util.Map; +-import java.util.Set; +-import java.util.concurrent.locks.Lock; - -- @Override -- public final boolean getWantClientAuth() { -- return clientAuth == ClientAuth.OPTIONAL; -- } +-import javax.crypto.spec.SecretKeySpec; +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLEngineResult; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.SSLHandshakeException; +-import javax.net.ssl.SSLParameters; +-import javax.net.ssl.SSLPeerUnverifiedException; +-import javax.net.ssl.SSLSession; +-import javax.net.ssl.SSLSessionBindingEvent; +-import javax.net.ssl.SSLSessionBindingListener; +-import javax.net.ssl.SSLSessionContext; +-import javax.security.cert.X509Certificate; - -- /** -- * See <a href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html">SSL_set_verify</a> and -- * {@link SSL#setVerify(long, int, int)}. -- */ -- @UnstableApi -- public final synchronized void setVerify(int verifyMode, int depth) { -- SSL.setVerify(ssl, verifyMode, depth); -- } +-import static io.netty.handler.ssl.OpenSsl.memoryAddress; +-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V2; +-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V2_HELLO; +-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V3; +-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1; +-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_1; +-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_2; +-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_3; +-import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH; +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import static java.lang.Integer.MAX_VALUE; +-import static java.lang.Math.min; +-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED; +-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_TASK; +-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP; +-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP; +-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; +-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW; +-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW; +-import static javax.net.ssl.SSLEngineResult.Status.CLOSED; +-import static javax.net.ssl.SSLEngineResult.Status.OK; - -- private void setClientAuth(ClientAuth mode) { -- if (clientMode) { -- return; -- } -- synchronized (this) { -- if (clientAuth == mode) { -- // No need to issue any JNI calls if the mode is the same -- return; -- } -- switch (mode) { -- case NONE: -- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, ReferenceCountedOpenSslContext.VERIFY_DEPTH); -- break; -- case REQUIRE: -- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, ReferenceCountedOpenSslContext.VERIFY_DEPTH); -- break; -- case OPTIONAL: -- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, ReferenceCountedOpenSslContext.VERIFY_DEPTH); -- break; -- default: -- throw new Error(mode.toString()); -- } -- clientAuth = mode; -- } -- } +-/** +- * Implements a {@link SSLEngine} using +- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>. +- * <p>Instances of this class must be {@link #release() released} or else native memory will leak! +- * +- * <p>Instances of this class <strong>must</strong> be released before the {@link ReferenceCountedOpenSslContext} +- * the instance depends upon are released. Otherwise if any method of this class is called which uses the +- * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash. +- */ +-public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted, ApplicationProtocolAccessor { - -- @Override -- public final void setEnableSessionCreation(boolean b) { -- if (b) { -- throw new UnsupportedOperationException(); -- } -- } +- private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class); - -- @Override -- public final boolean getEnableSessionCreation() { -- return false; -- } +- private static final ResourceLeakDetector<ReferenceCountedOpenSslEngine> leakDetector = +- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class); +- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2 = 0; +- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3 = 1; +- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1 = 2; +- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1 = 3; +- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2 = 4; +- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3 = 5; +- private static final int[] OPENSSL_OP_NO_PROTOCOLS = { +- SSL.SSL_OP_NO_SSLv2, +- SSL.SSL_OP_NO_SSLv3, +- SSL.SSL_OP_NO_TLSv1, +- SSL.SSL_OP_NO_TLSv1_1, +- SSL.SSL_OP_NO_TLSv1_2, +- SSL.SSL_OP_NO_TLSv1_3 +- }; - -- @Override -- public final synchronized SSLParameters getSSLParameters() { -- SSLParameters sslParameters = super.getSSLParameters(); +- /** +- * Depends upon tcnative ... only use if tcnative is available! +- */ +- static final int MAX_PLAINTEXT_LENGTH = SSL.SSL_MAX_PLAINTEXT_LENGTH; +- /** +- * Depends upon tcnative ... only use if tcnative is available! +- */ +- private static final int MAX_RECORD_SIZE = SSL.SSL_MAX_RECORD_LENGTH; - -- int version = PlatformDependent.javaVersion(); -- if (version >= 7) { -- sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm); -- Java7SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints); -- if (version >= 8) { -- if (sniHostNames != null) { -- Java8SslUtils.setSniHostNames(sslParameters, sniHostNames); -- } -- if (!isDestroyed()) { -- Java8SslUtils.setUseCipherSuitesOrder( -- sslParameters, (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0); -- } +- private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0); +- private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0); +- private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0); +- private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0); +- private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0); - -- Java8SslUtils.setSNIMatchers(sslParameters, matchers); -- } -- } -- return sslParameters; +- // OpenSSL state +- private long ssl; +- private long networkBIO; +- +- private enum HandshakeState { +- /** +- * Not started yet. +- */ +- NOT_STARTED, +- /** +- * Started via unwrap/wrap. +- */ +- STARTED_IMPLICITLY, +- /** +- * Started via {@link #beginHandshake()}. +- */ +- STARTED_EXPLICITLY, +- /** +- * Handshake is finished. +- */ +- FINISHED - } - -- @Override -- public final synchronized void setSSLParameters(SSLParameters sslParameters) { -- int version = PlatformDependent.javaVersion(); -- if (version >= 7) { -- if (sslParameters.getAlgorithmConstraints() != null) { -- throw new IllegalArgumentException("AlgorithmConstraints are not supported."); -- } +- private HandshakeState handshakeState = HandshakeState.NOT_STARTED; +- private boolean receivedShutdown; +- private volatile boolean destroyed; +- private volatile String applicationProtocol; +- private volatile boolean needTask; - -- if (version >= 8) { -- if (!isDestroyed()) { -- if (clientMode) { -- final List<String> sniHostNames = Java8SslUtils.getSniHostNames(sslParameters); -- for (String name: sniHostNames) { -- SSL.setTlsExtHostName(ssl, name); -- } -- this.sniHostNames = sniHostNames; -- } -- if (Java8SslUtils.getUseCipherSuitesOrder(sslParameters)) { -- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); -- } else { -- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); -- } -- } -- matchers = sslParameters.getSNIMatchers(); +- // Reference Counting +- private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak; +- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { +- @Override +- public ReferenceCounted touch(Object hint) { +- if (leak != null) { +- leak.record(hint); - } - -- final String endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm(); -- final boolean endPointVerificationEnabled = endPointIdentificationAlgorithm != null && -- !endPointIdentificationAlgorithm.isEmpty(); -- SSL.setHostNameValidation(ssl, DEFAULT_HOSTNAME_VALIDATION_FLAGS, -- endPointVerificationEnabled ? getPeerHost() : null); -- // If the user asks for hostname verification we must ensure we verify the peer. -- // If the user disables hostname verification we leave it up to the user to change the mode manually. -- if (clientMode && endPointVerificationEnabled) { -- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1); -- } +- return ReferenceCountedOpenSslEngine.this; +- } - -- this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm; -- algorithmConstraints = sslParameters.getAlgorithmConstraints(); +- @Override +- protected void deallocate() { +- shutdown(); +- if (leak != null) { +- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this); +- assert closed; +- } +- parentContext.release(); - } -- super.setSSLParameters(sslParameters); -- } +- }; - -- private boolean isDestroyed() { -- return destroyed != 0; -- } +- private volatile ClientAuth clientAuth = ClientAuth.NONE; +- private volatile Certificate[] localCertificateChain; - -- static int calculateOutNetBufSize(int pendingBytes, int numComponents) { -- return (int) min(MAX_ENCRYPTED_PACKET_LENGTH, -- pendingBytes + (long) MAX_TLS_RECORD_OVERHEAD_LENGTH * numComponents); -- } +- // Updated once a new handshake is started and so the SSLSession reused. +- private volatile long lastAccessed = -1; - -- final boolean checkSniHostnameMatch(String hostname) { -- return Java8SslUtils.checkSniHostnameMatch(matchers, hostname); -- } +- private String endPointIdentificationAlgorithm; +- // Store as object as AlgorithmConstraints only exists since java 7. +- private Object algorithmConstraints; +- private List<String> sniHostNames; - -- private final class OpenSslSession implements SSLSession, ApplicationProtocolAccessor { -- private final OpenSslSessionContext sessionContext; +- // Mark as volatile as accessed by checkSniHostnameMatch(...) and also not specify the SNIMatcher type to allow us +- // using it with java7. +- private volatile Collection<?> matchers; - -- // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any -- // thread. -- private X509Certificate[] x509PeerCerts; -- private Certificate[] peerCerts; -- private String protocol; -- private String applicationProtocol; -- private String cipher; -- private byte[] id; -- private long creationTime; +- // SSL Engine status variables +- private boolean isInboundDone; +- private boolean outboundClosed; - -- // lazy init for memory reasons -- private Map<String, Object> values; +- final boolean jdkCompatibilityMode; +- private final boolean clientMode; +- final ByteBufAllocator alloc; +- private final OpenSslEngineMap engineMap; +- private final OpenSslApplicationProtocolNegotiator apn; +- private final ReferenceCountedOpenSslContext parentContext; +- private final OpenSslSession session; +- private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1]; +- private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1]; +- private final boolean enableOcsp; +- private int maxWrapOverhead; +- private int maxWrapBufferSize; +- private Throwable pendingException; - -- OpenSslSession(OpenSslSessionContext sessionContext) { -- this.sessionContext = sessionContext; -- } +- /** +- * Create a new instance. +- * @param context Reference count release responsibility is not transferred! The callee still owns this object. +- * @param alloc The allocator to use. +- * @param peerHost The peer host name. +- * @param peerPort The peer port. +- * @param jdkCompatibilityMode {@code true} to behave like described in +- * https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html. +- * {@code false} allows for partial and/or multiple packets to be process in a single +- * wrap or unwrap call. +- * @param leakDetection {@code true} to enable leak detection of this object. +- */ +- ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context, final ByteBufAllocator alloc, String peerHost, +- int peerPort, boolean jdkCompatibilityMode, boolean leakDetection) { +- super(peerHost, peerPort); +- OpenSsl.ensureAvailability(); +- this.alloc = checkNotNull(alloc, "alloc"); +- apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator(); +- clientMode = context.isClient(); +- if (PlatformDependent.javaVersion() >= 7) { +- session = new ExtendedOpenSslSession(new DefaultOpenSslSession(context.sessionContext())) { +- private String[] peerSupportedSignatureAlgorithms; +- private List requestedServerNames; - -- @Override -- public byte[] getId() { -- synchronized (ReferenceCountedOpenSslEngine.this) { -- if (id == null) { -- return EmptyArrays.EMPTY_BYTES; +- @Override +- public List getRequestedServerNames() { +- if (clientMode) { +- return Java8SslUtils.getSniHostNames(sniHostNames); +- } else { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (requestedServerNames == null) { +- if (isDestroyed()) { +- requestedServerNames = Collections.emptyList(); +- } else { +- String name = SSL.getSniHostname(ssl); +- if (name == null) { +- requestedServerNames = Collections.emptyList(); +- } else { +- // Convert to bytes as we do not want to do any strict validation of the +- // SNIHostName while creating it. +- requestedServerNames = +- Java8SslUtils.getSniHostName( +- SSL.getSniHostname(ssl).getBytes(CharsetUtil.UTF_8)); +- } +- } +- } +- return requestedServerNames; +- } +- } - } -- return id.clone(); -- } -- } - -- @Override -- public SSLSessionContext getSessionContext() { -- return sessionContext; -- } +- @Override +- public String[] getPeerSupportedSignatureAlgorithms() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (peerSupportedSignatureAlgorithms == null) { +- if (isDestroyed()) { +- peerSupportedSignatureAlgorithms = EmptyArrays.EMPTY_STRINGS; +- } else { +- String[] algs = SSL.getSigAlgs(ssl); +- if (algs == null) { +- peerSupportedSignatureAlgorithms = EmptyArrays.EMPTY_STRINGS; +- } else { +- Set<String> algorithmList = new LinkedHashSet<String>(algs.length); +- for (String alg: algs) { +- String converted = SignatureAlgorithmConverter.toJavaName(alg); - -- @Override -- public long getCreationTime() { -- synchronized (ReferenceCountedOpenSslEngine.this) { -- if (creationTime == 0 && !isDestroyed()) { -- creationTime = SSL.getTime(ssl) * 1000L; +- if (converted != null) { +- algorithmList.add(converted); +- } +- } +- peerSupportedSignatureAlgorithms = algorithmList.toArray(new String[0]); +- } +- } +- } +- return peerSupportedSignatureAlgorithms.clone(); +- } - } -- } -- return creationTime; -- } -- -- @Override -- public long getLastAccessedTime() { -- long lastAccessed = ReferenceCountedOpenSslEngine.this.lastAccessed; -- // if lastAccessed is -1 we will just return the creation time as the handshake was not started yet. -- return lastAccessed == -1 ? getCreationTime() : lastAccessed; -- } - -- @Override -- public void invalidate() { -- synchronized (ReferenceCountedOpenSslEngine.this) { -- if (!isDestroyed()) { -- SSL.setTimeout(ssl, 0); +- @Override +- public List<byte[]> getStatusResponses() { +- byte[] ocspResponse = null; +- if (enableOcsp && clientMode) { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (!isDestroyed()) { +- ocspResponse = SSL.getOcspResponse(ssl); +- } +- } +- } +- return ocspResponse == null ? +- Collections.<byte[]>emptyList() : Collections.singletonList(ocspResponse); - } -- } +- }; +- } else { +- session = new DefaultOpenSslSession(context.sessionContext()); - } -- -- @Override -- public boolean isValid() { -- synchronized (ReferenceCountedOpenSslEngine.this) { -- if (!isDestroyed()) { -- return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L) < (SSL.getTime(ssl) * 1000L); -- } -- } -- return false; +- engineMap = context.engineMap; +- enableOcsp = context.enableOcsp; +- if (!context.sessionContext().useKeyManager()) { +- // If we do not use the KeyManagerFactory we need to set localCertificateChain now. +- // When we use a KeyManagerFactory it will be set during setKeyMaterial(...). +- localCertificateChain = context.keyCertChain; - } - -- @Override -- public void putValue(String name, Object value) { -- if (name == null) { -- throw new NullPointerException("name"); -- } -- if (value == null) { -- throw new NullPointerException("value"); -- } -- Map<String, Object> values = this.values; -- if (values == null) { -- // Use size of 2 to keep the memory overhead small -- values = this.values = new HashMap<String, Object>(2); -- } -- Object old = values.put(name, value); -- if (value instanceof SSLSessionBindingListener) { -- ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name)); -- } -- notifyUnbound(old, name); +- this.jdkCompatibilityMode = jdkCompatibilityMode; +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- final long finalSsl; +- try { +- finalSsl = SSL.newSSL(context.ctx, !context.isClient()); +- } finally { +- readerLock.unlock(); - } +- synchronized (this) { +- ssl = finalSsl; +- try { +- networkBIO = SSL.bioNewByteBuffer(ssl, context.getBioNonApplicationBufferSize()); - -- @Override -- public Object getValue(String name) { -- if (name == null) { -- throw new NullPointerException("name"); -- } -- if (values == null) { -- return null; -- } -- return values.get(name); -- } +- // 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 : context.clientAuth); - -- @Override -- public void removeValue(String name) { -- if (name == null) { -- throw new NullPointerException("name"); -- } -- Map<String, Object> values = this.values; -- if (values == null) { -- return; -- } -- Object old = values.remove(name); -- notifyUnbound(old, name); -- } +- if (context.protocols != null) { +- setEnabledProtocols(context.protocols); +- } - -- @Override -- public String[] getValueNames() { -- Map<String, Object> values = this.values; -- if (values == null || values.isEmpty()) { -- return EmptyArrays.EMPTY_STRINGS; -- } -- return values.keySet().toArray(new String[values.size()]); -- } +- // Use SNI if peerHost was specified and a valid hostname +- // See https://github.com/netty/netty/issues/4746 +- if (clientMode && SslUtils.isValidHostNameForSNI(peerHost)) { +- SSL.setTlsExtHostName(ssl, peerHost); +- sniHostNames = Collections.singletonList(peerHost); +- } - -- private void notifyUnbound(Object value, String name) { -- if (value instanceof SSLSessionBindingListener) { -- ((SSLSessionBindingListener) value).valueUnbound(new SSLSessionBindingEvent(this, name)); -- } -- } +- if (enableOcsp) { +- SSL.enableOcsp(ssl); +- } - -- /** -- * Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by -- * the user. -- */ -- void handshakeFinished() throws SSLException { -- synchronized (ReferenceCountedOpenSslEngine.this) { -- if (!isDestroyed()) { -- id = SSL.getSessionId(ssl); -- cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl)); -- protocol = SSL.getVersion(ssl); +- if (!jdkCompatibilityMode) { +- SSL.setMode(ssl, SSL.getMode(ssl) | SSL.SSL_MODE_ENABLE_PARTIAL_WRITE); +- } - -- initPeerCerts(); -- selectApplicationProtocol(); +- // setMode may impact the overhead. +- calculateMaxWrapOverhead(); +- } catch (Throwable cause) { +- // Call shutdown so we are sure we correctly release all native memory and also guard against the +- // case when shutdown() will be called by the finalizer again. +- shutdown(); - -- handshakeState = HandshakeState.FINISHED; -- } else { -- throw new SSLException("Already closed"); -- } +- PlatformDependent.throwException(cause); - } - } - -- /** -- * Init peer certificates that can be obtained via {@link #getPeerCertificateChain()} -- * and {@link #getPeerCertificates()}. -- */ -- private void initPeerCerts() { -- // Return the full chain from the JNI layer. -- byte[][] chain = SSL.getPeerCertChain(ssl); -- if (clientMode) { -- if (isEmpty(chain)) { -- peerCerts = EMPTY_CERTIFICATES; -- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES; -- } else { -- peerCerts = new Certificate[chain.length]; -- x509PeerCerts = new X509Certificate[chain.length]; -- initCerts(chain, 0); -- } -- } else { -- // if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer -- // certificate. We use SSL_get_peer_certificate to get it in this case and add it to our -- // array later. -- // -- // See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html -- byte[] clientCert = SSL.getPeerCertificate(ssl); -- if (isEmpty(clientCert)) { -- peerCerts = EMPTY_CERTIFICATES; -- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES; -- } else { -- if (isEmpty(chain)) { -- peerCerts = new Certificate[] {new OpenSslX509Certificate(clientCert)}; -- x509PeerCerts = new X509Certificate[] {new OpenSslJavaxX509Certificate(clientCert)}; -- } else { -- peerCerts = new Certificate[chain.length + 1]; -- x509PeerCerts = new X509Certificate[chain.length + 1]; -- peerCerts[0] = new OpenSslX509Certificate(clientCert); -- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert); -- initCerts(chain, 1); -- } -- } -- } +- // Now that everything looks good and we're going to successfully return the +- // object so we need to retain a reference to the parent context. +- parentContext = context; +- parentContext.retain(); +- +- // Only create the leak after everything else was executed and so ensure we don't produce a false-positive for +- // the ResourceLeakDetector. +- leak = leakDetection ? leakDetector.track(this) : null; +- } +- +- final synchronized String[] authMethods() { +- if (isDestroyed()) { +- return EmptyArrays.EMPTY_STRINGS; - } +- return SSL.authenticationMethods(ssl); +- } - -- private void initCerts(byte[][] chain, int startPos) { -- for (int i = 0; i < chain.length; i++) { -- int certPos = startPos + i; -- peerCerts[certPos] = new OpenSslX509Certificate(chain[i]); -- x509PeerCerts[certPos] = new OpenSslJavaxX509Certificate(chain[i]); +- final boolean setKeyMaterial(OpenSslKeyMaterial keyMaterial) throws Exception { +- synchronized (this) { +- if (isDestroyed()) { +- return false; - } +- SSL.setKeyMaterial(ssl, keyMaterial.certificateChainAddress(), keyMaterial.privateKeyAddress()); - } +- localCertificateChain = keyMaterial.certificateChain(); +- return true; +- } - -- /** -- * Select the application protocol used. -- */ -- private void selectApplicationProtocol() throws SSLException { -- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior = apn.selectedListenerFailureBehavior(); -- List<String> protocols = apn.protocols(); -- String applicationProtocol; -- switch (apn.protocol()) { -- case NONE: -- break; -- // We always need to check for applicationProtocol == null as the remote peer may not support -- // the TLS extension or may have returned an empty selection. -- case ALPN: -- applicationProtocol = SSL.getAlpnSelected(ssl); -- if (applicationProtocol != null) { -- this.applicationProtocol = selectApplicationProtocol( -- protocols, behavior, applicationProtocol); -- } -- break; -- case NPN: -- applicationProtocol = SSL.getNextProtoNegotiated(ssl); -- if (applicationProtocol != null) { -- this.applicationProtocol = selectApplicationProtocol( -- protocols, behavior, applicationProtocol); -- } -- break; -- case NPN_AND_ALPN: -- applicationProtocol = SSL.getAlpnSelected(ssl); -- if (applicationProtocol == null) { -- applicationProtocol = SSL.getNextProtoNegotiated(ssl); -- } -- if (applicationProtocol != null) { -- this.applicationProtocol = selectApplicationProtocol( -- protocols, behavior, applicationProtocol); -- } -- break; -- default: -- throw new Error(); -- } +- final synchronized SecretKeySpec masterKey() { +- if (isDestroyed()) { +- return null; - } +- return new SecretKeySpec(SSL.getMasterKey(ssl), "AES"); +- } - -- private String selectApplicationProtocol(List<String> protocols, -- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior, -- String applicationProtocol) throws SSLException { -- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) { -- return applicationProtocol; -- } else { -- int size = protocols.size(); -- assert size > 0; -- if (protocols.contains(applicationProtocol)) { -- return applicationProtocol; -- } else { -- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) { -- return protocols.get(size - 1); -- } else { -- throw new SSLException("unknown protocol " + applicationProtocol); -- } -- } +- /** +- * Sets the OCSP response. +- */ +- @UnstableApi +- public void setOcspResponse(byte[] response) { +- if (!enableOcsp) { +- throw new IllegalStateException("OCSP stapling is not enabled"); +- } +- +- if (clientMode) { +- throw new IllegalStateException("Not a server SSLEngine"); +- } +- +- synchronized (this) { +- if (!isDestroyed()) { +- SSL.setOcspResponse(ssl, response); - } - } +- } - -- @Override -- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { -- synchronized (ReferenceCountedOpenSslEngine.this) { -- if (isEmpty(peerCerts)) { -- throw new SSLPeerUnverifiedException("peer not verified"); -- } -- return peerCerts.clone(); +- /** +- * Returns the OCSP response or {@code null} if the server didn't provide a stapled OCSP response. +- */ +- @UnstableApi +- public byte[] getOcspResponse() { +- if (!enableOcsp) { +- throw new IllegalStateException("OCSP stapling is not enabled"); +- } +- +- if (!clientMode) { +- throw new IllegalStateException("Not a client SSLEngine"); +- } +- +- synchronized (this) { +- if (isDestroyed()) { +- return EmptyArrays.EMPTY_BYTES; - } +- return SSL.getOcspResponse(ssl); - } +- } - -- @Override -- public Certificate[] getLocalCertificates() { -- if (localCerts == null) { +- @Override +- public final int refCnt() { +- return refCnt.refCnt(); +- } +- +- @Override +- public final ReferenceCounted retain() { +- refCnt.retain(); +- return this; +- } +- +- @Override +- public final ReferenceCounted retain(int increment) { +- refCnt.retain(increment); +- return this; +- } +- +- @Override +- public final ReferenceCounted touch() { +- refCnt.touch(); +- return this; +- } +- +- @Override +- public final ReferenceCounted touch(Object hint) { +- refCnt.touch(hint); +- return this; +- } +- +- @Override +- public final boolean release() { +- return refCnt.release(); +- } +- +- @Override +- public final boolean release(int decrement) { +- return refCnt.release(decrement); +- } +- +- @Override +- public final synchronized SSLSession getHandshakeSession() { +- // Javadocs state return value should be: +- // null if this instance is not currently handshaking, or if the current handshake has not +- // progressed far enough to create a basic SSLSession. Otherwise, this method returns the +- // SSLSession currently being negotiated. +- switch(handshakeState) { +- case NOT_STARTED: +- case FINISHED: - return null; -- } -- return localCerts.clone(); +- default: +- return session; - } +- } - -- @Override -- public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { -- synchronized (ReferenceCountedOpenSslEngine.this) { -- if (isEmpty(x509PeerCerts)) { -- throw new SSLPeerUnverifiedException("peer not verified"); +- /** +- * Returns the pointer to the {@code SSL} object for this {@link ReferenceCountedOpenSslEngine}. +- * Be aware that it is freed as soon as the {@link #release()} or {@link #shutdown()} methods are called. +- * At this point {@code 0} will be returned. +- */ +- public final synchronized long sslPointer() { +- return ssl; +- } +- +- /** +- * Destroys this engine. +- */ +- public final synchronized void shutdown() { +- if (!destroyed) { +- destroyed = true; +- engineMap.remove(ssl); +- SSL.freeSSL(ssl); +- ssl = networkBIO = 0; +- +- isInboundDone = outboundClosed = true; +- } +- +- // On shutdown clear all errors +- SSL.clearError(); +- } +- +- /** +- * Write plaintext data to the OpenSSL internal BIO +- * +- * Calling this function with src.remaining == 0 is undefined. +- */ +- private int writePlaintextData(final ByteBuffer src, int len) { +- final int pos = src.position(); +- final int limit = src.limit(); +- final int sslWrote; +- +- if (src.isDirect()) { +- sslWrote = SSL.writeToSSL(ssl, bufferAddress(src) + pos, len); +- if (sslWrote > 0) { +- src.position(pos + sslWrote); +- } +- } else { +- ByteBuf buf = alloc.directBuffer(len); +- try { +- src.limit(pos + len); +- +- buf.setBytes(0, src); +- src.limit(limit); +- +- sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len); +- if (sslWrote > 0) { +- src.position(pos + sslWrote); +- } else { +- src.position(pos); - } -- return x509PeerCerts.clone(); +- } finally { +- buf.release(); - } - } +- return sslWrote; +- } - -- @Override -- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { -- Certificate[] peer = getPeerCertificates(); -- // No need for null or length > 0 is needed as this is done in getPeerCertificates() -- // already. -- return ((java.security.cert.X509Certificate) peer[0]).getSubjectX500Principal(); -- } +- /** +- * Write encrypted data to the OpenSSL network BIO. +- */ +- private ByteBuf writeEncryptedData(final ByteBuffer src, int len) { +- final int pos = src.position(); +- if (src.isDirect()) { +- SSL.bioSetByteBuffer(networkBIO, bufferAddress(src) + pos, len, false); +- } else { +- final ByteBuf buf = alloc.directBuffer(len); +- try { +- final int limit = src.limit(); +- src.limit(pos + len); +- buf.writeBytes(src); +- // Restore the original position and limit because we don't want to consume from `src`. +- src.position(pos); +- src.limit(limit); - -- @Override -- public Principal getLocalPrincipal() { -- Certificate[] local = localCerts; -- if (local == null || local.length == 0) { -- return null; +- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false); +- return buf; +- } catch (Throwable cause) { +- buf.release(); +- PlatformDependent.throwException(cause); - } -- return ((java.security.cert.X509Certificate) local[0]).getIssuerX500Principal(); - } +- return null; +- } - -- @Override -- public String getCipherSuite() { -- synchronized (ReferenceCountedOpenSslEngine.this) { -- if (cipher == null) { -- return INVALID_CIPHER; -- } -- return cipher; +- /** +- * Read plaintext data from the OpenSSL internal BIO +- */ +- private int readPlaintextData(final ByteBuffer dst) { +- final int sslRead; +- final int pos = dst.position(); +- if (dst.isDirect()) { +- sslRead = SSL.readFromSSL(ssl, bufferAddress(dst) + pos, dst.limit() - pos); +- if (sslRead > 0) { +- dst.position(pos + sslRead); - } -- } -- -- @Override -- public String getProtocol() { -- String protocol = this.protocol; -- if (protocol == null) { -- synchronized (ReferenceCountedOpenSslEngine.this) { -- if (!isDestroyed()) { -- protocol = SSL.getVersion(ssl); -- } else { -- protocol = StringUtil.EMPTY_STRING; -- } +- } else { +- final int limit = dst.limit(); +- final int len = min(maxEncryptedPacketLength0(), limit - pos); +- final ByteBuf buf = alloc.directBuffer(len); +- try { +- sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len); +- if (sslRead > 0) { +- dst.limit(pos + sslRead); +- buf.getBytes(buf.readerIndex(), dst); +- dst.limit(limit); - } +- } finally { +- buf.release(); - } -- return protocol; -- } -- -- @Override -- public String getApplicationProtocol() { -- synchronized (ReferenceCountedOpenSslEngine.this) { -- return applicationProtocol; -- } -- } -- -- @Override -- public String getPeerHost() { -- return ReferenceCountedOpenSslEngine.this.getPeerHost(); - } - -- @Override -- public int getPeerPort() { -- return ReferenceCountedOpenSslEngine.this.getPeerPort(); -- } +- return sslRead; +- } - -- @Override -- public int getPacketBufferSize() { -- return MAX_ENCRYPTED_PACKET_LENGTH; -- } +- /** +- * Visible only for testing! +- */ +- final synchronized int maxWrapOverhead() { +- return maxWrapOverhead; +- } - -- @Override -- public int getApplicationBufferSize() { -- return MAX_PLAINTEXT_LENGTH; -- } +- /** +- * Visible only for testing! +- */ +- final synchronized int maxEncryptedPacketLength() { +- return maxEncryptedPacketLength0(); - } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java -deleted file mode 100644 -index 4c9df31..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java -+++ /dev/null -@@ -1,239 +0,0 @@ --/* -- * 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.internal.tcnative.SSL; --import io.netty.internal.tcnative.SSLContext; --import io.netty.internal.tcnative.SniHostNameMatcher; --import io.netty.util.internal.PlatformDependent; --import io.netty.util.internal.logging.InternalLogger; --import io.netty.util.internal.logging.InternalLoggerFactory; +- /** +- * This method is intentionally not synchronized, only use if you know you are in the EventLoop +- * thread and visibility on {@link #maxWrapOverhead} is achieved via other synchronized blocks. +- */ +- final int maxEncryptedPacketLength0() { +- return maxWrapOverhead + MAX_PLAINTEXT_LENGTH; +- } - --import java.security.KeyStore; --import java.security.PrivateKey; --import java.security.cert.X509Certificate; --import javax.net.ssl.KeyManagerFactory; --import javax.net.ssl.SSLException; --import javax.net.ssl.TrustManagerFactory; --import javax.net.ssl.X509ExtendedKeyManager; --import javax.net.ssl.X509ExtendedTrustManager; --import javax.net.ssl.X509KeyManager; --import javax.net.ssl.X509TrustManager; +- /** +- * This method is intentionally not synchronized, only use if you know you are in the EventLoop +- * thread and visibility on {@link #maxWrapBufferSize} and {@link #maxWrapOverhead} is achieved +- * via other synchronized blocks. +- */ +- final int calculateMaxLengthForWrap(int plaintextLength, int numComponents) { +- return (int) min(maxWrapBufferSize, plaintextLength + (long) maxWrapOverhead * numComponents); +- } - --import static io.netty.util.internal.ObjectUtil.checkNotNull; +- final synchronized int sslPending() { +- return sslPending0(); +- } - --/** -- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. -- * <p>Instances of this class must be {@link #release() released} or else native memory will leak! -- * -- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine} -- * which depends upon the instance of this class is released. Otherwise if any method of -- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. -- */ --public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext { -- private static final InternalLogger logger = -- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class); -- private static final byte[] ID = {'n', 'e', 't', 't', 'y'}; -- private final OpenSslServerSessionContext sessionContext; -- private final OpenSslKeyMaterialManager keyMaterialManager; +- /** +- * It is assumed this method is called in a synchronized block (or the constructor)! +- */ +- private void calculateMaxWrapOverhead() { +- maxWrapOverhead = SSL.getMaxWrapOverhead(ssl); - -- ReferenceCountedOpenSslServerContext( -- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, -- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, -- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, -- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, -- boolean enableOcsp) throws SSLException { -- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, -- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, -- enableOcsp); +- // maxWrapBufferSize must be set after maxWrapOverhead because there is a dependency on this value. +- // If jdkCompatibility mode is off we allow enough space to encrypt 16 buffers at a time. This could be +- // configurable in the future if necessary. +- maxWrapBufferSize = jdkCompatibilityMode ? maxEncryptedPacketLength0() : maxEncryptedPacketLength0() << 4; - } - -- private ReferenceCountedOpenSslServerContext( -- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, -- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, -- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, -- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, -- boolean enableOcsp) throws SSLException { -- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, -- clientAuth, protocols, startTls, enableOcsp, true); -- // Create a new SSL_CTX and configure it. -- boolean success = false; -- try { -- ServerContext context = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, -- keyCertChain, key, keyPassword, keyManagerFactory); -- sessionContext = context.sessionContext; -- keyMaterialManager = context.keyMaterialManager; -- success = true; -- } finally { -- if (!success) { -- release(); -- } -- } +- private int sslPending0() { +- // OpenSSL has a limitation where if you call SSL_pending before the handshake is complete OpenSSL will throw a +- // "called a function you should not call" error. Using the TLS_method instead of SSLv23_method may solve this +- // issue but this API is only available in 1.1.0+ [1]. +- // [1] https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_new.html +- return handshakeState != HandshakeState.FINISHED ? 0 : SSL.sslPending(ssl); - } - -- @Override -- public OpenSslServerSessionContext sessionContext() { -- return sessionContext; +- private boolean isBytesAvailableEnoughForWrap(int bytesAvailable, int plaintextLength, int numComponents) { +- return bytesAvailable - (long) maxWrapOverhead * numComponents >= plaintextLength; - } - - @Override -- OpenSslKeyMaterialManager keyMaterialManager() { -- return keyMaterialManager; -- } +- public final SSLEngineResult wrap( +- final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst) throws SSLException { +- // Throw required runtime exceptions +- if (srcs == null) { +- throw new IllegalArgumentException("srcs is null"); +- } +- if (dst == null) { +- throw new IllegalArgumentException("dst is null"); +- } - -- static final class ServerContext { -- OpenSslServerSessionContext sessionContext; -- OpenSslKeyMaterialManager keyMaterialManager; -- } +- if (offset >= srcs.length || offset + length > srcs.length) { +- throw new IndexOutOfBoundsException( +- "offset: " + offset + ", length: " + length + +- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))"); +- } - -- static ServerContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx, OpenSslEngineMap engineMap, -- X509Certificate[] trustCertCollection, -- TrustManagerFactory trustManagerFactory, -- X509Certificate[] keyCertChain, PrivateKey key, -- String keyPassword, KeyManagerFactory keyManagerFactory) -- throws SSLException { -- ServerContext result = new ServerContext(); -- try { -- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); -- if (!OpenSsl.useKeyManagerFactory()) { -- if (keyManagerFactory != null) { -- throw new IllegalArgumentException( -- "KeyManagerFactory not supported"); +- if (dst.isReadOnly()) { +- throw new ReadOnlyBufferException(); +- } +- +- synchronized (this) { +- if (isOutboundDone()) { +- // All drained in the outbound buffer +- return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_UNWRAP_CLOSED; +- } +- +- int bytesProduced = 0; +- ByteBuf bioReadCopyBuf = null; +- try { +- // Setup the BIO buffer so that we directly write the encryption results into dst. +- if (dst.isDirect()) { +- SSL.bioSetByteBuffer(networkBIO, bufferAddress(dst) + dst.position(), dst.remaining(), +- true); +- } else { +- bioReadCopyBuf = alloc.directBuffer(dst.remaining()); +- SSL.bioSetByteBuffer(networkBIO, memoryAddress(bioReadCopyBuf), bioReadCopyBuf.writableBytes(), +- true); +- } +- +- int bioLengthBefore = SSL.bioLengthByteBuffer(networkBIO); +- +- // Explicitly use outboundClosed as we want to drain any bytes that are still present. +- if (outboundClosed) { +- // If the outbound was closed we want to ensure we can produce the alert to the destination buffer. +- // This is true even if we not using jdkCompatibilityMode. +- // +- // We use a plaintextLength of 2 as we at least want to have an alert fit into it. +- // https://tools.ietf.org/html/rfc5246#section-7.2 +- if (!isBytesAvailableEnoughForWrap(dst.remaining(), 2, 1)) { +- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0); +- } +- +- // There is something left to drain. +- // See https://github.com/netty/netty/issues/6260 +- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); +- if (bytesProduced <= 0) { +- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0); +- } +- // It is possible when the outbound was closed there was not enough room in the non-application +- // buffers to hold the close_notify. We should keep trying to close until we consume all the data +- // OpenSSL can give us. +- if (!doSSLShutdown()) { +- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, bytesProduced); +- } +- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO); +- return newResultMayFinishHandshake(NEED_WRAP, 0, bytesProduced); - } -- checkNotNull(keyCertChain, "keyCertChain"); - -- setKeyMaterial(ctx, keyCertChain, key, keyPassword); -- } else { -- // javadocs state that keyManagerFactory has precedent over keyCertChain, and we must have a -- // keyManagerFactory for the server so build one if it is not specified. -- if (keyManagerFactory == null) { -- keyManagerFactory = buildKeyManagerFactory( -- keyCertChain, key, keyPassword, keyManagerFactory); -- } -- X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers()); -- result.keyMaterialManager = useExtendedKeyManager(keyManager) ? -- new OpenSslExtendedKeyMaterialManager( -- (X509ExtendedKeyManager) keyManager, keyPassword) : -- new OpenSslKeyMaterialManager(keyManager, keyPassword); -- } -- } catch (Exception e) { -- throw new SSLException("failed to set certificate and key", e); -- } -- try { -- if (trustCertCollection != null) { -- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory); -- } else if (trustManagerFactory == null) { -- // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works -- trustManagerFactory = TrustManagerFactory.getInstance( -- TrustManagerFactory.getDefaultAlgorithm()); -- trustManagerFactory.init((KeyStore) null); -- } +- // Flush any data that may be implicitly generated by OpenSSL (handshake, close, etc..). +- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING; +- // Prepare OpenSSL to work in server mode and receive handshake +- if (handshakeState != HandshakeState.FINISHED) { +- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) { +- // Update accepted so we know we triggered the handshake via wrap +- handshakeState = HandshakeState.STARTED_IMPLICITLY; +- } +- +- // Flush any data that may have been written implicitly during the handshake by OpenSSL. +- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); +- +- if (pendingException != null) { +- // TODO(scott): It is possible that when the handshake failed there was not enough room in the +- // non-application buffers to hold the alert. We should get all the data before progressing on. +- // However I'm not aware of a way to do this with the OpenSSL APIs. +- // See https://github.com/netty/netty/issues/6385. +- +- // We produced / consumed some data during the handshake, signal back to the caller. +- // If there is a handshake exception and we have produced data, we should send the data before +- // we allow handshake() to throw the handshake exception. +- // +- // When the user calls wrap() again we will propagate the handshake error back to the user as +- // soon as there is no more data to was produced (as part of an alert etc). +- if (bytesProduced > 0) { +- return newResult(NEED_WRAP, 0, bytesProduced); +- } +- // Nothing was produced see if there is a handshakeException that needs to be propagated +- // to the caller by calling handshakeException() which will return the right HandshakeStatus +- // if it can "recover" from the exception for now. +- return newResult(handshakeException(), 0, 0); +- } +- +- status = handshake(); +- +- // Handshake may have generated more data, for example if the internal SSL buffer is small +- // we may have freed up space by flushing above. +- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO); +- +- if (status == NEED_TASK) { +- return newResult(status, 0, bytesProduced); +- } +- +- if (bytesProduced > 0) { +- // If we have filled up the dst buffer and we have not finished the handshake we should try to +- // wrap again. Otherwise we should only try to wrap again if there is still data pending in +- // SSL buffers. +- return newResult(mayFinishHandshake(status != FINISHED ? +- bytesProduced == bioLengthBefore ? NEED_WRAP : +- getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) : FINISHED), +- 0, bytesProduced); +- } +- +- if (status == NEED_UNWRAP) { +- // Signal if the outbound is done or not. +- return isOutboundDone() ? NEED_UNWRAP_CLOSED : NEED_UNWRAP_OK; +- } - -- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); +- // Explicit use outboundClosed and not outboundClosed() as we want to drain any bytes that are +- // still present. +- if (outboundClosed) { +- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); +- return newResultMayFinishHandshake(status, 0, bytesProduced); +- } +- } - -- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as -- // otherwise the context can never be collected. This is because the JNI code holds -- // a global reference to the callbacks. -- // -- // See https://github.com/netty/netty/issues/5372 +- final int endOffset = offset + length; +- if (jdkCompatibilityMode) { +- int srcsLen = 0; +- for (int i = offset; i < endOffset; ++i) { +- final ByteBuffer src = srcs[i]; +- if (src == null) { +- throw new IllegalArgumentException("srcs[" + i + "] is null"); +- } +- if (srcsLen == MAX_PLAINTEXT_LENGTH) { +- continue; +- } - -- // Use this to prevent an error when running on java < 7 -- if (useExtendedTrustManager(manager)) { -- SSLContext.setCertVerifyCallback(ctx, -- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager)); -- } else { -- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager)); -- } +- srcsLen += src.remaining(); +- if (srcsLen > MAX_PLAINTEXT_LENGTH || srcsLen < 0) { +- // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to MAX_PLAINTEXT_LENGTH. +- // This also help us to guard against overflow. +- // We not break out here as we still need to check for null entries in srcs[]. +- srcsLen = MAX_PLAINTEXT_LENGTH; +- } +- } - -- X509Certificate[] issuers = manager.getAcceptedIssuers(); -- if (issuers != null && issuers.length > 0) { -- long bio = 0; -- try { -- bio = toBIO(issuers); -- if (!SSLContext.setCACertificateBio(ctx, bio)) { -- throw new SSLException("unable to setup accepted issuers for trustmanager " + manager); +- // jdkCompatibilityMode will only produce a single TLS packet, and we don't aggregate src buffers, +- // so we always fix the number of buffers to 1 when checking if the dst buffer is large enough. +- if (!isBytesAvailableEnoughForWrap(dst.remaining(), srcsLen, 1)) { +- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0); - } -- } finally { -- freeBio(bio); - } -- } - -- if (PlatformDependent.javaVersion() >= 8) { -- // Only do on Java8+ as SNIMatcher is not supported in earlier releases. -- // IMPORTANT: The callbacks set for hostname matching must be static to prevent memory leak as -- // otherwise the context can never be collected. This is because the JNI code holds -- // a global reference to the matcher. -- SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engineMap)); -- } -- } catch (SSLException e) { -- throw e; -- } catch (Exception e) { -- throw new SSLException("unable to setup trustmanager", e); -- } +- // There was no pending data in the network BIO -- encrypt any application data +- int bytesConsumed = 0; +- assert bytesProduced == 0; - -- result.sessionContext = new OpenSslServerSessionContext(thiz); -- result.sessionContext.setSessionIdContext(ID); -- return result; -- } +- // Flush any data that may have been written implicitly by OpenSSL in case a shutdown/alert occurs. +- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); - -- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier { -- private final X509TrustManager manager; +- if (bytesProduced > 0) { +- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced); +- } +- // There was a pending exception that we just delayed because there was something to produce left. +- // Throw it now and shutdown the engine. +- if (pendingException != null) { +- Throwable error = pendingException; +- pendingException = null; +- shutdown(); +- // Throw a new exception wrapping the pending exception, so the stacktrace is meaningful and +- // contains all the details. +- throw new SSLException(error); +- } - -- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) { -- super(engineMap); -- this.manager = manager; -- } +- for (; offset < endOffset; ++offset) { +- final ByteBuffer src = srcs[offset]; +- final int remaining = src.remaining(); +- if (remaining == 0) { +- continue; +- } - -- @Override -- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) -- throws Exception { -- manager.checkClientTrusted(peerCerts, auth); -- } -- } +- final int bytesWritten; +- if (jdkCompatibilityMode) { +- // Write plaintext application data to the SSL engine. We don't have to worry about checking +- // if there is enough space if jdkCompatibilityMode because we only wrap at most +- // MAX_PLAINTEXT_LENGTH and we loop over the input before hand and check if there is space. +- bytesWritten = writePlaintextData(src, min(remaining, MAX_PLAINTEXT_LENGTH - bytesConsumed)); +- } else { +- // OpenSSL's SSL_write keeps state between calls. We should make sure the amount we attempt to +- // write is guaranteed to succeed so we don't have to worry about keeping state consistent +- // between calls. +- final int availableCapacityForWrap = dst.remaining() - bytesProduced - maxWrapOverhead; +- if (availableCapacityForWrap <= 0) { +- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), bytesConsumed, +- bytesProduced); +- } +- bytesWritten = writePlaintextData(src, min(remaining, availableCapacityForWrap)); +- } - -- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier { -- private final X509ExtendedTrustManager manager; +- // Determine how much encrypted data was generated. +- // +- // Even if SSL_write doesn't consume any application data it is possible that OpenSSL will +- // produce non-application data into the BIO. For example session tickets.... +- // See https://github.com/netty/netty/issues/10041 +- final int pendingNow = SSL.bioLengthByteBuffer(networkBIO); +- bytesProduced += bioLengthBefore - pendingNow; +- bioLengthBefore = pendingNow; - -- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) { -- super(engineMap); -- this.manager = manager; -- } +- if (bytesWritten > 0) { +- bytesConsumed += bytesWritten; - -- @Override -- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) -- throws Exception { -- manager.checkClientTrusted(peerCerts, auth, engine); -- } -- } +- if (jdkCompatibilityMode || bytesProduced == dst.remaining()) { +- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced); +- } +- } else { +- int sslError = SSL.getError(ssl, bytesWritten); +- if (sslError == SSL.SSL_ERROR_ZERO_RETURN) { +- // This means the connection was shutdown correctly, close inbound and outbound +- if (!receivedShutdown) { +- closeAll(); - -- private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher { -- private final OpenSslEngineMap engineMap; +- bytesProduced += bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO); - -- OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) { -- this.engineMap = engineMap; -- } +- // If we have filled up the dst buffer and we have not finished the handshake we should +- // try to wrap again. Otherwise we should only try to wrap again if there is still data +- // pending in SSL buffers. +- SSLEngineResult.HandshakeStatus hs = mayFinishHandshake( +- status != FINISHED ? bytesProduced == dst.remaining() ? NEED_WRAP +- : getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) +- : FINISHED); +- return newResult(hs, bytesConsumed, bytesProduced); +- } - -- @Override -- public boolean match(long ssl, String hostname) { -- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); -- if (engine != null) { -- return engine.checkSniHostnameMatch(hostname); -- } -- logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl); -- return false; -- } -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java -index 4998d0d..8dbc3cf 100644 ---- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java -+++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java -@@ -115,11 +115,7 @@ public abstract class SslContext { - } - - private static SslProvider defaultProvider() { -- if (OpenSsl.isAvailable()) { -- return SslProvider.OPENSSL; -- } else { -- return SslProvider.JDK; -- } -+ return SslProvider.JDK; - } - - /** -@@ -416,18 +412,6 @@ public abstract class SslContext { - trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, - keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, - clientAuth, protocols, startTls); -- case OPENSSL: -- verifyNullSslContextProvider(provider, sslContextProvider); -- return new OpenSslServerContext( -- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, -- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, -- clientAuth, protocols, startTls, enableOcsp); -- case OPENSSL_REFCNT: -- verifyNullSslContextProvider(provider, sslContextProvider); -- return new ReferenceCountedOpenSslServerContext( -- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, -- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, -- clientAuth, protocols, startTls, enableOcsp); - default: - throw new Error(provider.toString()); - } -@@ -770,18 +754,6 @@ public abstract class SslContext { - return new JdkSslClientContext(sslContextProvider, - trustCert, trustManagerFactory, keyCertChain, key, keyPassword, - keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout); -- case OPENSSL: -- verifyNullSslContextProvider(provider, sslContextProvider); -- return new OpenSslClientContext( -- trustCert, trustManagerFactory, keyCertChain, key, keyPassword, -- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, -- enableOcsp); -- case OPENSSL_REFCNT: -- verifyNullSslContextProvider(provider, sslContextProvider); -- return new ReferenceCountedOpenSslClientContext( -- trustCert, trustManagerFactory, keyCertChain, key, keyPassword, -- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, -- enableOcsp); - default: - throw new Error(provider.toString()); - } -diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java -index c054964..05c451a 100644 ---- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java -+++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java -@@ -159,6 +159,12 @@ import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength; - * <a href="https://github.com/netty/netty/issues/832">#832</a> in our issue tracker. - */ - public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler { -+ private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14 -+ private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024; -+ private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024; -+ // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256) -+ static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256; -+ static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = MAX_ENCRYPTED_PACKET_LENGTH - MAX_PLAINTEXT_LENGTH; - - private static final InternalLogger logger = - InternalLoggerFactory.getInstance(SslHandler.class); -@@ -181,40 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - new ClosedChannelException(), SslHandler.class, "channelInactive(...)"); - - private enum SslEngineType { -- TCNATIVE(true, COMPOSITE_CUMULATOR) { -- @Override -- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) -- throws SSLException { -- int nioBufferCount = in.nioBufferCount(); -- int writerIndex = out.writerIndex(); -- final SSLEngineResult result; -- if (nioBufferCount > 1) { -- /* -- * If {@link OpenSslEngine} is in use, -- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method -- * that accepts multiple {@link ByteBuffer}s without additional memory copies. -- */ -- ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine; -- try { -- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, -- out.writableBytes()); -- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer); -- } finally { -- handler.singleBuffer[0] = null; +- return newResult(NOT_HANDSHAKING, bytesConsumed, bytesProduced); +- } else if (sslError == SSL.SSL_ERROR_WANT_READ) { +- // If there is no pending data to read from BIO we should go back to event loop and try +- // to read more data [1]. It is also possible that event loop will detect the socket has +- // been closed. [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html +- return newResult(NEED_UNWRAP, bytesConsumed, bytesProduced); +- } else if (sslError == SSL.SSL_ERROR_WANT_WRITE) { +- // SSL_ERROR_WANT_WRITE typically means that the underlying transport is not writable +- // and we should set the "want write" flag on the selector and try again when the +- // underlying transport is writable [1]. However we are not directly writing to the +- // underlying transport and instead writing to a BIO buffer. The OpenSsl documentation +- // says we should do the following [1]: +- // +- // "When using a buffering BIO, like a BIO pair, data must be written into or retrieved +- // out of the BIO before being able to continue." +- // +- // In practice this means the destination buffer doesn't have enough space for OpenSSL +- // to write encrypted data to. This is an OVERFLOW condition. +- // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html +- if (bytesProduced > 0) { +- // If we produced something we should report this back and let the user call +- // wrap again. +- return newResult(NEED_WRAP, bytesConsumed, bytesProduced); +- } +- return newResult(BUFFER_OVERFLOW, status, bytesConsumed, bytesProduced); +- } else if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP || +- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY || +- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) { +- +- return newResult(NEED_TASK, bytesConsumed, bytesProduced); +- } else { +- // Everything else is considered as error +- throw shutdownWithError("SSL_write", sslError); +- } - } -- } else { -- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len), -- toByteBuffer(out, writerIndex, out.writableBytes())); - } -- out.writerIndex(writerIndex + result.bytesProduced()); -- return result; -- } -- -- @Override -- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) { -- return ReferenceCountedOpenSslEngine.calculateOutNetBufSize(pendingBytes, numComponents); -- } -- }, - CONSCRYPT(true, COMPOSITE_CUMULATOR) { - @Override - SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) -@@ -265,9 +237,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - }; - - static SslEngineType forEngine(SSLEngine engine) { -- if (engine instanceof ReferenceCountedOpenSslEngine) { -- return TCNATIVE; -- } - if (engine instanceof ConscryptAlpnSslEngine) { - return CONSCRYPT; - } -@@ -1034,7 +1003,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - - boolean nonSslRecord = false; - -- while (totalLength < ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { -+ while (totalLength < MAX_ENCRYPTED_PACKET_LENGTH) { - final int readableBytes = endOffset - offset; - if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) { - break; -@@ -1055,7 +1024,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - } - - int newTotalLength = totalLength + packetLength; -- if (newTotalLength > ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { -+ if (newTotalLength > MAX_ENCRYPTED_PACKET_LENGTH) { - // Don't read too much. - break; - } -diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java -deleted file mode 100644 -index aff0949..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java -+++ /dev/null -@@ -1,65 +0,0 @@ --/* -- * Copyright 2017 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.ocsp; -- --import io.netty.channel.ChannelHandlerContext; --import io.netty.channel.ChannelInboundHandlerAdapter; --import io.netty.handler.ssl.ReferenceCountedOpenSslContext; --import io.netty.handler.ssl.ReferenceCountedOpenSslEngine; --import io.netty.handler.ssl.SslHandshakeCompletionEvent; --import io.netty.util.internal.ObjectUtil; --import io.netty.util.internal.ThrowableUtil; --import io.netty.util.internal.UnstableApi; +- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced); +- } finally { +- SSL.bioClearByteBuffer(networkBIO); +- if (bioReadCopyBuf == null) { +- dst.position(dst.position() + bytesProduced); +- } else { +- assert bioReadCopyBuf.readableBytes() <= dst.remaining() : "The destination buffer " + dst + +- " didn't have enough remaining space to hold the encrypted content in " + bioReadCopyBuf; +- dst.put(bioReadCopyBuf.internalNioBuffer(bioReadCopyBuf.readerIndex(), bytesProduced)); +- bioReadCopyBuf.release(); +- } +- } +- } +- } - --import javax.net.ssl.SSLHandshakeException; +- private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int bytesConsumed, int bytesProduced) { +- return newResult(OK, hs, bytesConsumed, bytesProduced); +- } - --/** -- * A handler for SSL clients to handle and act upon stapled OCSP responses. -- * -- * @see ReferenceCountedOpenSslContext#enableOcsp() -- * @see ReferenceCountedOpenSslEngine#getOcspResponse() -- */ --@UnstableApi --public abstract class OcspClientHandler extends ChannelInboundHandlerAdapter { +- private SSLEngineResult newResult(SSLEngineResult.Status status, SSLEngineResult.HandshakeStatus hs, +- int bytesConsumed, int bytesProduced) { +- // If isOutboundDone, then the data from the network BIO +- // was the close_notify message and all was consumed we are not required to wait +- // for the receipt the peer's close_notify message -- shutdown. +- if (isOutboundDone()) { +- if (isInboundDone()) { +- // If the inbound was done as well, we need to ensure we return NOT_HANDSHAKING to signal we are done. +- hs = NOT_HANDSHAKING; - -- private static final SSLHandshakeException OCSP_VERIFICATION_EXCEPTION = ThrowableUtil.unknownStackTrace( -- new SSLHandshakeException("Bad OCSP response"), OcspClientHandler.class, "verify(...)"); +- // As the inbound and the outbound is done we can shutdown the engine now. +- shutdown(); +- } +- return new SSLEngineResult(CLOSED, hs, bytesConsumed, bytesProduced); +- } +- if (hs == NEED_TASK) { +- // Set needTask to true so getHandshakeStatus() will return the correct value. +- needTask = true; +- } +- return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced); +- } - -- private final ReferenceCountedOpenSslEngine engine; +- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus hs, +- int bytesConsumed, int bytesProduced) throws SSLException { +- return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED), +- bytesConsumed, bytesProduced); +- } - -- protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) { -- this.engine = ObjectUtil.checkNotNull(engine, "engine"); +- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status, +- SSLEngineResult.HandshakeStatus hs, +- int bytesConsumed, int bytesProduced) throws SSLException { +- return newResult(status, mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED), +- bytesConsumed, bytesProduced); - } - - /** -- * @see ReferenceCountedOpenSslEngine#getOcspResponse() +- * Log the error, shutdown the engine and throw an exception. - */ -- protected abstract boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception; +- private SSLException shutdownWithError(String operations, int sslError) { +- return shutdownWithError(operations, sslError, SSL.getLastErrorNumber()); +- } - -- @Override -- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { -- if (evt instanceof SslHandshakeCompletionEvent) { -- ctx.pipeline().remove(this); +- private SSLException shutdownWithError(String operation, int sslError, int error) { +- String errorString = SSL.getErrorString(error); +- if (logger.isDebugEnabled()) { +- logger.debug("{} failed with {}: OpenSSL error: {} {}", +- operation, sslError, error, errorString); +- } - -- SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt; -- if (event.isSuccess() && !verify(ctx, engine)) { -- throw OCSP_VERIFICATION_EXCEPTION; -- } +- // There was an internal error -- shutdown +- shutdown(); +- if (handshakeState == HandshakeState.FINISHED) { +- return new SSLException(errorString); - } - -- ctx.fireUserEventTriggered(evt); +- SSLHandshakeException exception = new SSLHandshakeException(errorString); +- // If we have a handshakeException stored already we should include it as well to help the user debug things. +- if (pendingException != null) { +- exception.initCause(pendingException); +- pendingException = null; +- } +- return exception; - } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java -deleted file mode 100644 -index 2883ff4..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java -+++ /dev/null -@@ -1,23 +0,0 @@ --/* -- * Copyright 2017 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. -- */ - --/** -- * <a href="https://en.wikipedia.org/wiki/OCSP_stapling">OCSP stapling</a>, -- * formally known as the TLS Certificate Status Request extension, is an -- * alternative approach to the Online Certificate Status Protocol (OCSP) -- * for checking the revocation status of X.509 digital certificates. -- */ --package io.netty.handler.ssl.ocsp; -diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java -deleted file mode 100644 -index d696d6b..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java -+++ /dev/null -@@ -1,108 +0,0 @@ --/* -- * 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; +- public final SSLEngineResult unwrap( +- final ByteBuffer[] srcs, int srcsOffset, final int srcsLength, +- final ByteBuffer[] dsts, int dstsOffset, final int dstsLength) throws SSLException { +- +- // Throw required runtime exceptions +- ObjectUtil.checkNotNull(srcs, "srcs"); +- if (srcsOffset >= srcs.length +- || srcsOffset + srcsLength > srcs.length) { +- throw new IndexOutOfBoundsException( +- "offset: " + srcsOffset + ", length: " + srcsLength + +- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))"); +- } +- if (dsts == null) { +- throw new IllegalArgumentException("dsts is null"); +- } +- if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) { +- throw new IndexOutOfBoundsException( +- "offset: " + dstsOffset + ", length: " + dstsLength + +- " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))"); +- } +- long capacity = 0; +- final int dstsEndOffset = dstsOffset + dstsLength; +- for (int i = dstsOffset; i < dstsEndOffset; i ++) { +- ByteBuffer dst = dsts[i]; +- if (dst == null) { +- throw new IllegalArgumentException("dsts[" + i + "] is null"); +- } +- if (dst.isReadOnly()) { +- throw new ReadOnlyBufferException(); +- } +- capacity += dst.remaining(); +- } - --import org.junit.BeforeClass; --import org.junit.Test; --import org.junit.runner.RunWith; --import org.junit.runners.Parameterized; +- final int srcsEndOffset = srcsOffset + srcsLength; +- long len = 0; +- for (int i = srcsOffset; i < srcsEndOffset; i++) { +- ByteBuffer src = srcs[i]; +- if (src == null) { +- throw new IllegalArgumentException("srcs[" + i + "] is null"); +- } +- len += src.remaining(); +- } - --import java.util.ArrayList; --import java.util.Collection; --import java.util.List; +- synchronized (this) { +- if (isInboundDone()) { +- return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_WRAP_CLOSED; +- } +- +- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING; +- // Prepare OpenSSL to work in server mode and receive handshake +- if (handshakeState != HandshakeState.FINISHED) { +- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) { +- // Update accepted so we know we triggered the handshake via wrap +- handshakeState = HandshakeState.STARTED_IMPLICITLY; +- } +- +- status = handshake(); +- +- if (status == NEED_TASK) { +- return newResult(status, 0, 0); +- } +- +- if (status == NEED_WRAP) { +- return NEED_WRAP_OK; +- } +- // Check if the inbound is considered to be closed if so let us try to wrap again. +- if (isInboundDone) { +- return NEED_WRAP_CLOSED; +- } +- } +- +- int sslPending = sslPending0(); +- int packetLength; +- // The JDK implies that only a single SSL packet should be processed per unwrap call [1]. If we are in +- // JDK compatibility mode then we should honor this, but if not we just wrap as much as possible. If there +- // are multiple records or partial records this may reduce thrashing events through the pipeline. +- // [1] https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html +- if (jdkCompatibilityMode) { +- if (len < SSL_RECORD_HEADER_LENGTH) { +- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0); +- } +- +- packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset); +- if (packetLength == SslUtils.NOT_ENCRYPTED) { +- throw new NotSslRecordException("not an SSL/TLS record"); +- } +- +- final int packetLengthDataOnly = packetLength - SSL_RECORD_HEADER_LENGTH; +- if (packetLengthDataOnly > capacity) { +- // Not enough space in the destination buffer so signal the caller that the buffer needs to be +- // increased. +- if (packetLengthDataOnly > MAX_RECORD_SIZE) { +- // The packet length MUST NOT exceed 2^14 [1]. However we do accommodate more data to support +- // legacy use cases which may violate this condition (e.g. OpenJDK's SslEngineImpl). If the max +- // length is exceeded we fail fast here to avoid an infinite loop due to the fact that we +- // won't allocate a buffer large enough. +- // [1] https://tools.ietf.org/html/rfc5246#section-6.2.1 +- throw new SSLException("Illegal packet length: " + packetLengthDataOnly + " > " + +- session.getApplicationBufferSize()); +- } else { +- session.tryExpandApplicationBufferSize(packetLengthDataOnly); +- } +- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0); +- } +- +- if (len < packetLength) { +- // We either don't have enough data to read the packet length or not enough for reading the whole +- // packet. +- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0); +- } +- } else if (len == 0 && sslPending <= 0) { +- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0); +- } else if (capacity == 0) { +- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0); +- } else { +- packetLength = (int) min(MAX_VALUE, len); +- } +- +- // This must always be the case when we reached here as if not we returned BUFFER_UNDERFLOW. +- assert srcsOffset < srcsEndOffset; +- +- // This must always be the case if we reached here. +- assert capacity > 0; +- +- // Number of produced bytes +- int bytesProduced = 0; +- int bytesConsumed = 0; +- try { +- srcLoop: +- for (;;) { +- ByteBuffer src = srcs[srcsOffset]; +- int remaining = src.remaining(); +- final ByteBuf bioWriteCopyBuf; +- int pendingEncryptedBytes; +- if (remaining == 0) { +- if (sslPending <= 0) { +- // We must skip empty buffers as BIO_write will return 0 if asked to write something +- // with length 0. +- if (++srcsOffset >= srcsEndOffset) { +- break; +- } +- continue; +- } else { +- bioWriteCopyBuf = null; +- pendingEncryptedBytes = SSL.bioLengthByteBuffer(networkBIO); +- } +- } else { +- // Write more encrypted data into the BIO. Ensure we only read one packet at a time as +- // stated in the SSLEngine javadocs. +- pendingEncryptedBytes = min(packetLength, remaining); +- bioWriteCopyBuf = writeEncryptedData(src, pendingEncryptedBytes); +- } +- try { +- for (;;) { +- ByteBuffer dst = dsts[dstsOffset]; +- if (!dst.hasRemaining()) { +- // No space left in the destination buffer, skip it. +- if (++dstsOffset >= dstsEndOffset) { +- break srcLoop; +- } +- continue; +- } +- +- int bytesRead = readPlaintextData(dst); +- // We are directly using the ByteBuffer memory for the write, and so we only know what has +- // been consumed after we let SSL decrypt the data. At this point we should update the +- // number of bytes consumed, update the ByteBuffer position, and release temp ByteBuf. +- int localBytesConsumed = pendingEncryptedBytes - SSL.bioLengthByteBuffer(networkBIO); +- bytesConsumed += localBytesConsumed; +- packetLength -= localBytesConsumed; +- pendingEncryptedBytes -= localBytesConsumed; +- src.position(src.position() + localBytesConsumed); +- +- if (bytesRead > 0) { +- bytesProduced += bytesRead; +- +- if (!dst.hasRemaining()) { +- sslPending = sslPending0(); +- // Move to the next dst buffer as this one is full. +- if (++dstsOffset >= dstsEndOffset) { +- return sslPending > 0 ? +- newResult(BUFFER_OVERFLOW, status, bytesConsumed, bytesProduced) : +- newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, +- bytesConsumed, bytesProduced); +- } +- } else if (packetLength == 0 || jdkCompatibilityMode) { +- // We either consumed all data or we are in jdkCompatibilityMode and have consumed +- // a single TLS packet and should stop consuming until this method is called again. +- break srcLoop; +- } +- } else { +- int sslError = SSL.getError(ssl, bytesRead); +- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) { +- // break to the outer loop as we want to read more data which means we need to +- // write more to the BIO. +- break; +- } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) { +- // This means the connection was shutdown correctly, close inbound and outbound +- if (!receivedShutdown) { +- closeAll(); +- } +- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, +- bytesConsumed, bytesProduced); +- } else if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP || +- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY || +- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) { +- return newResult(isInboundDone() ? CLOSED : OK, +- NEED_TASK, bytesConsumed, bytesProduced); +- } else { +- return sslReadErrorResult(sslError, SSL.getLastErrorNumber(), bytesConsumed, +- bytesProduced); +- } +- } +- } - --import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory; --import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED; --import static org.junit.Assume.assumeTrue; +- if (++srcsOffset >= srcsEndOffset) { +- break; +- } +- } finally { +- if (bioWriteCopyBuf != null) { +- bioWriteCopyBuf.release(); +- } +- } +- } +- } finally { +- SSL.bioClearByteBuffer(networkBIO); +- rejectRemoteInitiatedRenegotiation(); +- } - --@RunWith(Parameterized.class) --public class JdkOpenSslEngineInteroptTest extends SSLEngineTest { +- // Check to see if we received a close_notify message from the peer. +- if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) { +- closeAll(); +- } - -- @Parameterized.Parameters(name = "{index}: bufferType = {0}") -- public static Collection<Object> data() { -- List<Object> params = new ArrayList<Object>(); -- for (BufferType type: BufferType.values()) { -- params.add(type); +- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced); - } -- return params; - } - -- public JdkOpenSslEngineInteroptTest(BufferType type) { -- super(type); +- private SSLEngineResult sslReadErrorResult(int error, int stackError, int bytesConsumed, int bytesProduced) +- throws SSLException { +- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the +- // BIO first or can just shutdown and throw it now. +- // This is needed so we ensure close_notify etc is correctly send to the remote peer. +- // See https://github.com/netty/netty/issues/3900 +- if (SSL.bioLengthNonApplication(networkBIO) > 0) { +- // we seems to have data left that needs to be transferred and so the user needs +- // call wrap(...). Store the error so we can pick it up later. +- String message = SSL.getErrorString(stackError); +- SSLException exception = handshakeState == HandshakeState.FINISHED ? +- new SSLException(message) : new SSLHandshakeException(message); +- if (pendingException == null) { +- pendingException = exception; +- } else { +- ThrowableUtil.addSuppressed(pendingException, exception); +- } +- // We need to clear all errors so we not pick up anything that was left on the stack on the next +- // operation. Note that shutdownWithError(...) will cleanup the stack as well so its only needed here. +- SSL.clearError(); +- return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced); +- } +- throw shutdownWithError("SSL_read", error, stackError); - } - -- @BeforeClass -- public static void checkOpenSsl() { -- assumeTrue(OpenSsl.isAvailable()); +- private void closeAll() throws SSLException { +- receivedShutdown = true; +- closeOutbound(); +- closeInbound(); - } - -- @Override -- protected SslProvider sslClientProvider() { -- return SslProvider.JDK; +- private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException { +- // As rejectRemoteInitiatedRenegotiation() is called in a finally block we also need to check if we shutdown +- // the engine before as otherwise SSL.getHandshakeCount(ssl) will throw an NPE if the passed in ssl is 0. +- // See https://github.com/netty/netty/issues/7353 +- if (!isDestroyed() && SSL.getHandshakeCount(ssl) > 1 && +- // As we may count multiple handshakes when TLSv1.3 is used we should just ignore this here as +- // renegotiation is not supported in TLSv1.3 as per spec. +- !SslUtils.PROTOCOL_TLS_V1_3.equals(session.getProtocol()) && handshakeState == HandshakeState.FINISHED) { +- // TODO: In future versions me may also want to send a fatal_alert to the client and so notify it +- // that the renegotiation failed. +- shutdown(); +- throw new SSLHandshakeException("remote-initiated renegotiation not allowed"); +- } - } - -- @Override -- protected SslProvider sslServerProvider() { -- return SslProvider.OPENSSL; +- public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException { +- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length); - } - -- @Override -- @Test -- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth(); +- private ByteBuffer[] singleSrcBuffer(ByteBuffer src) { +- singleSrcBuffer[0] = src; +- return singleSrcBuffer; - } - -- @Override -- @Test -- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth(); +- private void resetSingleSrcBuffer() { +- singleSrcBuffer[0] = null; - } - -- @Override -- @Test -- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth(); +- private ByteBuffer[] singleDstBuffer(ByteBuffer src) { +- singleDstBuffer[0] = src; +- return singleDstBuffer; - } - -- @Override -- @Test -- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth(); +- private void resetSingleDstBuffer() { +- singleDstBuffer[0] = null; - } - - @Override -- @Test -- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth(); +- public final synchronized SSLEngineResult unwrap( +- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException { +- try { +- return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length); +- } finally { +- resetSingleSrcBuffer(); +- } - } - - @Override -- protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) { -- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) handler.engine(); -- engine.setVerify(SSL_CVERIFY_IGNORED, 1); +- public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException { +- try { +- return wrap(singleSrcBuffer(src), dst); +- } finally { +- resetSingleSrcBuffer(); +- } - } - - @Override -- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) { -- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. -- return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause); -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java -deleted file mode 100644 -index 229e853..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java -+++ /dev/null -@@ -1,49 +0,0 @@ --/* -- * Copyright 2017 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.internal.tcnative.CertificateVerifier; --import org.junit.Assert; --import org.junit.Assume; --import org.junit.BeforeClass; --import org.junit.Test; -- --import java.lang.reflect.Field; -- --public class OpenSslCertificateExceptionTest { -- -- @BeforeClass -- public static void assumeOpenSsl() { -- Assume.assumeTrue(OpenSsl.isAvailable()); -- } -- -- @Test -- public void testValidErrorCode() throws Exception { -- Field[] fields = CertificateVerifier.class.getFields(); -- for (Field field : fields) { -- if (field.isAccessible()) { -- int errorCode = field.getInt(null); -- OpenSslCertificateException exception = new OpenSslCertificateException(errorCode); -- Assert.assertEquals(errorCode, exception.errorCode()); -- } +- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException { +- try { +- return unwrap(singleSrcBuffer(src), singleDstBuffer(dst)); +- } finally { +- resetSingleSrcBuffer(); +- resetSingleDstBuffer(); - } - } - -- @Test(expected = IllegalArgumentException.class) -- public void testNonValidErrorCode() { -- new OpenSslCertificateException(Integer.MIN_VALUE); -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java -deleted file mode 100644 -index 6011cf7..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java -+++ /dev/null -@@ -1,38 +0,0 @@ --/* -- * 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.handler.ssl.util.InsecureTrustManagerFactory; --import org.junit.BeforeClass; -- --import javax.net.ssl.SSLException; --import java.io.File; -- --import static org.junit.Assume.assumeTrue; -- --public class OpenSslClientContextTest extends SslContextTest { -- -- @BeforeClass -- public static void checkOpenSsl() { -- assumeTrue(OpenSsl.isAvailable()); -- } -- - @Override -- protected SslContext newServerContext(File crtFile, File keyFile, String pass) throws SSLException { -- return new OpenSslClientContext(crtFile, InsecureTrustManagerFactory.INSTANCE, crtFile, keyFile, pass, -- null, null, IdentityCipherSuiteFilter.INSTANCE, ApplicationProtocolConfig.DISABLED, 0, 0); -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java -deleted file mode 100644 -index 5939b66..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java -+++ /dev/null -@@ -1,661 +0,0 @@ --/* -- * Copyright 2015 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.buffer.UnpooledByteBufAllocator; --import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; --import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior; --import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; --import io.netty.handler.ssl.util.InsecureTrustManagerFactory; --import io.netty.handler.ssl.util.SelfSignedCertificate; --import io.netty.util.internal.PlatformDependent; --import org.junit.Assume; --import org.junit.BeforeClass; --import org.junit.Test; --import org.junit.runner.RunWith; --import org.junit.runners.Parameterized; -- --import java.nio.ByteBuffer; --import java.security.AlgorithmConstraints; --import java.security.AlgorithmParameters; --import java.security.CryptoPrimitive; --import java.security.Key; --import java.util.ArrayList; --import java.util.Collection; --import java.util.List; --import java.util.Set; --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLEngineResult; --import javax.net.ssl.SSLException; --import javax.net.ssl.SSLParameters; -- --import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory; --import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH; --import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH; --import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_PLAINTEXT_LENGTH; --import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED; --import static java.lang.Integer.MAX_VALUE; --import static org.junit.Assert.assertEquals; --import static org.junit.Assert.assertFalse; --import static org.junit.Assert.assertNull; --import static org.junit.Assert.assertSame; --import static org.junit.Assert.assertTrue; --import static org.junit.Assume.assumeTrue; -- --@RunWith(Parameterized.class) --public class OpenSslEngineTest extends SSLEngineTest { -- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2"; -- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1"; -- -- @Parameterized.Parameters(name = "{index}: bufferType = {0}") -- public static Collection<Object> data() { -- List<Object> params = new ArrayList<Object>(); -- for (BufferType type: BufferType.values()) { -- params.add(type); +- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException { +- try { +- return unwrap(singleSrcBuffer(src), dsts); +- } finally { +- resetSingleSrcBuffer(); - } -- return params; -- } -- -- public OpenSslEngineTest(BufferType type) { -- super(type); -- } -- -- @BeforeClass -- public static void checkOpenSsl() { -- assumeTrue(OpenSsl.isAvailable()); - } - - @Override -- @Test -- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth(); +- public final synchronized Runnable getDelegatedTask() { +- if (isDestroyed()) { +- return null; +- } +- final Runnable task = SSL.getTask(ssl); +- if (task == null) { +- return null; +- } +- return new Runnable() { +- @Override +- public void run() { +- if (isDestroyed()) { +- // The engine was destroyed in the meantime, just return. +- return; +- } +- try { +- task.run(); +- } finally { +- // The task was run, reset needTask to false so getHandshakeStatus() returns the correct value. +- needTask = false; +- } +- } +- }; - } - - @Override -- @Test -- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth(); -- } +- public final synchronized void closeInbound() throws SSLException { +- if (isInboundDone) { +- return; +- } - -- @Override -- @Test -- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth(); -- } +- isInboundDone = true; - -- @Override -- @Test -- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth(); -- } +- if (isOutboundDone()) { +- // Only call shutdown if there is no outbound data pending. +- // See https://github.com/netty/netty/issues/6167 +- shutdown(); +- } - -- @Override -- @Test -- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth(); +- if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown) { +- throw new SSLException( +- "Inbound closed before receiving peer's close_notify: possible truncation attack?"); +- } - } - - @Override -- @Test -- public void testClientHostnameValidationSuccess() throws InterruptedException, SSLException { -- assumeTrue(OpenSsl.supportsHostnameValidation()); -- super.testClientHostnameValidationSuccess(); +- public final synchronized boolean isInboundDone() { +- return isInboundDone; - } - - @Override -- @Test -- public void testClientHostnameValidationFail() throws InterruptedException, SSLException { -- assumeTrue(OpenSsl.supportsHostnameValidation()); -- super.testClientHostnameValidationFail(); -- } -- -- @Test -- public void testNpn() throws Exception { -- ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.NPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- setupHandlers(apn); -- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- } -- -- @Test -- public void testAlpn() throws Exception { -- assumeTrue(OpenSsl.isAlpnSupported()); -- ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.ALPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- setupHandlers(apn); -- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- } -- -- @Test -- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception { -- assumeTrue(OpenSsl.isAlpnSupported()); -- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN, -- FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL); -- setupHandlers(serverApn, clientApn); -- assertNull(serverException); -- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- } -- -- @Test -- public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception { -- testEnablingAnAlreadyDisabledSslProtocol(new String[]{PROTOCOL_SSL_V2_HELLO}, -- new String[]{PROTOCOL_SSL_V2_HELLO, PROTOCOL_TLS_V1_2}); -- } -- @Test -- public void testWrapBuffersNoWritePendingError() throws Exception { -- clientSslCtx = SslContextBuilder.forClient() -- .trustManager(InsecureTrustManagerFactory.INSTANCE) -- .sslProvider(sslClientProvider()) -- .build(); -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslServerProvider()) -- .build(); -- SSLEngine clientEngine = null; -- SSLEngine serverEngine = null; -- try { -- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- handshake(clientEngine, serverEngine); -- -- ByteBuffer src = allocateBuffer(1024 * 10); -- byte[] data = new byte[src.capacity()]; -- PlatformDependent.threadLocalRandom().nextBytes(data); -- src.put(data).flip(); -- ByteBuffer dst = allocateBuffer(1); -- // Try to wrap multiple times so we are more likely to hit the issue. -- for (int i = 0; i < 100; i++) { -- src.position(0); -- dst.position(0); -- assertSame(SSLEngineResult.Status.BUFFER_OVERFLOW, clientEngine.wrap(src, dst).getStatus()); -- } -- } finally { -- cleanupClientSslEngine(clientEngine); -- cleanupServerSslEngine(serverEngine); -- } -- } -- -- @Test -- public void testOnlySmallBufferNeededForWrap() throws Exception { -- clientSslCtx = SslContextBuilder.forClient() -- .trustManager(InsecureTrustManagerFactory.INSTANCE) -- .sslProvider(sslClientProvider()) -- .build(); -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslServerProvider()) -- .build(); -- SSLEngine clientEngine = null; -- SSLEngine serverEngine = null; -- try { -- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- handshake(clientEngine, serverEngine); -- -- // Allocate a buffer which is small enough and set the limit to the capacity to mark its whole content -- // as readable. -- int srcLen = 1024; -- ByteBuffer src = allocateBuffer(srcLen); -- -- ByteBuffer dstTooSmall = allocateBuffer( -- src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH - 1); -- ByteBuffer dst = allocateBuffer( -- src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH); -- -- // Check that we fail to wrap if the dst buffers capacity is not at least -- // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH -- SSLEngineResult result = clientEngine.wrap(src, dstTooSmall); -- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); -- assertEquals(0, result.bytesConsumed()); -- assertEquals(0, result.bytesProduced()); -- assertEquals(src.remaining(), src.capacity()); -- assertEquals(dst.remaining(), dst.capacity()); -- -- // Check that we can wrap with a dst buffer that has the capacity of -- // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH -- result = clientEngine.wrap(src, dst); -- assertEquals(SSLEngineResult.Status.OK, result.getStatus()); -- assertEquals(srcLen, result.bytesConsumed()); -- assertEquals(0, src.remaining()); -- assertTrue(result.bytesProduced() > srcLen); -- assertEquals(src.capacity() - result.bytesConsumed(), src.remaining()); -- assertEquals(dst.capacity() - result.bytesProduced(), dst.remaining()); -- } finally { -- cleanupClientSslEngine(clientEngine); -- cleanupServerSslEngine(serverEngine); -- } -- } -- -- @Test -- public void testNeededDstCapacityIsCorrectlyCalculated() throws Exception { -- clientSslCtx = SslContextBuilder.forClient() -- .trustManager(InsecureTrustManagerFactory.INSTANCE) -- .sslProvider(sslClientProvider()) -- .build(); -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslServerProvider()) -- .build(); -- SSLEngine clientEngine = null; -- SSLEngine serverEngine = null; -- try { -- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- handshake(clientEngine, serverEngine); -- -- ByteBuffer src = allocateBuffer(1024); -- ByteBuffer src2 = src.duplicate(); -- -- ByteBuffer dst = allocateBuffer(src.capacity() -- + MAX_TLS_RECORD_OVERHEAD_LENGTH); -- -- SSLEngineResult result = clientEngine.wrap(new ByteBuffer[] { src, src2 }, dst); -- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); -- assertEquals(0, src.position()); -- assertEquals(0, src2.position()); -- assertEquals(0, dst.position()); -- assertEquals(0, result.bytesConsumed()); -- assertEquals(0, result.bytesProduced()); -- } finally { -- cleanupClientSslEngine(clientEngine); -- cleanupServerSslEngine(serverEngine); -- } -- } -- -- @Test -- public void testSrcsLenOverFlowCorrectlyHandled() throws Exception { -- clientSslCtx = SslContextBuilder.forClient() -- .trustManager(InsecureTrustManagerFactory.INSTANCE) -- .sslProvider(sslClientProvider()) -- .build(); -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslServerProvider()) -- .build(); -- SSLEngine clientEngine = null; -- SSLEngine serverEngine = null; -- try { -- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- handshake(clientEngine, serverEngine); +- public final synchronized void closeOutbound() { +- if (outboundClosed) { +- return; +- } - -- ByteBuffer src = allocateBuffer(1024); -- List<ByteBuffer> srcList = new ArrayList<ByteBuffer>(); -- long srcsLen = 0; -- long maxLen = ((long) MAX_VALUE) * 2; +- outboundClosed = true; - -- while (srcsLen < maxLen) { -- ByteBuffer dup = src.duplicate(); -- srcList.add(dup); -- srcsLen += dup.capacity(); +- if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) { +- int mode = SSL.getShutdown(ssl); +- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) { +- doSSLShutdown(); - } +- } else { +- // engine closing before initial handshake +- shutdown(); +- } +- } - -- ByteBuffer[] srcs = srcList.toArray(new ByteBuffer[srcList.size()]); -- -- ByteBuffer dst = allocateBuffer(MAX_ENCRYPTED_PACKET_LENGTH - 1); -- -- SSLEngineResult result = clientEngine.wrap(srcs, dst); -- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); -- -- for (ByteBuffer buffer : srcs) { -- assertEquals(0, buffer.position()); +- /** +- * Attempt to call {@link SSL#shutdownSSL(long)}. +- * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not attempted or returned an error. +- */ +- private boolean doSSLShutdown() { +- if (SSL.isInInit(ssl) != 0) { +- // Only try to call SSL_shutdown if we are not in the init state anymore. +- // Otherwise we will see 'error:140E0197:SSL routines:SSL_shutdown:shutdown while in init' in our logs. +- // +- // See also http://hg.nginx.org/nginx/rev/062c189fee20 +- return false; +- } +- int err = SSL.shutdownSSL(ssl); +- if (err < 0) { +- int sslErr = SSL.getError(ssl, err); +- if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) { +- if (logger.isDebugEnabled()) { +- int error = SSL.getLastErrorNumber(); +- logger.debug("SSL_shutdown failed: OpenSSL error: {} {}", error, SSL.getErrorString(error)); +- } +- // There was an internal error -- shutdown +- shutdown(); +- return false; - } -- assertEquals(0, dst.position()); -- assertEquals(0, result.bytesConsumed()); -- assertEquals(0, result.bytesProduced()); -- } finally { -- cleanupClientSslEngine(clientEngine); -- cleanupServerSslEngine(serverEngine); +- SSL.clearError(); - } +- return true; - } - -- @Test -- public void testCalculateOutNetBufSizeOverflow() { -- assertEquals(MAX_ENCRYPTED_PACKET_LENGTH, -- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_VALUE, 1)); -- } -- -- @Test -- public void testCalculateOutNetBufSize0() { -- assertEquals(MAX_TLS_RECORD_OVERHEAD_LENGTH, -- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(0, 1)); +- @Override +- public final synchronized boolean isOutboundDone() { +- // Check if there is anything left in the outbound buffer. +- // We need to ensure we only call SSL.pendingWrittenBytesInBIO(...) if the engine was not destroyed yet. +- return outboundClosed && (networkBIO == 0 || SSL.bioLengthNonApplication(networkBIO) == 0); - } - -- @Test -- public void testCalculateOutNetBufSizeMaxEncryptedPacketLength() { -- assertEquals(MAX_ENCRYPTED_PACKET_LENGTH, -- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_ENCRYPTED_PACKET_LENGTH + 1, 2)); +- @Override +- public final String[] getSupportedCipherSuites() { +- return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[0]); - } - - @Override -- protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) { -- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) handler.engine(); -- engine.setVerify(SSL_CVERIFY_IGNORED, 1); -- } -- -- @Test -- public void testWrapWithDifferentSizesTLSv1() throws Exception { -- clientSslCtx = SslContextBuilder.forClient() -- .trustManager(InsecureTrustManagerFactory.INSTANCE) -- .sslProvider(sslClientProvider()) -- .build(); -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslServerProvider()) -- .build(); -- -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-MD5"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "EDH-RSA-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-RC4-MD5"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "IDEA-CBC-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-RC4-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-RC4-SHA"); -- } -- -- @Test -- public void testWrapWithDifferentSizesTLSv1_1() throws Exception { -- clientSslCtx = SslContextBuilder.forClient() -- .trustManager(InsecureTrustManagerFactory.INSTANCE) -- .sslProvider(sslClientProvider()) -- .build(); -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslServerProvider()) -- .build(); -- -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "IDEA-CBC-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-RC4-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-RC4-MD5"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "RC4-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "EDH-RSA-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DES-CBC3-SHA"); -- } -- -- @Test -- public void testWrapWithDifferentSizesTLSv1_2() throws Exception { -- clientSslCtx = SslContextBuilder.forClient() -- .trustManager(InsecureTrustManagerFactory.INSTANCE) -- .sslProvider(sslClientProvider()) -- .build(); -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslServerProvider()) -- .build(); -- -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-GCM-SHA384"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-GCM-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-GCM-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-SHA384"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-GCM-SHA384"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-GCM-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-MD5"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "EDH-RSA-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-RC4-MD5"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "IDEA-CBC-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-GCM-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-RC4-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-GCM-SHA384"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-GCM-SHA384"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-SHA256"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-RC4-SHA"); -- } -- -- @Test -- public void testWrapWithDifferentSizesSSLv3() throws Exception { -- clientSslCtx = SslContextBuilder.forClient() -- .trustManager(InsecureTrustManagerFactory.INSTANCE) -- .sslProvider(sslClientProvider()) -- .build(); -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslServerProvider()) -- .build(); -- -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-MD5"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "EDH-RSA-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-RC4-MD5"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "IDEA-CBC-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-AES128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-RC4-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-SEED-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-AES256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ECDHE-RSA-DES-CBC3-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-CAMELLIA256-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-CAMELLIA128-SHA"); -- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ECDHE-RSA-RC4-SHA"); -- } -- -- private void testWrapWithDifferentSizes(String protocol, String cipher) throws Exception { -- assumeTrue(OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocol)); -- if (!OpenSsl.isCipherSuiteAvailable(cipher)) { -- return; +- public final String[] getEnabledCipherSuites() { +- final String[] extraCiphers; +- final String[] enabled; +- synchronized (this) { +- if (!isDestroyed()) { +- enabled = SSL.getCiphers(ssl); +- int opts = SSL.getOptions(ssl); +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, PROTOCOL_TLS_V1_3)) { +- extraCiphers = OpenSsl.EXTRA_SUPPORTED_TLS_1_3_CIPHERS; +- } else { +- extraCiphers = EmptyArrays.EMPTY_STRINGS; +- } +- } else { +- return EmptyArrays.EMPTY_STRINGS; +- } - } -- -- SSLEngine clientEngine = null; -- SSLEngine serverEngine = null; -- try { -- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- clientEngine.setEnabledCipherSuites(new String[] { cipher }); -- clientEngine.setEnabledProtocols(new String[] { protocol }); -- serverEngine.setEnabledCipherSuites(new String[] { cipher }); -- serverEngine.setEnabledProtocols(new String[] { protocol }); -- -- try { -- handshake(clientEngine, serverEngine); -- } catch (SSLException e) { -- if (e.getMessage().contains("unsupported protocol")) { -- Assume.assumeNoException(protocol + " not supported with cipher " + cipher, e); +- if (enabled == null) { +- return EmptyArrays.EMPTY_STRINGS; +- } else { +- Set<String> enabledSet = new LinkedHashSet<String>(enabled.length + extraCiphers.length); +- synchronized (this) { +- for (int i = 0; i < enabled.length; i++) { +- String mapped = toJavaCipherSuite(enabled[i]); +- final String cipher = mapped == null ? enabled[i] : mapped; +- if (!OpenSsl.isTlsv13Supported() && SslUtils.isTLSv13Cipher(cipher)) { +- continue; +- } +- enabledSet.add(cipher); - } -- throw e; +- Collections.addAll(enabledSet, extraCiphers); - } -- -- int srcLen = 64; -- do { -- testWrapDstBigEnough(clientEngine, srcLen); -- srcLen += 64; -- } while (srcLen < MAX_PLAINTEXT_LENGTH); -- -- testWrapDstBigEnough(clientEngine, MAX_PLAINTEXT_LENGTH); -- } finally { -- cleanupClientSslEngine(clientEngine); -- cleanupServerSslEngine(serverEngine); +- return enabledSet.toArray(new String[0]); - } - } - -- private void testWrapDstBigEnough(SSLEngine engine, int srcLen) throws SSLException { -- ByteBuffer src = allocateBuffer(srcLen); -- ByteBuffer dst = allocateBuffer(srcLen + MAX_TLS_RECORD_OVERHEAD_LENGTH); -- -- SSLEngineResult result = engine.wrap(src, dst); -- assertEquals(SSLEngineResult.Status.OK, result.getStatus()); -- int consumed = result.bytesConsumed(); -- int produced = result.bytesProduced(); -- assertEquals(srcLen, consumed); -- assertTrue(produced > consumed); +- @Override +- public final void setEnabledCipherSuites(String[] cipherSuites) { +- checkNotNull(cipherSuites, "cipherSuites"); - -- dst.flip(); -- assertEquals(produced, dst.remaining()); -- assertFalse(src.hasRemaining()); -- } +- final StringBuilder buf = new StringBuilder(); +- final StringBuilder bufTLSv13 = new StringBuilder(); - -- @Test -- public void testSNIMatchersDoesNotThrow() throws Exception { -- assumeTrue(PlatformDependent.javaVersion() >= 8); -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslServerProvider()) -- .build(); +- CipherSuiteConverter.convertToCipherStrings(Arrays.asList(cipherSuites), buf, bufTLSv13, OpenSsl.isBoringSSL()); +- final String cipherSuiteSpec = buf.toString(); +- final String cipherSuiteSpecTLSv13 = bufTLSv13.toString(); - -- SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- try { -- SSLParameters parameters = new SSLParameters(); -- Java8SslTestUtils.setSNIMatcher(parameters); -- engine.setSSLParameters(parameters); -- } finally { -- cleanupServerSslEngine(engine); -- ssc.delete(); +- if (!OpenSsl.isTlsv13Supported() && !cipherSuiteSpecTLSv13.isEmpty()) { +- throw new IllegalArgumentException("TLSv1.3 is not supported by this java version."); - } -- } -- -- @Test(expected = IllegalArgumentException.class) -- public void testAlgorithmConstraintsThrows() throws Exception { -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslServerProvider()) -- .build(); -- -- SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); -- try { -- SSLParameters parameters = new SSLParameters(); -- parameters.setAlgorithmConstraints(new AlgorithmConstraints() { -- @Override -- public boolean permits( -- Set<CryptoPrimitive> primitives, String algorithm, AlgorithmParameters parameters) { -- return false; -- } +- synchronized (this) { +- if (!isDestroyed()) { +- // TODO: Should we also adjust the protocols based on if there are any ciphers left that can be used +- // for TLSv1.3 or for previor SSL/TLS versions ? +- try { +- // Set non TLSv1.3 ciphers. +- SSL.setCipherSuites(ssl, cipherSuiteSpec, false); - -- @Override -- public boolean permits(Set<CryptoPrimitive> primitives, Key key) { -- return false; -- } +- if (OpenSsl.isTlsv13Supported()) { +- // Set TLSv1.3 ciphers. +- SSL.setCipherSuites(ssl, cipherSuiteSpecTLSv13, true); +- } - -- @Override -- public boolean permits( -- Set<CryptoPrimitive> primitives, String algorithm, Key key, AlgorithmParameters parameters) { -- return false; +- } catch (Exception e) { +- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e); - } -- }); -- engine.setSSLParameters(parameters); -- } finally { -- cleanupServerSslEngine(engine); -- ssc.delete(); +- } else { +- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec); +- } - } - } - - @Override -- protected SslProvider sslClientProvider() { -- return SslProvider.OPENSSL; +- public final String[] getSupportedProtocols() { +- return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[0]); - } - - @Override -- protected SslProvider sslServerProvider() { -- return SslProvider.OPENSSL; -- } -- -- private static ApplicationProtocolConfig acceptingNegotiator(Protocol protocol, -- String... supportedProtocols) { -- return new ApplicationProtocolConfig(protocol, -- SelectorFailureBehavior.NO_ADVERTISE, -- SelectedListenerFailureBehavior.ACCEPT, -- supportedProtocols); -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java -deleted file mode 100644 -index f63a16f..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java -+++ /dev/null -@@ -1,114 +0,0 @@ --/* -- * 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 org.junit.BeforeClass; --import org.junit.Ignore; --import org.junit.Test; -- --import javax.net.ssl.SSLException; --import org.junit.runner.RunWith; --import org.junit.runners.Parameterized; -- --import java.util.ArrayList; --import java.util.Collection; --import java.util.List; -- --import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory; --import static org.junit.Assume.assumeTrue; -- --@RunWith(Parameterized.class) --public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest { +- public final String[] getEnabledProtocols() { +- List<String> enabled = new ArrayList<String>(6); +- // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is always enabled +- enabled.add(PROTOCOL_SSL_V2_HELLO); - -- @Parameterized.Parameters(name = "{index}: bufferType = {0}") -- public static Collection<Object> data() { -- List<Object> params = new ArrayList<Object>(); -- for (BufferType type: BufferType.values()) { -- params.add(type); +- int opts; +- synchronized (this) { +- if (!isDestroyed()) { +- opts = SSL.getOptions(ssl); +- } else { +- return enabled.toArray(new String[0]); +- } - } -- return params; -- } -- -- public OpenSslJdkSslEngineInteroptTest(BufferType type) { -- super(type); +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, PROTOCOL_TLS_V1)) { +- enabled.add(PROTOCOL_TLS_V1); +- } +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, PROTOCOL_TLS_V1_1)) { +- enabled.add(PROTOCOL_TLS_V1_1); +- } +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, PROTOCOL_TLS_V1_2)) { +- enabled.add(PROTOCOL_TLS_V1_2); +- } +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, PROTOCOL_TLS_V1_3)) { +- enabled.add(PROTOCOL_TLS_V1_3); +- } +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, PROTOCOL_SSL_V2)) { +- enabled.add(PROTOCOL_SSL_V2); +- } +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, PROTOCOL_SSL_V3)) { +- enabled.add(PROTOCOL_SSL_V3); +- } +- return enabled.toArray(new String[0]); - } - -- @BeforeClass -- public static void checkOpenSsl() { -- assumeTrue(OpenSsl.isAvailable()); +- private static boolean isProtocolEnabled(int opts, int disableMask, String protocolString) { +- // We also need to check if the actual protocolString is supported as depending on the openssl API +- // implementations it may use a disableMask of 0 (BoringSSL is doing this for example). +- return (opts & disableMask) == 0 && OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString); - } - +- /** +- * {@inheritDoc} +- * TLS doesn't support a way to advertise non-contiguous versions from the client's perspective, and the client +- * just advertises the max supported version. The TLS protocol also doesn't support all different combinations of +- * discrete protocols, and instead assumes contiguous ranges. OpenSSL has some unexpected behavior +- * (e.g. handshake failures) if non-contiguous protocols are used even where there is a compatible set of protocols +- * and ciphers. For these reasons this method will determine the minimum protocol and the maximum protocol and +- * enabled a contiguous range from [min protocol, max protocol] in OpenSSL. +- */ - @Override -- protected SslProvider sslClientProvider() { -- return SslProvider.OPENSSL; -- } +- public final void setEnabledProtocols(String[] protocols) { +- if (protocols == null) { +- // This is correct from the API docs +- throw new IllegalArgumentException(); +- } +- int minProtocolIndex = OPENSSL_OP_NO_PROTOCOLS.length; +- int maxProtocolIndex = 0; +- for (String p: protocols) { +- if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) { +- throw new IllegalArgumentException("Protocol " + p + " is not supported."); +- } +- if (p.equals(PROTOCOL_SSL_V2)) { +- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) { +- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2; +- } +- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) { +- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2; +- } +- } else if (p.equals(PROTOCOL_SSL_V3)) { +- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3) { +- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3; +- } +- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3) { +- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3; +- } +- } else if (p.equals(PROTOCOL_TLS_V1)) { +- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1) { +- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1; +- } +- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1) { +- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1; +- } +- } else if (p.equals(PROTOCOL_TLS_V1_1)) { +- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1) { +- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1; +- } +- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1) { +- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1; +- } +- } else if (p.equals(PROTOCOL_TLS_V1_2)) { +- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2) { +- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2; +- } +- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2) { +- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2; +- } +- } else if (p.equals(PROTOCOL_TLS_V1_3)) { +- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3) { +- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3; +- } +- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3) { +- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3; +- } +- } +- } +- synchronized (this) { +- if (!isDestroyed()) { +- // Clear out options which disable protocols +- SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 | +- SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2 | SSL.SSL_OP_NO_TLSv1_3); - -- @Override -- protected SslProvider sslServerProvider() { -- return SslProvider.JDK; -- } +- int opts = 0; +- for (int i = 0; i < minProtocolIndex; ++i) { +- opts |= OPENSSL_OP_NO_PROTOCOLS[i]; +- } +- assert maxProtocolIndex != MAX_VALUE; +- for (int i = maxProtocolIndex + 1; i < OPENSSL_OP_NO_PROTOCOLS.length; ++i) { +- opts |= OPENSSL_OP_NO_PROTOCOLS[i]; +- } - -- @Ignore /* Does the JDK support a "max certificate chain length"? */ -- @Override -- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { +- // Disable protocols we do not want +- SSL.setOptions(ssl, opts); +- } else { +- throw new IllegalStateException("failed to enable protocols: " + Arrays.asList(protocols)); +- } +- } - } - -- @Ignore /* Does the JDK support a "max certificate chain length"? */ - @Override -- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { +- public final SSLSession getSession() { +- return session; - } - - @Override -- @Test -- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth(); -- } +- public final synchronized void beginHandshake() throws SSLException { +- switch (handshakeState) { +- case STARTED_IMPLICITLY: +- checkEngineClosed(); - -- @Override -- @Test -- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth(); -- } +- // A user did not start handshake by calling this method by him/herself, +- // but handshake has been started already by wrap() or unwrap() implicitly. +- // Because it's the user's first time to call this method, it is unfair to +- // raise an exception. From the user's standpoint, he or she never asked +- // for renegotiation. - -- @Override -- @Test -- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception { -- checkShouldUseKeyManagerFactory(); -- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth(); +- handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this method is invoked by the user, +- calculateMaxWrapOverhead(); +- // we should raise an exception. +- break; +- case STARTED_EXPLICITLY: +- // Nothing to do as the handshake is not done yet. +- break; +- case FINISHED: +- throw new SSLException("renegotiation unsupported"); +- case NOT_STARTED: +- handshakeState = HandshakeState.STARTED_EXPLICITLY; +- if (handshake() == NEED_TASK) { +- // Set needTask to true so getHandshakeStatus() will return the correct value. +- needTask = true; +- } +- calculateMaxWrapOverhead(); +- break; +- default: +- throw new Error(); +- } - } - -- @Override -- @Test -- public void testClientHostnameValidationSuccess() throws InterruptedException, SSLException { -- assumeTrue(OpenSsl.supportsHostnameValidation()); -- super.testClientHostnameValidationSuccess(); +- private void checkEngineClosed() throws SSLException { +- if (isDestroyed()) { +- throw new SSLException("engine closed"); +- } - } - -- @Override -- @Test -- public void testClientHostnameValidationFail() throws InterruptedException, SSLException { -- assumeTrue(OpenSsl.supportsHostnameValidation()); -- super.testClientHostnameValidationFail(); +- private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingStatus) { +- // Depending on if there is something left in the BIO we need to WRAP or UNWRAP +- return pendingStatus > 0 ? NEED_WRAP : NEED_UNWRAP; - } - -- @Override -- protected boolean mySetupMutualAuthServerIsValidServerException(Throwable cause) { -- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. -- return super.mySetupMutualAuthServerIsValidServerException(cause) || causedBySSLException(cause); +- private static boolean isEmpty(Object[] arr) { +- return arr == null || arr.length == 0; - } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java -deleted file mode 100644 -index 3959e64..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java -+++ /dev/null -@@ -1,23 +0,0 @@ --/* -- * Copyright 2017 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; - --public class OpenSslRenegotiateSmallBIOTest extends OpenSslRenegotiateTest { -- @Override -- protected void initSslServerContext(SslContext context) { -- ((ReferenceCountedOpenSslContext) context).setBioNonApplicationBufferSize(1); +- private static boolean isEmpty(byte[] cert) { +- return cert == null || cert.length == 0; - } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java -deleted file mode 100644 -index 8f3dfee..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java -+++ /dev/null -@@ -1,36 +0,0 @@ --/* -- * Copyright 2015 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 org.junit.BeforeClass; +- private SSLEngineResult.HandshakeStatus handshakeException() throws SSLException { +- if (SSL.bioLengthNonApplication(networkBIO) > 0) { +- // There is something pending, we need to consume it first via a WRAP so we don't loose anything. +- return NEED_WRAP; +- } +- +- Throwable exception = pendingException; +- assert exception != null; +- pendingException = null; +- shutdown(); +- if (exception instanceof SSLHandshakeException) { +- throw (SSLHandshakeException) exception; +- } +- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem"); +- e.initCause(exception); +- throw e; +- } - --import static org.junit.Assume.assumeFalse; --import static org.junit.Assume.assumeTrue; +- /** +- * Should be called if the handshake will be failed due a callback that throws an exception. +- * This cause will then be used to give more details as part of the {@link SSLHandshakeException}. +- */ +- final void initHandshakeException(Throwable cause) { +- if (pendingException == null) { +- pendingException = cause; +- } else { +- ThrowableUtil.addSuppressed(pendingException, cause); +- } +- } - --public class OpenSslRenegotiateTest extends RenegotiateTest { +- private SSLEngineResult.HandshakeStatus handshake() throws SSLException { +- if (needTask) { +- return NEED_TASK; +- } +- if (handshakeState == HandshakeState.FINISHED) { +- return FINISHED; +- } - -- @BeforeClass -- public static void checkOpenSsl() { -- assumeTrue(OpenSsl.isAvailable()); -- // BoringSSL does not support renegotiation intentionally. -- assumeFalse("BoringSSL".equals(OpenSsl.versionString())); -- } +- checkEngineClosed(); - -- @Override -- protected SslProvider serverSslProvider() { -- return SslProvider.OPENSSL; -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java -deleted file mode 100644 -index f22d045..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java -+++ /dev/null -@@ -1,39 +0,0 @@ --/* -- * 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. -- */ +- if (pendingException != null) { +- // Let's call SSL.doHandshake(...) again in case there is some async operation pending that would fill the +- // outbound buffer. +- if (SSL.doHandshake(ssl) <= 0) { +- // Clear any error that was put on the stack by the handshake +- SSL.clearError(); +- } +- return handshakeException(); +- } - --package io.netty.handler.ssl; +- // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the AbstractCertificateVerifier. +- engineMap.add(this); +- if (lastAccessed == -1) { +- lastAccessed = System.currentTimeMillis(); +- } - --import org.junit.Assume; --import org.junit.BeforeClass; +- int code = SSL.doHandshake(ssl); +- if (code <= 0) { +- int sslError = SSL.getError(ssl, code); +- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) { +- return pendingStatus(SSL.bioLengthNonApplication(networkBIO)); +- } - --import javax.net.ssl.SSLException; --import java.io.File; +- if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP || +- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY || +- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) { +- return NEED_TASK; +- } - --import static org.junit.Assume.assumeTrue; +- // Check if we have a pending exception that was created during the handshake and if so throw it after +- // shutdown the connection. +- if (pendingException != null) { +- return handshakeException(); +- } - --public class OpenSslServerContextTest extends SslContextTest { +- // Everything else is considered as error +- throw shutdownWithError("SSL_do_handshake", sslError); +- } +- // We have produced more data as part of the handshake if this is the case the user should call wrap(...) +- if (SSL.bioLengthNonApplication(networkBIO) > 0) { +- return NEED_WRAP; +- } +- // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means the handshake was finished. +- session.handshakeFinished(); +- return FINISHED; +- } - -- @BeforeClass -- public static void checkOpenSsl() { -- assumeTrue(OpenSsl.isAvailable()); +- private SSLEngineResult.HandshakeStatus mayFinishHandshake(SSLEngineResult.HandshakeStatus status) +- throws SSLException { +- if (status == NOT_HANDSHAKING && handshakeState != HandshakeState.FINISHED) { +- // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call +- // SSL_do_handshake() again +- return handshake(); +- } +- return status; - } - - @Override -- protected SslContext newServerContext(File crtFile, File keyFile, String pass) throws SSLException { -- Assume.assumeTrue(OpenSsl.isAvailable()); -- return new OpenSslServerContext(crtFile, keyFile, pass); +- public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() { +- // Check if we are in the initial handshake phase or shutdown phase +- if (needPendingStatus()) { +- if (needTask) { +- // There is a task outstanding +- return NEED_TASK; +- } +- return pendingStatus(SSL.bioLengthNonApplication(networkBIO)); +- } +- return NOT_HANDSHAKING; - } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java -deleted file mode 100644 -index 7882a61..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java -+++ /dev/null -@@ -1,27 +0,0 @@ --/* -- * Copyright 2017 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 static org.junit.Assume.assumeTrue; -- --final class OpenSslTestUtils { -- private OpenSslTestUtils() { +- private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) { +- // Check if we are in the initial handshake phase or shutdown phase +- if (needPendingStatus()) { +- if (needTask) { +- // There is a task outstanding +- return NEED_TASK; +- } +- return pendingStatus(pending); +- } +- return NOT_HANDSHAKING; - } - -- static void checkShouldUseKeyManagerFactory() { -- assumeTrue(OpenSsl.supportsKeyManagerFactory() && OpenSsl.useKeyManagerFactory()); +- private boolean needPendingStatus() { +- return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed() +- && (handshakeState != HandshakeState.FINISHED || isInboundDone() || isOutboundDone()); - } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java b/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java -deleted file mode 100644 -index 793f772..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java -+++ /dev/null -@@ -1,95 +0,0 @@ --/* -- * 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; +- /** +- * Converts the specified OpenSSL cipher suite to the Java cipher suite. +- */ +- private String toJavaCipherSuite(String openSslCipherSuite) { +- if (openSslCipherSuite == null) { +- return null; +- } - --import static org.junit.Assert.assertEquals; --import static org.junit.Assert.assertTrue; --import static org.junit.Assume.assumeFalse; --import static org.junit.Assume.assumeTrue; +- String version = SSL.getVersion(ssl); +- String prefix = toJavaCipherSuitePrefix(version); +- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix); +- } - --import java.io.ByteArrayOutputStream; --import java.io.File; --import java.io.FileInputStream; +- /** +- * Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string. +- */ +- private static String toJavaCipherSuitePrefix(String protocolVersion) { +- final char c; +- if (protocolVersion == null || protocolVersion.isEmpty()) { +- c = 0; +- } else { +- c = protocolVersion.charAt(0); +- } - --import org.junit.Test; +- switch (c) { +- case 'T': +- return "TLS"; +- case 'S': +- return "SSL"; +- default: +- return "UNKNOWN"; +- } +- } - --import io.netty.handler.ssl.util.SelfSignedCertificate; --import io.netty.util.ReferenceCountUtil; +- @Override +- public final void setUseClientMode(boolean clientMode) { +- if (clientMode != this.clientMode) { +- throw new UnsupportedOperationException(); +- } +- } - --public class PemEncodedTest { +- @Override +- public final boolean getUseClientMode() { +- return clientMode; +- } - -- @Test -- public void testPemEncodedOpenSsl() throws Exception { -- testPemEncoded(SslProvider.OPENSSL); +- @Override +- public final void setNeedClientAuth(boolean b) { +- setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE); - } - -- @Test -- public void testPemEncodedOpenSslRef() throws Exception { -- testPemEncoded(SslProvider.OPENSSL_REFCNT); +- @Override +- public final boolean getNeedClientAuth() { +- return clientAuth == ClientAuth.REQUIRE; - } - -- private static void testPemEncoded(SslProvider provider) throws Exception { -- assumeTrue(OpenSsl.isAvailable()); -- assumeFalse(OpenSsl.useKeyManagerFactory()); -- PemPrivateKey pemKey; -- PemX509Certificate pemCert; -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- try { -- pemKey = PemPrivateKey.valueOf(toByteArray(ssc.privateKey())); -- pemCert = PemX509Certificate.valueOf(toByteArray(ssc.certificate())); -- } finally { -- ssc.delete(); -- } +- @Override +- public final void setWantClientAuth(boolean b) { +- setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE); +- } - -- SslContext context = SslContextBuilder.forServer(pemKey, pemCert) -- .sslProvider(provider) -- .build(); -- assertEquals(1, pemKey.refCnt()); -- assertEquals(1, pemCert.refCnt()); -- try { -- assertTrue(context instanceof ReferenceCountedOpenSslContext); -- } finally { -- ReferenceCountUtil.release(context); -- assertRelease(pemKey); -- assertRelease(pemCert); -- } +- @Override +- public final boolean getWantClientAuth() { +- return clientAuth == ClientAuth.OPTIONAL; - } - -- private static void assertRelease(PemEncoded encoded) { -- assertTrue(encoded.release()); +- /** +- * See <a href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html">SSL_set_verify</a> and +- * {@link SSL#setVerify(long, int, int)}. +- */ +- @UnstableApi +- public final synchronized void setVerify(int verifyMode, int depth) { +- if (!isDestroyed()) { +- SSL.setVerify(ssl, verifyMode, depth); +- } - } - -- private static byte[] toByteArray(File file) throws Exception { -- FileInputStream in = new FileInputStream(file); -- try { -- ByteArrayOutputStream baos = new ByteArrayOutputStream(); -- try { -- byte[] buf = new byte[1024]; -- int len; -- while ((len = in.read(buf)) != -1) { -- baos.write(buf, 0, len); +- private void setClientAuth(ClientAuth mode) { +- if (clientMode) { +- return; +- } +- synchronized (this) { +- if (clientAuth == mode) { +- // No need to issue any JNI calls if the mode is the same +- return; +- } +- if (!isDestroyed()) { +- switch (mode) { +- case NONE: +- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, ReferenceCountedOpenSslContext.VERIFY_DEPTH); +- break; +- case REQUIRE: +- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, ReferenceCountedOpenSslContext.VERIFY_DEPTH); +- break; +- case OPTIONAL: +- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, ReferenceCountedOpenSslContext.VERIFY_DEPTH); +- break; +- default: +- throw new Error(mode.toString()); - } -- } finally { -- baos.close(); - } +- clientAuth = mode; +- } +- } - -- return baos.toByteArray(); -- } finally { -- in.close(); +- @Override +- public final void setEnableSessionCreation(boolean b) { +- if (b) { +- throw new UnsupportedOperationException(); - } - } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java -deleted file mode 100644 -index 6d38940..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java -+++ /dev/null -@@ -1,57 +0,0 @@ --/* -- * 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.util.ReferenceCountUtil; +- @Override +- public final boolean getEnableSessionCreation() { +- return false; +- } - --import javax.net.ssl.SSLEngine; +- @SuppressJava6Requirement(reason = "Usage guarded by java version check") +- @Override +- public final synchronized SSLParameters getSSLParameters() { +- SSLParameters sslParameters = super.getSSLParameters(); +- +- int version = PlatformDependent.javaVersion(); +- if (version >= 7) { +- sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm); +- Java7SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints); +- if (version >= 8) { +- if (sniHostNames != null) { +- Java8SslUtils.setSniHostNames(sslParameters, sniHostNames); +- } +- if (!isDestroyed()) { +- Java8SslUtils.setUseCipherSuitesOrder( +- sslParameters, (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0); +- } +- +- Java8SslUtils.setSNIMatchers(sslParameters, matchers); +- } +- } +- return sslParameters; +- } - --public class ReferenceCountedOpenSslEngineTest extends OpenSslEngineTest { +- @SuppressJava6Requirement(reason = "Usage guarded by java version check") +- @Override +- public final synchronized void setSSLParameters(SSLParameters sslParameters) { +- int version = PlatformDependent.javaVersion(); +- if (version >= 7) { +- if (sslParameters.getAlgorithmConstraints() != null) { +- throw new IllegalArgumentException("AlgorithmConstraints are not supported."); +- } - -- public ReferenceCountedOpenSslEngineTest(BufferType type) { -- super(type); -- } +- boolean isDestroyed = isDestroyed(); +- if (version >= 8) { +- if (!isDestroyed) { +- if (clientMode) { +- final List<String> sniHostNames = Java8SslUtils.getSniHostNames(sslParameters); +- for (String name: sniHostNames) { +- SSL.setTlsExtHostName(ssl, name); +- } +- this.sniHostNames = sniHostNames; +- } +- if (Java8SslUtils.getUseCipherSuitesOrder(sslParameters)) { +- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); +- } else { +- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); +- } +- } +- matchers = sslParameters.getSNIMatchers(); +- } - -- @Override -- protected SslProvider sslClientProvider() { -- return SslProvider.OPENSSL_REFCNT; +- final String endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm(); +- if (!isDestroyed) { +- // If the user asks for hostname verification we must ensure we verify the peer. +- // If the user disables hostname verification we leave it up to the user to change the mode manually. +- if (clientMode && isEndPointVerificationEnabled(endPointIdentificationAlgorithm)) { +- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1); +- } +- } +- this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm; +- algorithmConstraints = sslParameters.getAlgorithmConstraints(); +- } +- super.setSSLParameters(sslParameters); - } - -- @Override -- protected SslProvider sslServerProvider() { -- return SslProvider.OPENSSL_REFCNT; +- private static boolean isEndPointVerificationEnabled(String endPointIdentificationAlgorithm) { +- return endPointIdentificationAlgorithm != null && !endPointIdentificationAlgorithm.isEmpty(); - } - -- @Override -- protected void cleanupClientSslContext(SslContext ctx) { -- ReferenceCountUtil.release(ctx); +- private boolean isDestroyed() { +- return destroyed; - } - -- @Override -- protected void cleanupClientSslEngine(SSLEngine engine) { -- ReferenceCountUtil.release(engine); +- final boolean checkSniHostnameMatch(byte[] hostname) { +- return Java8SslUtils.checkSniHostnameMatch(matchers, hostname); - } - - @Override -- protected void cleanupServerSslContext(SslContext ctx) { -- ReferenceCountUtil.release(ctx); +- public String getNegotiatedApplicationProtocol() { +- return applicationProtocol; - } - -- @Override -- protected void cleanupServerSslEngine(SSLEngine engine) { -- ReferenceCountUtil.release(engine); +- private static long bufferAddress(ByteBuffer b) { +- assert b.isDirect(); +- if (PlatformDependent.hasUnsafe()) { +- return PlatformDependent.directBufferAddress(b); +- } +- return Buffer.address(b); - } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java -deleted file mode 100644 -index 3193d20..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java -+++ /dev/null -@@ -1,161 +0,0 @@ --/* -- * 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 io.netty.util.internal.PlatformDependent; --import org.junit.Assert; --import org.junit.Assume; --import org.junit.Test; - --import java.nio.channels.ClosedChannelException; -- --public class SniClientTest { -- -- @Test(timeout = 30000) -- public void testSniClientJdkSslServerJdkSsl() throws Exception { -- testSniClient(SslProvider.JDK, SslProvider.JDK); -- } +- private final class DefaultOpenSslSession implements OpenSslSession { +- private final OpenSslSessionContext sessionContext; - -- @Test(timeout = 30000) -- public void testSniClientOpenSslServerOpenSsl() throws Exception { -- Assume.assumeTrue(OpenSsl.isAvailable()); -- testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL); -- } +- // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any +- // thread. +- private X509Certificate[] x509PeerCerts; +- private Certificate[] peerCerts; - -- @Test(timeout = 30000) -- public void testSniClientJdkSslServerOpenSsl() throws Exception { -- Assume.assumeTrue(OpenSsl.isAvailable()); -- testSniClient(SslProvider.JDK, SslProvider.OPENSSL); -- } +- private String protocol; +- private String cipher; +- private byte[] id; +- private long creationTime; +- private volatile int applicationBufferSize = MAX_PLAINTEXT_LENGTH; - -- @Test(timeout = 30000) -- public void testSniClientOpenSslServerJdkSsl() throws Exception { -- Assume.assumeTrue(OpenSsl.isAvailable()); -- testSniClient(SslProvider.OPENSSL, SslProvider.JDK); -- } +- // lazy init for memory reasons +- private Map<String, Object> values; - -- @Test(timeout = 30000) -- public void testSniSNIMatcherMatchesClientJdkSslServerJdkSsl() throws Exception { -- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); -- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, true); -- } +- DefaultOpenSslSession(OpenSslSessionContext sessionContext) { +- this.sessionContext = sessionContext; +- } - -- @Test(timeout = 30000, expected = ClosedChannelException.class) -- public void testSniSNIMatcherDoesNotMatchClientJdkSslServerJdkSsl() throws Exception { -- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); -- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, false); -- } +- private SSLSessionBindingEvent newSSLSessionBindingEvent(String name) { +- return new SSLSessionBindingEvent(session, name); +- } - -- @Test(timeout = 30000) -- public void testSniSNIMatcherMatchesClientOpenSslServerOpenSsl() throws Exception { -- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); -- Assume.assumeTrue(OpenSsl.isAvailable()); -- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL, true); -- } +- @Override +- public byte[] getId() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (id == null) { +- return EmptyArrays.EMPTY_BYTES; +- } +- return id.clone(); +- } +- } - -- @Test(timeout = 30000, expected = ClosedChannelException.class) -- public void testSniSNIMatcherDoesNotMatchClientOpenSslServerOpenSsl() throws Exception { -- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); -- Assume.assumeTrue(OpenSsl.isAvailable()); -- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL, false); -- } +- @Override +- public SSLSessionContext getSessionContext() { +- return sessionContext; +- } - -- @Test(timeout = 30000) -- public void testSniSNIMatcherMatchesClientJdkSslServerOpenSsl() throws Exception { -- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); -- Assume.assumeTrue(OpenSsl.isAvailable()); -- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL, true); -- } +- @Override +- public long getCreationTime() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (creationTime == 0 && !isDestroyed()) { +- creationTime = SSL.getTime(ssl) * 1000L; +- } +- } +- return creationTime; +- } - -- @Test(timeout = 30000, expected = ClosedChannelException.class) -- public void testSniSNIMatcherDoesNotMatchClientJdkSslServerOpenSsl() throws Exception { -- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); -- Assume.assumeTrue(OpenSsl.isAvailable()); -- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL, false); -- } +- @Override +- public long getLastAccessedTime() { +- long lastAccessed = ReferenceCountedOpenSslEngine.this.lastAccessed; +- // if lastAccessed is -1 we will just return the creation time as the handshake was not started yet. +- return lastAccessed == -1 ? getCreationTime() : lastAccessed; +- } - -- @Test(timeout = 30000) -- public void testSniSNIMatcherMatchesClientOpenSslServerJdkSsl() throws Exception { -- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); -- Assume.assumeTrue(OpenSsl.isAvailable()); -- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK, true); -- } +- @Override +- public void invalidate() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (!isDestroyed()) { +- SSL.setTimeout(ssl, 0); +- } +- } +- } - -- @Test(timeout = 30000, expected = ClosedChannelException.class) -- public void testSniSNIMatcherDoesNotMatchClientOpenSslServerJdkSsl() throws Exception { -- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); -- Assume.assumeTrue(OpenSsl.isAvailable()); -- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK, false); -- } +- @Override +- public boolean isValid() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (!isDestroyed()) { +- return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L) < (SSL.getTime(ssl) * 1000L); +- } +- } +- return false; +- } - -- 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(); +- @Override +- public void putValue(String name, Object value) { +- ObjectUtil.checkNotNull(name, "name"); +- ObjectUtil.checkNotNull(value, "value"); - -- final Promise<String> promise = group.next().newPromise(); -- ServerBootstrap sb = new ServerBootstrap(); -- sc = sb.group(group).channel(LocalServerChannel.class).childHandler(new ChannelInitializer<Channel>() { -- @Override -- protected void initChannel(Channel ch) throws Exception { -- ch.pipeline().addFirst(new SniHandler(new Mapping<String, SslContext>() { -- @Override -- public SslContext map(String input) { -- promise.setSuccess(input); -- return sslServerContext; -- } -- })); +- final Object old; +- synchronized (this) { +- Map<String, Object> values = this.values; +- if (values == null) { +- // Use size of 2 to keep the memory overhead small +- values = this.values = new HashMap<String, Object>(2); - } -- }).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().syncUninterruptibly(); +- old = values.put(name, value); - } -- if (sc != null) { -- sc.close().syncUninterruptibly(); +- +- if (value instanceof SSLSessionBindingListener) { +- // Use newSSLSessionBindingEvent so we alway use the wrapper if needed. +- ((SSLSessionBindingListener) value).valueBound(newSSLSessionBindingEvent(name)); - } -- group.shutdownGracefully(); +- notifyUnbound(old, name); - } -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java b/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java -deleted file mode 100644 -index 07c87c6..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java -+++ /dev/null -@@ -1,496 +0,0 @@ --/* -- * Copyright 2014 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; +- @Override +- public Object getValue(String name) { +- ObjectUtil.checkNotNull(name, "name"); +- synchronized (this) { +- if (values == null) { +- return null; +- } +- return values.get(name); +- } +- } - --import static org.hamcrest.CoreMatchers.is; --import static org.hamcrest.CoreMatchers.nullValue; --import static org.junit.Assert.assertEquals; --import static org.junit.Assert.assertThat; --import static org.junit.Assert.assertTrue; --import static org.junit.Assume.assumeTrue; +- @Override +- public void removeValue(String name) { +- ObjectUtil.checkNotNull(name, "name"); - --import java.io.File; --import java.net.InetSocketAddress; --import java.util.ArrayList; --import java.util.List; --import java.util.concurrent.CountDownLatch; --import java.util.concurrent.TimeUnit; +- final Object old; +- synchronized (this) { +- Map<String, Object> values = this.values; +- if (values == null) { +- return; +- } +- old = values.remove(name); +- } - --import javax.net.ssl.SSLEngine; +- notifyUnbound(old, name); +- } - --import org.junit.Test; +- @Override +- public String[] getValueNames() { +- synchronized (this) { +- Map<String, Object> values = this.values; +- if (values == null || values.isEmpty()) { +- return EmptyArrays.EMPTY_STRINGS; +- } +- return values.keySet().toArray(new String[0]); +- } +- } - --import io.netty.bootstrap.Bootstrap; --import io.netty.bootstrap.ServerBootstrap; --import io.netty.buffer.ByteBufAllocator; --import io.netty.buffer.Unpooled; --import io.netty.channel.Channel; --import io.netty.channel.ChannelFuture; --import io.netty.channel.ChannelHandlerContext; --import io.netty.channel.ChannelInitializer; --import io.netty.channel.ChannelPipeline; --import io.netty.channel.DefaultEventLoopGroup; --import io.netty.channel.EventLoopGroup; --import io.netty.channel.embedded.EmbeddedChannel; --import io.netty.channel.local.LocalAddress; --import io.netty.channel.local.LocalChannel; --import io.netty.channel.local.LocalServerChannel; --import io.netty.channel.nio.NioEventLoopGroup; --import io.netty.channel.socket.nio.NioServerSocketChannel; --import io.netty.channel.socket.nio.NioSocketChannel; --import io.netty.handler.codec.DecoderException; --import io.netty.handler.ssl.util.InsecureTrustManagerFactory; --import io.netty.handler.ssl.util.SelfSignedCertificate; --import io.netty.util.DomainNameMapping; --import io.netty.util.DomainNameMappingBuilder; --import io.netty.util.Mapping; --import io.netty.util.ReferenceCountUtil; --import io.netty.util.ReferenceCounted; --import io.netty.util.concurrent.Promise; --import io.netty.util.internal.ObjectUtil; --import io.netty.util.internal.StringUtil; --import org.junit.runner.RunWith; --import org.junit.runners.Parameterized; +- private void notifyUnbound(Object value, String name) { +- if (value instanceof SSLSessionBindingListener) { +- // Use newSSLSessionBindingEvent so we alway use the wrapper if needed. +- ((SSLSessionBindingListener) value).valueUnbound(newSSLSessionBindingEvent(name)); +- } +- } - --@RunWith(Parameterized.class) --public class SniHandlerTest { +- /** +- * Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by +- * the user. +- */ +- @Override +- public void handshakeFinished() throws SSLException { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (!isDestroyed()) { +- id = SSL.getSessionId(ssl); +- cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl)); +- protocol = SSL.getVersion(ssl); - -- private static ApplicationProtocolConfig newApnConfig() { -- return new ApplicationProtocolConfig( -- ApplicationProtocolConfig.Protocol.ALPN, -- // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers. -- ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, -- // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers. -- ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, -- "myprotocol"); -- } +- initPeerCerts(); +- selectApplicationProtocol(); +- calculateMaxWrapOverhead(); - -- private static void assumeApnSupported(SslProvider provider) { -- switch (provider) { -- case OPENSSL: -- case OPENSSL_REFCNT: -- assumeTrue(OpenSsl.isAlpnSupported()); -- break; -- case JDK: -- assumeTrue(JettyAlpnSslEngine.isAvailable()); -- break; -- default: -- throw new Error(); +- handshakeState = HandshakeState.FINISHED; +- } else { +- throw new SSLException("Already closed"); +- } +- } - } -- } - -- private static SslContext makeSslContext(SslProvider provider, boolean apn) throws Exception { -- if (apn) { -- assumeApnSupported(provider); +- /** +- * Init peer certificates that can be obtained via {@link #getPeerCertificateChain()} +- * and {@link #getPeerCertificates()}. +- */ +- private void initPeerCerts() { +- // Return the full chain from the JNI layer. +- byte[][] chain = SSL.getPeerCertChain(ssl); +- if (clientMode) { +- if (isEmpty(chain)) { +- peerCerts = EmptyArrays.EMPTY_CERTIFICATES; +- x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES; +- } else { +- peerCerts = new Certificate[chain.length]; +- x509PeerCerts = new X509Certificate[chain.length]; +- initCerts(chain, 0); +- } +- } else { +- // if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer +- // certificate. We use SSL_get_peer_certificate to get it in this case and add it to our +- // array later. +- // +- // See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html +- byte[] clientCert = SSL.getPeerCertificate(ssl); +- if (isEmpty(clientCert)) { +- peerCerts = EmptyArrays.EMPTY_CERTIFICATES; +- x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES; +- } else { +- if (isEmpty(chain)) { +- peerCerts = new Certificate[] {new OpenSslX509Certificate(clientCert)}; +- x509PeerCerts = new X509Certificate[] {new OpenSslJavaxX509Certificate(clientCert)}; +- } else { +- peerCerts = new Certificate[chain.length + 1]; +- x509PeerCerts = new X509Certificate[chain.length + 1]; +- peerCerts[0] = new OpenSslX509Certificate(clientCert); +- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert); +- initCerts(chain, 1); +- } +- } +- } - } - -- File keyFile = new File(SniHandlerTest.class.getResource("test_encrypted.pem").getFile()); -- File crtFile = new File(SniHandlerTest.class.getResource("test.crt").getFile()); -- -- SslContextBuilder sslCtxBuilder = SslContextBuilder.forServer(crtFile, keyFile, "12345") -- .sslProvider(provider); -- if (apn) { -- sslCtxBuilder.applicationProtocolConfig(newApnConfig()); +- private void initCerts(byte[][] chain, int startPos) { +- for (int i = 0; i < chain.length; i++) { +- int certPos = startPos + i; +- peerCerts[certPos] = new OpenSslX509Certificate(chain[i]); +- x509PeerCerts[certPos] = new OpenSslJavaxX509Certificate(chain[i]); +- } - } -- return sslCtxBuilder.build(); -- } - -- private static SslContext makeSslClientContext(SslProvider provider, boolean apn) throws Exception { -- if (apn) { -- assumeApnSupported(provider); +- /** +- * Select the application protocol used. +- */ +- private void selectApplicationProtocol() throws SSLException { +- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior = apn.selectedListenerFailureBehavior(); +- List<String> protocols = apn.protocols(); +- String applicationProtocol; +- switch (apn.protocol()) { +- case NONE: +- break; +- // We always need to check for applicationProtocol == null as the remote peer may not support +- // the TLS extension or may have returned an empty selection. +- case ALPN: +- applicationProtocol = SSL.getAlpnSelected(ssl); +- if (applicationProtocol != null) { +- ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol( +- protocols, behavior, applicationProtocol); +- } +- break; +- case NPN: +- applicationProtocol = SSL.getNextProtoNegotiated(ssl); +- if (applicationProtocol != null) { +- ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol( +- protocols, behavior, applicationProtocol); +- } +- break; +- case NPN_AND_ALPN: +- applicationProtocol = SSL.getAlpnSelected(ssl); +- if (applicationProtocol == null) { +- applicationProtocol = SSL.getNextProtoNegotiated(ssl); +- } +- if (applicationProtocol != null) { +- ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol( +- protocols, behavior, applicationProtocol); +- } +- break; +- default: +- throw new Error(); +- } - } - -- File crtFile = new File(SniHandlerTest.class.getResource("test.crt").getFile()); -- -- SslContextBuilder sslCtxBuilder = SslContextBuilder.forClient().trustManager(crtFile).sslProvider(provider); -- if (apn) { -- sslCtxBuilder.applicationProtocolConfig(newApnConfig()); +- private String selectApplicationProtocol(List<String> protocols, +- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior, +- String applicationProtocol) throws SSLException { +- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) { +- return applicationProtocol; +- } else { +- int size = protocols.size(); +- assert size > 0; +- if (protocols.contains(applicationProtocol)) { +- return applicationProtocol; +- } else { +- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) { +- return protocols.get(size - 1); +- } else { +- throw new SSLException("unknown protocol " + applicationProtocol); +- } +- } +- } - } -- return sslCtxBuilder.build(); -- } - -- @Parameterized.Parameters(name = "{index}: sslProvider={0}") -- public static Iterable<?> data() { -- List<SslProvider> params = new ArrayList<SslProvider>(3); -- if (OpenSsl.isAvailable()) { -- params.add(SslProvider.OPENSSL); -- params.add(SslProvider.OPENSSL_REFCNT); +- @Override +- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (isEmpty(peerCerts)) { +- throw new SSLPeerUnverifiedException("peer not verified"); +- } +- return peerCerts.clone(); +- } - } -- params.add(SslProvider.JDK); -- return params; -- } -- -- private final SslProvider provider; - -- public SniHandlerTest(SslProvider provider) { -- this.provider = provider; -- } -- -- @Test -- public void testServerNameParsing() throws Exception { -- SslContext nettyContext = makeSslContext(provider, false); -- SslContext leanContext = makeSslContext(provider, false); -- SslContext leanContext2 = makeSslContext(provider, false); -- -- try { -- DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext) -- .add("*.netty.io", nettyContext) -- // input with custom cases -- .add("*.LEANCLOUD.CN", leanContext) -- // a hostname conflict with previous one, since we are using order-sensitive config, -- // the engine won't be used with the handler. -- .add("chat4.leancloud.cn", leanContext2) -- .build(); -- -- SniHandler handler = new SniHandler(mapping); -- EmbeddedChannel ch = new EmbeddedChannel(handler); -- -- try { -- // hex dump of a client hello packet, which contains hostname "CHAT4.LEANCLOUD.CN" -- String tlsHandshakeMessageHex1 = "16030100"; -- // part 2 -- String tlsHandshakeMessageHex = "c6010000c20303bb0855d66532c05a0ef784f7c384feeafa68b3" + -- "b655ac7288650d5eed4aa3fb52000038c02cc030009fcca9cca8ccaac02b" + -- "c02f009ec024c028006bc023c0270067c00ac0140039c009c0130033009d" + -- "009c003d003c0035002f00ff010000610000001700150000124348415434" + -- "2e4c45414e434c4f55442e434e000b000403000102000a000a0008001d00" + -- "170019001800230000000d0020001e060106020603050105020503040104" + -- "0204030301030203030201020202030016000000170000"; -- -- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1))); -- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex))); -- -- // This should produce an alert -- assertTrue(ch.finish()); -- -- assertThat(handler.hostname(), is("chat4.leancloud.cn")); -- assertThat(handler.sslContext(), is(leanContext)); -- } finally { -- ch.finishAndReleaseAll(); +- @Override +- public Certificate[] getLocalCertificates() { +- Certificate[] localCerts = ReferenceCountedOpenSslEngine.this.localCertificateChain; +- if (localCerts == null) { +- return null; - } -- } finally { -- releaseAll(leanContext, leanContext2, nettyContext); +- return localCerts.clone(); - } -- } -- -- @Test(expected = DecoderException.class) -- public void testNonAsciiServerNameParsing() throws Exception { -- SslContext nettyContext = makeSslContext(provider, false); -- SslContext leanContext = makeSslContext(provider, false); -- SslContext leanContext2 = makeSslContext(provider, false); - -- try { -- DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext) -- .add("*.netty.io", nettyContext) -- // input with custom cases -- .add("*.LEANCLOUD.CN", leanContext) -- // a hostname conflict with previous one, since we are using order-sensitive config, -- // the engine won't be used with the handler. -- .add("chat4.leancloud.cn", leanContext2) -- .build(); -- -- SniHandler handler = new SniHandler(mapping); -- EmbeddedChannel ch = new EmbeddedChannel(handler); -- -- try { -- // hex dump of a client hello packet, which contains an invalid hostname "CHAT4。LEANCLOUD。CN" -- String tlsHandshakeMessageHex1 = "16030100"; -- // part 2 -- String tlsHandshakeMessageHex = "bd010000b90303a74225676d1814ba57faff3b366" + -- "3656ed05ee9dbb2a4dbb1bb1c32d2ea5fc39e0000000100008c0000001700150000164348" + -- "415434E380824C45414E434C4F5544E38082434E000b000403000102000a00340032000e0" + -- "00d0019000b000c00180009000a0016001700080006000700140015000400050012001300" + -- "0100020003000f0010001100230000000d0020001e0601060206030501050205030401040" + -- "20403030103020303020102020203000f00010133740000"; -- -- // Push the handshake message. -- // Decode should fail because of the badly encoded "HostName" string in the SNI extension -- // that isn't ASCII as per RFC 6066 - https://tools.ietf.org/html/rfc6066#page-6 -- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1))); -- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex))); -- } finally { -- ch.finishAndReleaseAll(); +- @Override +- public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (isEmpty(x509PeerCerts)) { +- throw new SSLPeerUnverifiedException("peer not verified"); +- } +- return x509PeerCerts.clone(); - } -- } finally { -- releaseAll(leanContext, leanContext2, nettyContext); - } -- } -- -- @Test -- public void testFallbackToDefaultContext() throws Exception { -- SslContext nettyContext = makeSslContext(provider, false); -- SslContext leanContext = makeSslContext(provider, false); -- SslContext leanContext2 = makeSslContext(provider, false); -- -- try { -- DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext) -- .add("*.netty.io", nettyContext) -- // input with custom cases -- .add("*.LEANCLOUD.CN", leanContext) -- // a hostname conflict with previous one, since we are using order-sensitive config, -- // the engine won't be used with the handler. -- .add("chat4.leancloud.cn", leanContext2) -- .build(); - -- SniHandler handler = new SniHandler(mapping); -- EmbeddedChannel ch = new EmbeddedChannel(handler); -- -- // invalid -- byte[] message = {22, 3, 1, 0, 0}; +- @Override +- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { +- Certificate[] peer = getPeerCertificates(); +- // No need for null or length > 0 is needed as this is done in getPeerCertificates() +- // already. +- return ((java.security.cert.X509Certificate) peer[0]).getSubjectX500Principal(); +- } - -- try { -- // Push the handshake message. -- ch.writeInbound(Unpooled.wrappedBuffer(message)); -- } catch (Exception e) { -- // expected +- @Override +- public Principal getLocalPrincipal() { +- Certificate[] local = ReferenceCountedOpenSslEngine.this.localCertificateChain; +- if (local == null || local.length == 0) { +- return null; - } -- -- assertThat(ch.finish(), is(false)); -- assertThat(handler.hostname(), nullValue()); -- assertThat(handler.sslContext(), is(nettyContext)); -- } finally { -- releaseAll(leanContext, leanContext2, nettyContext); +- return ((java.security.cert.X509Certificate) local[0]).getIssuerX500Principal(); - } -- } -- -- @Test -- public void testSniWithApnHandler() throws Exception { -- SslContext nettyContext = makeSslContext(provider, true); -- SslContext sniContext = makeSslContext(provider, true); -- final SslContext clientContext = makeSslClientContext(provider, true); -- try { -- final CountDownLatch serverApnDoneLatch = new CountDownLatch(1); -- final CountDownLatch clientApnDoneLatch = new CountDownLatch(1); -- -- final DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext) -- .add("*.netty.io", nettyContext) -- .add("sni.fake.site", sniContext).build(); -- final SniHandler handler = new SniHandler(mapping); -- EventLoopGroup group = new NioEventLoopGroup(2); -- Channel serverChannel = null; -- Channel clientChannel = null; -- try { -- ServerBootstrap sb = new ServerBootstrap(); -- sb.group(group); -- sb.channel(NioServerSocketChannel.class); -- sb.childHandler(new ChannelInitializer<Channel>() { -- @Override -- protected void initChannel(Channel ch) throws Exception { -- ChannelPipeline p = ch.pipeline(); -- // Server side SNI. -- p.addLast(handler); -- // Catch the notification event that APN has completed successfully. -- p.addLast(new ApplicationProtocolNegotiationHandler("foo") { -- @Override -- protected void configurePipeline(ChannelHandlerContext ctx, String protocol) { -- serverApnDoneLatch.countDown(); -- } -- }); -- } -- }); -- -- Bootstrap cb = new Bootstrap(); -- cb.group(group); -- cb.channel(NioSocketChannel.class); -- cb.handler(new ChannelInitializer<Channel>() { -- @Override -- protected void initChannel(Channel ch) throws Exception { -- ch.pipeline().addLast(new SslHandler(clientContext.newEngine( -- ch.alloc(), "sni.fake.site", -1))); -- // Catch the notification event that APN has completed successfully. -- ch.pipeline().addLast(new ApplicationProtocolNegotiationHandler("foo") { -- @Override -- protected void configurePipeline(ChannelHandlerContext ctx, String protocol) { -- clientApnDoneLatch.countDown(); -- } -- }); -- } -- }); -- -- serverChannel = sb.bind(new InetSocketAddress(0)).sync().channel(); - -- ChannelFuture ccf = cb.connect(serverChannel.localAddress()); -- assertTrue(ccf.awaitUninterruptibly().isSuccess()); -- clientChannel = ccf.channel(); -- -- assertTrue(serverApnDoneLatch.await(5, TimeUnit.SECONDS)); -- assertTrue(clientApnDoneLatch.await(5, TimeUnit.SECONDS)); -- assertThat(handler.hostname(), is("sni.fake.site")); -- assertThat(handler.sslContext(), is(sniContext)); -- } finally { -- if (serverChannel != null) { -- serverChannel.close().sync(); -- } -- if (clientChannel != null) { -- clientChannel.close().sync(); +- @Override +- public String getCipherSuite() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (cipher == null) { +- return SslUtils.INVALID_CIPHER; - } -- group.shutdownGracefully(0, 0, TimeUnit.MICROSECONDS); +- return cipher; - } -- } finally { -- releaseAll(clientContext, nettyContext, sniContext); - } -- } -- -- @Test(timeout = 30000) -- public void testReplaceHandler() throws Exception { -- switch (provider) { -- case OPENSSL: -- case OPENSSL_REFCNT: -- final String sniHost = "sni.netty.io"; -- LocalAddress address = new LocalAddress("testReplaceHandler-" + Math.random()); -- EventLoopGroup group = new DefaultEventLoopGroup(1); -- Channel sc = null; -- Channel cc = null; -- SslContext sslContext = null; -- -- SelfSignedCertificate cert = new SelfSignedCertificate(); -- -- try { -- final SslContext sslServerContext = SslContextBuilder -- .forServer(cert.key(), cert.cert()) -- .sslProvider(provider) -- .build(); -- -- final Mapping<String, SslContext> mapping = new Mapping<String, SslContext>() { -- @Override -- public SslContext map(String input) { -- return sslServerContext; -- } -- }; -- -- final Promise<Void> releasePromise = group.next().newPromise(); -- -- final SniHandler handler = new SniHandler(mapping) { -- @Override -- protected void replaceHandler(ChannelHandlerContext ctx, -- String hostname, final SslContext sslContext) -- throws Exception { -- -- boolean success = false; -- try { -- // The SniHandler's replaceHandler() method allows us to implement custom behavior. -- // As an example, we want to release() the SslContext upon channelInactive() or rather -- // when the SslHandler closes it's SslEngine. If you take a close look at SslHandler -- // you'll see that it's doing it in the #handlerRemoved0() method. -- -- SSLEngine sslEngine = sslContext.newEngine(ctx.alloc()); -- try { -- SslHandler customSslHandler = new CustomSslHandler(sslContext, sslEngine) { -- @Override -- public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { -- try { -- super.handlerRemoved0(ctx); -- } finally { -- releasePromise.trySuccess(null); -- } -- } -- }; -- ctx.pipeline().replace(this, CustomSslHandler.class.getName(), customSslHandler); -- success = true; -- } finally { -- if (!success) { -- ReferenceCountUtil.safeRelease(sslEngine); -- } -- } -- } finally { -- if (!success) { -- ReferenceCountUtil.safeRelease(sslContext); -- releasePromise.cancel(true); -- } -- } -- } -- }; -- -- ServerBootstrap sb = new ServerBootstrap(); -- sc = sb.group(group).channel(LocalServerChannel.class) -- .childHandler(new ChannelInitializer<Channel>() { -- @Override -- protected void initChannel(Channel ch) throws Exception { -- ch.pipeline().addFirst(handler); -- } -- }).bind(address).syncUninterruptibly().channel(); -- -- sslContext = SslContextBuilder.forClient().sslProvider(provider) -- .trustManager(InsecureTrustManagerFactory.INSTANCE).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(); -- -- cc.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes())) -- .syncUninterruptibly(); -- -- // Notice how the server's SslContext refCnt is 1 -- assertEquals(1, ((ReferenceCounted) sslServerContext).refCnt()); -- -- // The client disconnects -- cc.close().syncUninterruptibly(); -- if (!releasePromise.awaitUninterruptibly(10L, TimeUnit.SECONDS)) { -- throw new IllegalStateException("It doesn't seem #replaceHandler() got called."); -- } - -- // We should have successfully release() the SslContext -- assertEquals(0, ((ReferenceCounted) sslServerContext).refCnt()); -- } finally { -- if (cc != null) { -- cc.close().syncUninterruptibly(); -- } -- if (sc != null) { -- sc.close().syncUninterruptibly(); -- } -- if (sslContext != null) { -- ReferenceCountUtil.release(sslContext); +- @Override +- public String getProtocol() { +- String protocol = this.protocol; +- if (protocol == null) { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (!isDestroyed()) { +- protocol = SSL.getVersion(ssl); +- } else { +- protocol = StringUtil.EMPTY_STRING; - } -- group.shutdownGracefully(); -- -- cert.delete(); - } -- case JDK: -- return; -- default: -- throw new Error(); +- } +- return protocol; - } -- } -- -- /** -- * This is a {@link SslHandler} that will call {@code release()} on the {@link SslContext} when -- * the client disconnects. -- * -- * @see SniHandlerTest#testReplaceHandler() -- */ -- private static class CustomSslHandler extends SslHandler { -- private final SslContext sslContext; - -- public CustomSslHandler(SslContext sslContext, SSLEngine sslEngine) { -- super(sslEngine); -- this.sslContext = ObjectUtil.checkNotNull(sslContext, "sslContext"); +- @Override +- public String getPeerHost() { +- return ReferenceCountedOpenSslEngine.this.getPeerHost(); - } - - @Override -- public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { -- super.handlerRemoved0(ctx); -- ReferenceCountUtil.release(sslContext); +- public int getPeerPort() { +- return ReferenceCountedOpenSslEngine.this.getPeerPort(); - } -- } - -- private static void releaseAll(SslContext... contexts) { -- for (SslContext ctx: contexts) { -- ReferenceCountUtil.release(ctx); +- @Override +- public int getPacketBufferSize() { +- return maxEncryptedPacketLength(); - } -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java b/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java -deleted file mode 100644 -index 752424c..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java -+++ /dev/null -@@ -1,132 +0,0 @@ --/* -- * Copyright 2015 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 static org.junit.Assert.assertFalse; --import static org.junit.Assert.assertTrue; - --import io.netty.buffer.UnpooledByteBufAllocator; --import io.netty.handler.ssl.util.SelfSignedCertificate; --import org.junit.Assume; --import org.junit.Test; -- --import javax.net.ssl.SSLEngine; +- @Override +- public int getApplicationBufferSize() { +- return applicationBufferSize; +- } - --public class SslContextBuilderTest { -- -- @Test -- public void testClientContextFromFileJdk() throws Exception { -- testClientContextFromFile(SslProvider.JDK); -- } -- -- @Test -- public void testClientContextFromFileOpenssl() throws Exception { -- Assume.assumeTrue(OpenSsl.isAvailable()); -- testClientContextFromFile(SslProvider.OPENSSL); -- } -- -- @Test -- public void testClientContextJdk() throws Exception { -- testClientContext(SslProvider.JDK); -- } -- -- @Test -- public void testClientContextOpenssl() throws Exception { -- Assume.assumeTrue(OpenSsl.isAvailable()); -- testClientContext(SslProvider.OPENSSL); -- } -- -- @Test -- public void testServerContextFromFileJdk() throws Exception { -- testServerContextFromFile(SslProvider.JDK); -- } -- -- @Test -- public void testServerContextFromFileOpenssl() throws Exception { -- Assume.assumeTrue(OpenSsl.isAvailable()); -- testServerContextFromFile(SslProvider.OPENSSL); -- } -- -- @Test -- public void testServerContextJdk() throws Exception { -- testServerContext(SslProvider.JDK); -- } -- -- @Test -- public void testServerContextOpenssl() throws Exception { -- Assume.assumeTrue(OpenSsl.isAvailable()); -- testServerContext(SslProvider.OPENSSL); -- } -- -- private static void testClientContextFromFile(SslProvider provider) throws Exception { -- SelfSignedCertificate cert = new SelfSignedCertificate(); -- SslContextBuilder builder = SslContextBuilder.forClient() -- .sslProvider(provider) -- .keyManager(cert.certificate(), -- cert.privateKey()) -- .trustManager(cert.certificate()) -- .clientAuth(ClientAuth.OPTIONAL); -- SslContext context = builder.build(); -- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); -- assertFalse(engine.getWantClientAuth()); -- assertFalse(engine.getNeedClientAuth()); -- engine.closeInbound(); -- engine.closeOutbound(); -- } -- -- private static void testClientContext(SslProvider provider) throws Exception { -- SelfSignedCertificate cert = new SelfSignedCertificate(); -- SslContextBuilder builder = SslContextBuilder.forClient() -- .sslProvider(provider) -- .keyManager(cert.key(), cert.cert()) -- .trustManager(cert.cert()) -- .clientAuth(ClientAuth.OPTIONAL); -- SslContext context = builder.build(); -- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); -- assertFalse(engine.getWantClientAuth()); -- assertFalse(engine.getNeedClientAuth()); -- engine.closeInbound(); -- engine.closeOutbound(); -- } -- -- private static void testServerContextFromFile(SslProvider provider) throws Exception { -- SelfSignedCertificate cert = new SelfSignedCertificate(); -- SslContextBuilder builder = SslContextBuilder.forServer(cert.certificate(), cert.privateKey()) -- .sslProvider(provider) -- .trustManager(cert.certificate()) -- .clientAuth(ClientAuth.OPTIONAL); -- SslContext context = builder.build(); -- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); -- assertTrue(engine.getWantClientAuth()); -- assertFalse(engine.getNeedClientAuth()); -- engine.closeInbound(); -- engine.closeOutbound(); -- } -- -- private static void testServerContext(SslProvider provider) throws Exception { -- SelfSignedCertificate cert = new SelfSignedCertificate(); -- SslContextBuilder builder = SslContextBuilder.forServer(cert.key(), cert.cert()) -- .sslProvider(provider) -- .trustManager(cert.cert()) -- .clientAuth(ClientAuth.REQUIRE); -- SslContext context = builder.build(); -- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); -- assertFalse(engine.getWantClientAuth()); -- assertTrue(engine.getNeedClientAuth()); -- engine.closeInbound(); -- engine.closeOutbound(); +- @Override +- public void tryExpandApplicationBufferSize(int packetLengthDataOnly) { +- if (packetLengthDataOnly > MAX_PLAINTEXT_LENGTH && applicationBufferSize != MAX_RECORD_SIZE) { +- applicationBufferSize = MAX_RECORD_SIZE; +- } +- } - } -} -diff --git a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java b/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java deleted file mode 100644 -index aacdb69..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java +index bac027a3b4..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java +++ /dev/null -@@ -1,255 +0,0 @@ +@@ -1,286 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * @@ -8134,351 +8008,449 @@ index aacdb69..0000000 - */ -package io.netty.handler.ssl; - --import io.netty.bootstrap.Bootstrap; --import io.netty.bootstrap.ServerBootstrap; --import io.netty.channel.Channel; --import io.netty.channel.ChannelHandlerContext; --import io.netty.channel.ChannelInboundHandlerAdapter; --import io.netty.channel.ChannelInitializer; --import io.netty.channel.EventLoopGroup; --import io.netty.channel.nio.NioEventLoopGroup; --import io.netty.channel.socket.nio.NioServerSocketChannel; --import io.netty.channel.socket.nio.NioSocketChannel; --import io.netty.handler.logging.LogLevel; --import io.netty.handler.logging.LoggingHandler; --import io.netty.handler.ssl.util.InsecureTrustManagerFactory; --import io.netty.handler.ssl.util.SelfSignedCertificate; --import io.netty.handler.ssl.util.SimpleTrustManagerFactory; --import io.netty.util.ReferenceCountUtil; --import io.netty.util.concurrent.Promise; --import io.netty.util.internal.EmptyArrays; --import org.junit.Assume; --import org.junit.Test; --import org.junit.runner.RunWith; --import org.junit.runners.Parameterized; +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.internal.tcnative.CertificateCallback; +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +-import io.netty.internal.tcnative.SniHostNameMatcher; +-import io.netty.util.CharsetUtil; +-import io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.SuppressJava6Requirement; +-import io.netty.util.internal.SystemPropertyUtil; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; - --import javax.net.ssl.ManagerFactoryParameters; --import javax.net.ssl.SSLException; --import javax.net.ssl.TrustManager; --import javax.net.ssl.X509TrustManager; --import javax.security.auth.x500.X500Principal; --import java.io.File; -import java.security.KeyStore; --import java.security.cert.CRLReason; --import java.security.cert.CertPathValidatorException; --import java.security.cert.CertificateException; --import java.security.cert.CertificateExpiredException; --import java.security.cert.CertificateNotYetValidException; --import java.security.cert.CertificateRevokedException; --import java.security.cert.Extension; +-import java.security.PrivateKey; -import java.security.cert.X509Certificate; --import java.util.ArrayList; --import java.util.Collection; --import java.util.Collections; --import java.util.Date; --import java.util.List; --import java.util.Locale; +-import javax.net.ssl.KeyManagerFactory; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.TrustManagerFactory; +-import javax.net.ssl.X509ExtendedTrustManager; +-import javax.net.ssl.X509TrustManager; - +-import static io.netty.util.internal.ObjectUtil.checkNotNull; - --@RunWith(Parameterized.class) --public class SslErrorTest { +-/** +- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- * <p>Instances of this class must be {@link #release() released} or else native memory will leak! +- * +- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine} +- * which depends upon the instance of this class is released. Otherwise if any method of +- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. +- */ +-public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext { +- private static final InternalLogger logger = +- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class); +- private static final byte[] ID = {'n', 'e', 't', 't', 'y'}; +- private final OpenSslServerSessionContext sessionContext; - -- @Parameterized.Parameters(name = "{index}: serverProvider = {0}, clientProvider = {1}, exception = {2}") -- public static Collection<Object[]> data() { -- List<SslProvider> serverProviders = new ArrayList<SslProvider>(2); -- List<SslProvider> clientProviders = new ArrayList<SslProvider>(3); +- private static final boolean ENABLE_SESSION_TICKET = +- SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension", false); - -- if (OpenSsl.isAvailable()) { -- serverProviders.add(SslProvider.OPENSSL); -- serverProviders.add(SslProvider.OPENSSL_REFCNT); -- clientProviders.add(SslProvider.OPENSSL); -- clientProviders.add(SslProvider.OPENSSL_REFCNT); -- } -- // We not test with SslProvider.JDK on the server side as the JDK implementation currently just send the same -- // alert all the time, sigh..... -- clientProviders.add(SslProvider.JDK); -- -- List<CertificateException> exceptions = new ArrayList<CertificateException>(6); -- exceptions.add(new CertificateExpiredException()); -- exceptions.add(new CertificateNotYetValidException()); -- exceptions.add(new CertificateRevokedException( -- new Date(), CRLReason.AA_COMPROMISE, new X500Principal(""), -- Collections.<String, Extension>emptyMap())); -- -- // Also use wrapped exceptions as this is what the JDK implementation of X509TrustManagerFactory is doing. -- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.EXPIRED)); -- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.NOT_YET_VALID)); -- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.REVOKED)); -- -- List<Object[]> params = new ArrayList<Object[]>(); -- for (SslProvider serverProvider: serverProviders) { -- for (SslProvider clientProvider: clientProviders) { -- for (CertificateException exception: exceptions) { -- params.add(new Object[] { serverProvider, clientProvider, exception}); -- } +- ReferenceCountedOpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp, String keyStore) throws SSLException { +- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, +- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, +- enableOcsp, keyStore); +- } +- +- ReferenceCountedOpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp, String keyStore) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, +- clientAuth, protocols, startTls, enableOcsp, true); +- // Create a new SSL_CTX and configure it. +- boolean success = false; +- try { +- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, +- keyCertChain, key, keyPassword, keyManagerFactory, keyStore); +- if (ENABLE_SESSION_TICKET) { +- sessionContext.setTicketKeys(); +- } +- success = true; +- } finally { +- if (!success) { +- release(); - } - } -- return params; - } - -- private static CertificateException newCertificateException(CertPathValidatorException.Reason reason) { -- return new TestCertificateException( -- new CertPathValidatorException("x", null, null, -1, reason)); +- @Override +- public OpenSslServerSessionContext sessionContext() { +- return sessionContext; - } - -- private final SslProvider serverProvider; -- private final SslProvider clientProvider; -- private final CertificateException exception; +- static OpenSslServerSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx, +- OpenSslEngineMap engineMap, +- X509Certificate[] trustCertCollection, +- TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, +- String keyPassword, KeyManagerFactory keyManagerFactory, +- String keyStore) +- throws SSLException { +- OpenSslKeyMaterialProvider keyMaterialProvider = null; +- try { +- try { +- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); +- if (!OpenSsl.useKeyManagerFactory()) { +- if (keyManagerFactory != null) { +- throw new IllegalArgumentException( +- "KeyManagerFactory not supported"); +- } +- checkNotNull(keyCertChain, "keyCertChain"); - -- public SslErrorTest(SslProvider serverProvider, SslProvider clientProvider, CertificateException exception) { -- this.serverProvider = serverProvider; -- this.clientProvider = clientProvider; -- this.exception = exception; -- } +- setKeyMaterial(ctx, keyCertChain, key, keyPassword); +- } else { +- // javadocs state that keyManagerFactory has precedent over keyCertChain, and we must have a +- // keyManagerFactory for the server so build one if it is not specified. +- if (keyManagerFactory == null) { +- char[] keyPasswordChars = keyStorePassword(keyPassword); +- KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore); +- if (ks.aliases().hasMoreElements()) { +- keyManagerFactory = new OpenSslX509KeyManagerFactory(); +- } else { +- keyManagerFactory = new OpenSslCachingX509KeyManagerFactory( +- KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())); +- } +- keyManagerFactory.init(ks, keyPasswordChars); +- } +- keyMaterialProvider = providerFor(keyManagerFactory, keyPassword); - -- @Test(timeout = 30000) -- public void testCorrectAlert() throws Exception { -- // As this only works correctly at the moment when OpenSslEngine is used on the server-side there is -- // no need to run it if there is no openssl is available at all. -- Assume.assumeTrue(OpenSsl.isAvailable()); +- SSLContext.setCertificateCallback(ctx, new OpenSslServerCertificateCallback( +- engineMap, new OpenSslKeyMaterialManager(keyMaterialProvider))); +- } +- } catch (Exception e) { +- throw new SSLException("failed to set certificate and key", e); +- } +- try { +- if (trustCertCollection != null) { +- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore); +- } else if (trustManagerFactory == null) { +- // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works +- trustManagerFactory = TrustManagerFactory.getInstance( +- TrustManagerFactory.getDefaultAlgorithm()); +- trustManagerFactory.init((KeyStore) null); +- } - -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- final SslContext sslServerCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(serverProvider) -- .trustManager(new SimpleTrustManagerFactory() { -- @Override -- protected void engineInit(KeyStore keyStore) { } -- @Override -- protected void engineInit(ManagerFactoryParameters managerFactoryParameters) { } +- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); - -- @Override -- protected TrustManager[] engineGetTrustManagers() { -- return new TrustManager[] { new X509TrustManager() { +- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as +- // otherwise the context can never be collected. This is because the JNI code holds +- // a global reference to the callbacks. +- // +- // See https://github.com/netty/netty/issues/5372 - -- @Override -- public void checkClientTrusted(X509Certificate[] x509Certificates, String s) -- throws CertificateException { -- throw exception; -- } +- setVerifyCallback(ctx, engineMap, manager); - -- @Override -- public void checkServerTrusted(X509Certificate[] x509Certificates, String s) -- throws CertificateException { -- // NOOP +- X509Certificate[] issuers = manager.getAcceptedIssuers(); +- if (issuers != null && issuers.length > 0) { +- long bio = 0; +- try { +- bio = toBIO(ByteBufAllocator.DEFAULT, issuers); +- if (!SSLContext.setCACertificateBio(ctx, bio)) { +- throw new SSLException("unable to setup accepted issuers for trustmanager " + manager); +- } +- } finally { +- freeBio(bio); - } +- } - -- @Override -- public X509Certificate[] getAcceptedIssuers() { -- return EmptyArrays.EMPTY_X509_CERTIFICATES; -- } -- } }; +- if (PlatformDependent.javaVersion() >= 8) { +- // Only do on Java8+ as SNIMatcher is not supported in earlier releases. +- // IMPORTANT: The callbacks set for hostname matching must be static to prevent memory leak as +- // otherwise the context can never be collected. This is because the JNI code holds +- // a global reference to the matcher. +- SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engineMap)); +- } +- } catch (SSLException e) { +- throw e; +- } catch (Exception e) { +- throw new SSLException("unable to setup trustmanager", e); - } -- }).clientAuth(ClientAuth.REQUIRE).build(); - -- final SslContext sslClientCtx = SslContextBuilder.forClient() -- .trustManager(InsecureTrustManagerFactory.INSTANCE) -- .keyManager(new File(getClass().getResource("test.crt").getFile()), -- new File(getClass().getResource("test_unencrypted.pem").getFile())) -- .sslProvider(clientProvider).build(); +- OpenSslServerSessionContext sessionContext = new OpenSslServerSessionContext(thiz, keyMaterialProvider); +- sessionContext.setSessionIdContext(ID); - -- Channel serverChannel = null; -- Channel clientChannel = null; -- EventLoopGroup group = new NioEventLoopGroup(); -- try { -- serverChannel = new ServerBootstrap().group(group) -- .channel(NioServerSocketChannel.class) -- .handler(new LoggingHandler(LogLevel.INFO)) -- .childHandler(new ChannelInitializer<Channel>() { -- @Override -- protected void initChannel(Channel ch) throws Exception { -- ch.pipeline().addLast(sslServerCtx.newHandler(ch.alloc())); -- ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { -- -- @Override -- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { -- ctx.close(); -- } -- }); -- } -- }).bind(0).sync().channel(); -- -- final Promise<Void> promise = group.next().newPromise(); -- -- clientChannel = new Bootstrap().group(group) -- .channel(NioSocketChannel.class) -- .handler(new ChannelInitializer<Channel>() { -- @Override -- protected void initChannel(Channel ch) throws Exception { -- ch.pipeline().addLast(sslClientCtx.newHandler(ch.alloc())); -- ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { -- @Override -- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { -- // Unwrap as its wrapped by a DecoderException -- Throwable unwrappedCause = cause.getCause(); -- if (unwrappedCause instanceof SSLException) { -- if (exception instanceof TestCertificateException) { -- CertPathValidatorException.Reason reason = -- ((CertPathValidatorException) exception.getCause()).getReason(); -- if (reason == CertPathValidatorException.BasicReason.EXPIRED) { -- verifyException(unwrappedCause, "expired", promise); -- } else if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) { -- verifyException(unwrappedCause, "bad", promise); -- } else if (reason == CertPathValidatorException.BasicReason.REVOKED) { -- verifyException(unwrappedCause, "revoked", promise); -- } -- } else if (exception instanceof CertificateExpiredException) { -- verifyException(unwrappedCause, "expired", promise); -- } else if (exception instanceof CertificateNotYetValidException) { -- verifyException(unwrappedCause, "bad", promise); -- } else if (exception instanceof CertificateRevokedException) { -- verifyException(unwrappedCause, "revoked", promise); -- } -- } -- } -- }); -- } -- }).connect(serverChannel.localAddress()).syncUninterruptibly().channel(); -- // Block until we received the correct exception -- promise.syncUninterruptibly(); +- keyMaterialProvider = null; +- +- return sessionContext; - } finally { -- if (clientChannel != null) { -- clientChannel.close().syncUninterruptibly(); -- } -- if (serverChannel != null) { -- serverChannel.close().syncUninterruptibly(); +- if (keyMaterialProvider != null) { +- keyMaterialProvider.destroy(); - } -- group.shutdownGracefully(); -- -- ReferenceCountUtil.release(sslServerCtx); -- ReferenceCountUtil.release(sslClientCtx); - } - } - -- // Its a bit hacky to verify against the message that is part of the exception but there is no other way -- // at the moment as there are no different exceptions for the different alerts. -- private static void verifyException(Throwable cause, String messagePart, Promise<Void> promise) { -- String message = cause.getMessage(); -- if (message.toLowerCase(Locale.UK).contains(messagePart.toLowerCase(Locale.UK))) { -- promise.setSuccess(null); +- @SuppressJava6Requirement(reason = "Guarded by java version check") +- private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap, X509TrustManager manager) { +- // Use this to prevent an error when running on java < 7 +- if (useExtendedTrustManager(manager)) { +- SSLContext.setCertVerifyCallback(ctx, new ExtendedTrustManagerVerifyCallback( +- engineMap, (X509ExtendedTrustManager) manager)); - } else { -- promise.setFailure(new AssertionError("message not contains '" + messagePart + "': " + message)); +- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager)); - } - } - -- private static final class TestCertificateException extends CertificateException { +- private static final class OpenSslServerCertificateCallback implements CertificateCallback { +- private final OpenSslEngineMap engineMap; +- private final OpenSslKeyMaterialManager keyManagerHolder; - -- public TestCertificateException(Throwable cause) { -- super(cause); +- OpenSslServerCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) { +- this.engineMap = engineMap; +- this.keyManagerHolder = keyManagerHolder; - } -- } --} -diff --git a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java -index 5ef43de..52c4d22 100644 ---- a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java -+++ b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java -@@ -121,35 +121,6 @@ public class SslHandlerTest { - } - } - -- @Test -- public void testReleaseSslEngine() throws Exception { -- assumeTrue(OpenSsl.isAvailable()); - -- SelfSignedCertificate cert = new SelfSignedCertificate(); -- try { -- SslContext sslContext = SslContextBuilder.forServer(cert.certificate(), cert.privateKey()) -- .sslProvider(SslProvider.OPENSSL) -- .build(); +- @Override +- public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception { +- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); +- if (engine == null) { +- // Maybe null if destroyed in the meantime. +- return; +- } - try { -- SSLEngine sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT); -- EmbeddedChannel ch = new EmbeddedChannel(new SslHandler(sslEngine)); +- // For now we just ignore the asn1DerEncodedPrincipals as this is kind of inline with what the +- // OpenJDK SSLEngineImpl does. +- keyManagerHolder.setKeyMaterialServerSide(engine); +- } catch (Throwable cause) { +- logger.debug("Failed to set the server-side key material", cause); +- engine.initHandshakeException(cause); +- } +- } +- } - -- assertEquals(1, ((ReferenceCounted) sslContext).refCnt()); -- assertEquals(1, ((ReferenceCounted) sslEngine).refCnt()); +- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier { +- private final X509TrustManager manager; - -- assertTrue(ch.finishAndReleaseAll()); -- ch.close().syncUninterruptibly(); +- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) { +- super(engineMap); +- this.manager = manager; +- } - -- assertEquals(1, ((ReferenceCounted) sslContext).refCnt()); -- assertEquals(0, ((ReferenceCounted) sslEngine).refCnt()); -- } finally { -- ReferenceCountUtil.release(sslContext); -- } -- } finally { -- cert.delete(); +- @Override +- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) +- throws Exception { +- manager.checkClientTrusted(peerCerts, auth); - } - } - - private static final class TlsReadTest extends ChannelOutboundHandlerAdapter { - private volatile boolean readIssued; - -@@ -279,13 +250,6 @@ public class SslHandlerTest { - testAlertProducedAndSend(SslProvider.JDK); - } - -- @Test(timeout = 30000) -- public void testAlertProducedAndSendOpenSsl() throws Exception { -- assumeTrue(OpenSsl.isAvailable()); -- testAlertProducedAndSend(SslProvider.OPENSSL); -- testAlertProducedAndSend(SslProvider.OPENSSL_REFCNT); +- @SuppressJava6Requirement(reason = "Usage guarded by java version check") +- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier { +- private final X509ExtendedTrustManager manager; +- +- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) { +- super(engineMap); +- this.manager = OpenSslTlsv13X509ExtendedTrustManager.wrap(manager); +- } +- +- @Override +- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) +- throws Exception { +- manager.checkClientTrusted(peerCerts, auth, engine); +- } - } - - private void testAlertProducedAndSend(SslProvider provider) throws Exception { - SelfSignedCertificate ssc = new SelfSignedCertificate(); - -@@ -425,12 +389,6 @@ public class SslHandlerTest { - testCloseNotify(SslProvider.JDK, 5000, false); - } - -- @Test(timeout = 30000) -- public void testCloseNotifyReceivedOpenSsl() throws Exception { -- assumeTrue(OpenSsl.isAvailable()); -- testCloseNotify(SslProvider.OPENSSL, 5000, false); -- testCloseNotify(SslProvider.OPENSSL_REFCNT, 5000, false); +- private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher { +- private final OpenSslEngineMap engineMap; +- +- OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) { +- this.engineMap = engineMap; +- } +- +- @Override +- public boolean match(long ssl, String hostname) { +- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); +- if (engine != null) { +- // TODO: In the next release of tcnative we should pass the byte[] directly in and not use a String. +- return engine.checkSniHostnameMatch(hostname.getBytes(CharsetUtil.UTF_8)); +- } +- logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl); +- return false; +- } - } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java +index fef2702cfb..eb5110d145 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java ++++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java +@@ -120,11 +120,7 @@ public abstract class SslContext { + }
- @Test(timeout = 30000) - public void testCloseNotifyReceivedJdkTimeout() throws Exception { -@@ -438,24 +396,10 @@ public class SslHandlerTest { + private static SslProvider defaultProvider() { +- if (OpenSsl.isAvailable()) { +- return SslProvider.OPENSSL; +- } else { +- return SslProvider.JDK; +- } ++ return SslProvider.JDK; }
- @Test(timeout = 30000) -- public void testCloseNotifyReceivedOpenSslTimeout() throws Exception { -- assumeTrue(OpenSsl.isAvailable()); -- testCloseNotify(SslProvider.OPENSSL, 100, true); -- testCloseNotify(SslProvider.OPENSSL_REFCNT, 100, true); -- } + /** +@@ -466,18 +462,6 @@ public abstract class SslContext { + trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, + keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, + clientAuth, protocols, startTls, keyStoreType); +- case OPENSSL: +- verifyNullSslContextProvider(provider, sslContextProvider); +- return new OpenSslServerContext( +- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, +- clientAuth, protocols, startTls, enableOcsp, keyStoreType); +- case OPENSSL_REFCNT: +- verifyNullSslContextProvider(provider, sslContextProvider); +- return new ReferenceCountedOpenSslServerContext( +- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, +- clientAuth, protocols, startTls, enableOcsp, keyStoreType); + default: + throw new Error(provider.toString()); + } +@@ -822,18 +806,6 @@ public abstract class SslContext { + trustCert, trustManagerFactory, keyCertChain, key, keyPassword, + keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, + sessionTimeout, keyStoreType); +- case OPENSSL: +- verifyNullSslContextProvider(provider, sslContextProvider); +- return new OpenSslClientContext( +- trustCert, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, +- enableOcsp, keyStoreType); +- case OPENSSL_REFCNT: +- verifyNullSslContextProvider(provider, sslContextProvider); +- return new ReferenceCountedOpenSslClientContext( +- trustCert, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, +- enableOcsp, keyStoreType); + default: + throw new Error(provider.toString()); + } +diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +index 8e11bbf4cc..56be212b09 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java ++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +@@ -181,53 +181,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; + + private enum SslEngineType { +- TCNATIVE(true, COMPOSITE_CUMULATOR) { +- @Override +- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) +- throws SSLException { +- int nioBufferCount = in.nioBufferCount(); +- int writerIndex = out.writerIndex(); +- final SSLEngineResult result; +- if (nioBufferCount > 1) { +- /* +- * If {@link OpenSslEngine} is in use, +- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method +- * that accepts multiple {@link ByteBuffer}s without additional memory copies. +- */ +- ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine; +- try { +- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, +- out.writableBytes()); +- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer); +- } finally { +- handler.singleBuffer[0] = null; +- } +- } else { +- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len), +- toByteBuffer(out, writerIndex, out.writableBytes())); +- } +- out.writerIndex(writerIndex + result.bytesProduced()); +- return result; +- } - -- @Test(timeout = 30000) - public void testCloseNotifyNotWaitForResponseJdk() throws Exception { - testCloseNotify(SslProvider.JDK, 0, false); - } +- @Override +- ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator, +- int pendingBytes, int numComponents) { +- return allocator.directBuffer(((ReferenceCountedOpenSslEngine) handler.engine) +- .calculateMaxLengthForWrap(pendingBytes, numComponents)); +- } +- +- @Override +- int calculatePendingData(SslHandler handler, int guess) { +- int sslPending = ((ReferenceCountedOpenSslEngine) handler.engine).sslPending(); +- return sslPending > 0 ? sslPending : guess; +- } +- +- @Override +- boolean jdkCompatibilityMode(SSLEngine engine) { +- return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode; +- } +- }, + JDK(false, MERGE_CUMULATOR) { + @Override + SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) +@@ -280,7 +233,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + }; + + static SslEngineType forEngine(SSLEngine engine) { +- return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : JDK; ++ return JDK; + } + + SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) { +diff --git a/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java +index b1c710c841..44ef0456ed 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java ++++ b/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java +@@ -138,9 +138,6 @@ public abstract class SslMasterKeyHandler extends ChannelInboundHandlerAdapter { + "via reflection.", e); + } + accept(secretKey, sslSession); +- } else if (OpenSsl.isAvailable() && engine instanceof ReferenceCountedOpenSslEngine) { +- SecretKeySpec secretKey = ((ReferenceCountedOpenSslEngine) engine).masterKey(); +- accept(secretKey, sslSession); + } + } + } +diff --git a/handler/src/main/java/io/netty/handler/ssl/SslProvider.java b/handler/src/main/java/io/netty/handler/ssl/SslProvider.java +index e72cfed8d9..5263314e7c 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/SslProvider.java ++++ b/handler/src/main/java/io/netty/handler/ssl/SslProvider.java +@@ -26,16 +26,7 @@ public enum SslProvider { + /** + * JDK's default implementation. + */ +- JDK, +- /** +- * OpenSSL-based implementation. +- */ +- OPENSSL, +- /** +- * OpenSSL-based implementation which does not have finalizers and instead implements {@link ReferenceCounted}. +- */ +- @UnstableApi +- OPENSSL_REFCNT; ++ JDK;
-- @Test(timeout = 30000) -- public void testCloseNotifyNotWaitForResponseOpenSsl() throws Exception { -- assumeTrue(OpenSsl.isAvailable()); -- testCloseNotify(SslProvider.OPENSSL, 0, false); -- testCloseNotify(SslProvider.OPENSSL_REFCNT, 0, false); -- } -- - private static void testCloseNotify(SslProvider provider, final long closeNotifyReadTimeout, final boolean timeout) - throws Exception { - SelfSignedCertificate ssc = new SelfSignedCertificate(); -@@ -720,7 +664,7 @@ public class SslHandlerTest { + /** + * Returns {@code true} if the specified {@link SslProvider} supports +@@ -45,9 +36,6 @@ public enum SslProvider { switch (provider) { - case OPENSSL: - case OPENSSL_REFCNT: -- return OpenSsl.isAvailable(); -+ return false; + case JDK: + return JdkAlpnApplicationProtocolNegotiator.isAlpnSupported(); +- case OPENSSL: +- case OPENSSL_REFCNT: +- return OpenSsl.isAlpnSupported(); default: - return true; + throw new Error("Unknown SslProvider: " + provider); } -diff --git a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java b/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java +diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java deleted file mode 100644 -index 4aecc74..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java +index c45c50e1e3..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java +++ /dev/null -@@ -1,501 +0,0 @@ +@@ -1,61 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * @@ -8494,492 +8466,102 @@ index 4aecc74..0000000 - * License for the specific language governing permissions and limitations - * under the License. - */ -- -package io.netty.handler.ssl.ocsp; - --import io.netty.bootstrap.Bootstrap; --import io.netty.bootstrap.ServerBootstrap; --import io.netty.buffer.ByteBufAllocator; --import io.netty.buffer.Unpooled; --import io.netty.channel.Channel; --import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; --import io.netty.channel.ChannelInitializer; --import io.netty.channel.ChannelPipeline; --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.OpenSsl; +-import io.netty.handler.ssl.ReferenceCountedOpenSslContext; -import io.netty.handler.ssl.ReferenceCountedOpenSslEngine; --import io.netty.handler.ssl.SslContext; --import io.netty.handler.ssl.SslContextBuilder; --import io.netty.handler.ssl.SslHandler; --import io.netty.handler.ssl.SslProvider; --import io.netty.handler.ssl.util.InsecureTrustManagerFactory; --import io.netty.handler.ssl.util.SelfSignedCertificate; --import io.netty.util.CharsetUtil; --import io.netty.util.ReferenceCountUtil; -- --import java.net.SocketAddress; --import java.util.concurrent.CountDownLatch; --import java.util.concurrent.TimeUnit; --import java.util.concurrent.TimeoutException; --import java.util.concurrent.atomic.AtomicReference; +-import io.netty.handler.ssl.SslHandshakeCompletionEvent; +-import io.netty.util.internal.ObjectUtil; +-import io.netty.util.internal.UnstableApi; - -import javax.net.ssl.SSLHandshakeException; - --import org.junit.BeforeClass; --import org.junit.Test; -- --import static org.junit.Assert.assertArrayEquals; --import static org.junit.Assert.assertNotNull; --import static org.junit.Assert.assertNotSame; --import static org.junit.Assert.assertNull; --import static org.junit.Assert.assertSame; --import static org.junit.Assert.assertTrue; --import static org.junit.Assume.assumeTrue; -- --public class OcspTest { -- -- @BeforeClass -- public static void checkOcspSupported() { -- assumeTrue(OpenSsl.isOcspSupported()); -- } -- -- @Test(expected = IllegalArgumentException.class) -- public void testJdkClientEnableOcsp() throws Exception { -- SslContextBuilder.forClient() -- .sslProvider(SslProvider.JDK) -- .enableOcsp(true) -- .build(); -- } -- -- @Test(expected = IllegalArgumentException.class) -- public void testJdkServerEnableOcsp() throws Exception { -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- try { -- SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(SslProvider.JDK) -- .enableOcsp(true) -- .build(); -- } finally { -- ssc.delete(); -- } -- } -- -- @Test(expected = IllegalStateException.class) -- public void testClientOcspNotEnabledOpenSsl() throws Exception { -- testClientOcspNotEnabled(SslProvider.OPENSSL); -- } -- -- @Test(expected = IllegalStateException.class) -- public void testClientOcspNotEnabledOpenSslRefCnt() throws Exception { -- testClientOcspNotEnabled(SslProvider.OPENSSL_REFCNT); -- } -- -- private void testClientOcspNotEnabled(SslProvider sslProvider) throws Exception { -- SslContext context = SslContextBuilder.forClient() -- .sslProvider(sslProvider) -- .build(); -- try { -- SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT); -- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); -- try { -- engine.getOcspResponse(); -- } finally { -- engine.release(); -- } -- } finally { -- ReferenceCountUtil.release(context); -- } -- } -- -- @Test(expected = IllegalStateException.class) -- public void testServerOcspNotEnabledOpenSsl() throws Exception { -- testServerOcspNotEnabled(SslProvider.OPENSSL); -- } -- -- @Test(expected = IllegalStateException.class) -- public void testServerOcspNotEnabledOpenSslRefCnt() throws Exception { -- testServerOcspNotEnabled(SslProvider.OPENSSL_REFCNT); -- } -- -- private void testServerOcspNotEnabled(SslProvider sslProvider) throws Exception { -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- try { -- SslContext context = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslProvider) -- .build(); -- try { -- SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT); -- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); -- try { -- engine.setOcspResponse(new byte[] { 1, 2, 3 }); -- } finally { -- engine.release(); -- } -- } finally { -- ReferenceCountUtil.release(context); -- } -- } finally { -- ssc.delete(); -- } -- } -- -- @Test(timeout = 10000L) -- public void testClientAcceptingOcspStapleOpenSsl() throws Exception { -- testClientAcceptingOcspStaple(SslProvider.OPENSSL); -- } -- -- @Test(timeout = 10000L) -- public void testClientAcceptingOcspStapleOpenSslRefCnt() throws Exception { -- testClientAcceptingOcspStaple(SslProvider.OPENSSL_REFCNT); -- } -- -- /** -- * The Server provides an OCSP staple and the Client accepts it. -- */ -- private void testClientAcceptingOcspStaple(SslProvider sslProvider) throws Exception { -- final CountDownLatch latch = new CountDownLatch(1); -- ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter() { -- @Override -- public void channelActive(ChannelHandlerContext ctx) throws Exception { -- ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes())); -- ctx.fireChannelActive(); -- } -- }; -- -- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { -- @Override -- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { -- try { -- ReferenceCountUtil.release(msg); -- } finally { -- latch.countDown(); -- } -- } -- }; -- -- byte[] response = newOcspResponse(); -- TestClientOcspContext callback = new TestClientOcspContext(true); -- -- handshake(sslProvider, latch, serverHandler, response, clientHandler, callback); -- -- byte[] actual = callback.response(); -- -- assertNotNull(actual); -- assertNotSame(response, actual); -- assertArrayEquals(response, actual); -- } -- -- @Test(timeout = 10000L) -- public void testClientRejectingOcspStapleOpenSsl() throws Exception { -- testClientRejectingOcspStaple(SslProvider.OPENSSL); -- } -- -- @Test(timeout = 10000L) -- public void testClientRejectingOcspStapleOpenSslRefCnt() throws Exception { -- testClientRejectingOcspStaple(SslProvider.OPENSSL_REFCNT); -- } -- -- /** -- * The Server provides an OCSP staple and the Client rejects it. -- */ -- private void testClientRejectingOcspStaple(SslProvider sslProvider) throws Exception { -- final AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>(); -- final CountDownLatch latch = new CountDownLatch(1); -- -- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { -- @Override -- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { -- try { -- causeRef.set(cause); -- } finally { -- latch.countDown(); -- } -- } -- }; -- -- byte[] response = newOcspResponse(); -- TestClientOcspContext callback = new TestClientOcspContext(false); -- -- handshake(sslProvider, latch, null, response, clientHandler, callback); -- -- byte[] actual = callback.response(); -- -- assertNotNull(actual); -- assertNotSame(response, actual); -- assertArrayEquals(response, actual); -- -- Throwable cause = causeRef.get(); -- assertTrue("" + cause, cause instanceof SSLHandshakeException); -- } -- -- @Test(timeout = 10000L) -- public void testServerHasNoStapleOpenSsl() throws Exception { -- testServerHasNoStaple(SslProvider.OPENSSL); -- } -- -- @Test(timeout = 10000L) -- public void testServerHasNoStapleOpenSslRefCnt() throws Exception { -- testServerHasNoStaple(SslProvider.OPENSSL_REFCNT); -- } -- -- /** -- * The server has OCSP stapling enabled but doesn't provide a staple. -- */ -- private void testServerHasNoStaple(SslProvider sslProvider) throws Exception { -- final CountDownLatch latch = new CountDownLatch(1); -- ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter() { -- @Override -- public void channelActive(ChannelHandlerContext ctx) throws Exception { -- ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes())); -- ctx.fireChannelActive(); -- } -- }; -- -- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { -- @Override -- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { -- try { -- ReferenceCountUtil.release(msg); -- } finally { -- latch.countDown(); -- } -- } -- }; -- -- byte[] response = null; -- TestClientOcspContext callback = new TestClientOcspContext(true); -- -- handshake(sslProvider, latch, serverHandler, response, clientHandler, callback); -- -- byte[] actual = callback.response(); -- -- assertNull(response); -- assertNull(actual); -- } +-/** +- * A handler for SSL clients to handle and act upon stapled OCSP responses. +- * +- * @see ReferenceCountedOpenSslContext#enableOcsp() +- * @see ReferenceCountedOpenSslEngine#getOcspResponse() +- */ +-@UnstableApi +-public abstract class OcspClientHandler extends ChannelInboundHandlerAdapter { - -- @Test(timeout = 10000L) -- public void testClientExceptionOpenSsl() throws Exception { -- testClientException(SslProvider.OPENSSL); -- } +- private final ReferenceCountedOpenSslEngine engine; - -- @Test(timeout = 10000L) -- public void testClientExceptionOpenSslRefCnt() throws Exception { -- testClientException(SslProvider.OPENSSL_REFCNT); +- protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) { +- this.engine = ObjectUtil.checkNotNull(engine, "engine"); - } - - /** -- * Testing what happens if the {@link OcspClientCallback} throws an {@link Exception}. -- * -- * The exception should bubble up on the client side and the connection should get closed. +- * @see ReferenceCountedOpenSslEngine#getOcspResponse() - */ -- private void testClientException(SslProvider sslProvider) throws Exception { -- final AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>(); -- final CountDownLatch latch = new CountDownLatch(1); -- -- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { -- @Override -- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { -- try { -- causeRef.set(cause); -- } finally { -- latch.countDown(); -- } -- } -- }; -- -- final OcspTestException clientException = new OcspTestException("testClientException"); -- byte[] response = newOcspResponse(); -- OcspClientCallback callback = new OcspClientCallback() { -- @Override -- public boolean verify(byte[] response) throws Exception { -- throw clientException; -- } -- }; -- -- handshake(sslProvider, latch, null, response, clientHandler, callback); -- -- assertSame(clientException, causeRef.get()); -- } -- -- private static void handshake(SslProvider sslProvider, CountDownLatch latch, ChannelHandler serverHandler, -- byte[] response, ChannelHandler clientHandler, OcspClientCallback callback) throws Exception { -- -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- try { -- SslContext serverSslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) -- .sslProvider(sslProvider) -- .enableOcsp(true) -- .build(); -- -- try { -- SslContext clientSslContext = SslContextBuilder.forClient() -- .sslProvider(sslProvider) -- .enableOcsp(true) -- .trustManager(InsecureTrustManagerFactory.INSTANCE) -- .build(); -- -- try { -- EventLoopGroup group = new DefaultEventLoopGroup(); -- try { -- LocalAddress address = new LocalAddress("handshake-" + Math.random()); -- Channel server = newServer(group, address, serverSslContext, response, serverHandler); -- Channel client = newClient(group, address, clientSslContext, callback, clientHandler); -- try { -- assertTrue("Something went wrong.", latch.await(10L, TimeUnit.SECONDS)); -- } finally { -- client.close().syncUninterruptibly(); -- server.close().syncUninterruptibly(); -- } -- } finally { -- group.shutdownGracefully(1L, 1L, TimeUnit.SECONDS); -- } -- } finally { -- ReferenceCountUtil.release(clientSslContext); -- } -- } finally { -- ReferenceCountUtil.release(serverSslContext); -- } -- } finally { -- ssc.delete(); -- } -- } -- -- private static Channel newServer(EventLoopGroup group, SocketAddress address, -- SslContext context, byte[] response, ChannelHandler handler) { -- -- ServerBootstrap bootstrap = new ServerBootstrap() -- .channel(LocalServerChannel.class) -- .group(group) -- .childHandler(newServerHandler(context, response, handler)); -- -- return bootstrap.bind(address) -- .syncUninterruptibly() -- .channel(); -- } -- -- private static Channel newClient(EventLoopGroup group, SocketAddress address, -- SslContext context, OcspClientCallback callback, ChannelHandler handler) { -- -- Bootstrap bootstrap = new Bootstrap() -- .channel(LocalChannel.class) -- .group(group) -- .handler(newClientHandler(context, callback, handler)); -- -- return bootstrap.connect(address) -- .syncUninterruptibly() -- .channel(); -- } -- -- private static ChannelHandler newServerHandler(final SslContext context, -- final byte[] response, final ChannelHandler handler) { -- return new ChannelInitializer<Channel>() { -- @Override -- protected void initChannel(Channel ch) throws Exception { -- ChannelPipeline pipeline = ch.pipeline(); -- SslHandler sslHandler = context.newHandler(ch.alloc()); -- -- if (response != null) { -- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); -- engine.setOcspResponse(response); -- } -- -- pipeline.addLast(sslHandler); -- -- if (handler != null) { -- pipeline.addLast(handler); -- } -- } -- }; -- } -- -- private static ChannelHandler newClientHandler(final SslContext context, -- final OcspClientCallback callback, final ChannelHandler handler) { -- return new ChannelInitializer<Channel>() { -- @Override -- protected void initChannel(Channel ch) throws Exception { -- ChannelPipeline pipeline = ch.pipeline(); -- -- SslHandler sslHandler = context.newHandler(ch.alloc()); -- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); +- protected abstract boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception; - -- pipeline.addLast(sslHandler); -- pipeline.addLast(new OcspClientCallbackHandler(engine, callback)); +- @Override +- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { +- if (evt instanceof SslHandshakeCompletionEvent) { +- ctx.pipeline().remove(this); - -- if (handler != null) { -- pipeline.addLast(handler); -- } +- SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt; +- if (event.isSuccess() && !verify(ctx, engine)) { +- throw new SSLHandshakeException("Bad OCSP response"); - } -- }; -- } -- -- private static byte[] newOcspResponse() { -- // Assume we got the OCSP staple from somewhere. Using a bogus byte[] -- // in the test because getting a true staple from the CA is quite involved. -- // It requires HttpCodec and Bouncycastle and the test may be very unreliable -- // because the OCSP responder servers are basically being DDoS'd by the -- // Internet. -- -- return "I am a bogus OCSP staple. OpenSSL does not care about the format of the byte[]!" -- .getBytes(CharsetUtil.US_ASCII); -- } -- -- private interface OcspClientCallback { -- boolean verify(byte[] staple) throws Exception; -- } -- -- private static final class TestClientOcspContext implements OcspClientCallback { -- -- private final CountDownLatch latch = new CountDownLatch(1); -- private final boolean valid; -- -- private volatile byte[] response; -- -- public TestClientOcspContext(boolean valid) { -- this.valid = valid; -- } -- -- public byte[] response() throws InterruptedException, TimeoutException { -- assertTrue(latch.await(10L, TimeUnit.SECONDS)); -- return response; -- } -- -- @Override -- public boolean verify(byte[] response) throws Exception { -- this.response = response; -- latch.countDown(); -- -- return valid; -- } -- } -- -- private static final class OcspClientCallbackHandler extends OcspClientHandler { -- -- private final OcspClientCallback callback; -- -- public OcspClientCallbackHandler(ReferenceCountedOpenSslEngine engine, OcspClientCallback callback) { -- super(engine); -- this.callback = callback; -- } -- -- @Override -- protected boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception { -- byte[] response = engine.getOcspResponse(); -- return callback.verify(response); - } -- } - -- private static final class OcspTestException extends IllegalStateException { -- public OcspTestException(String message) { -- super(message); -- } +- ctx.fireUserEventTriggered(evt); - } -} +diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java +deleted file mode 100644 +index 2883ff48cf..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java ++++ /dev/null +@@ -1,23 +0,0 @@ +-/* +- * Copyright 2017 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. +- */ +- +-/** +- * <a href="https://en.wikipedia.org/wiki/OCSP_stapling">OCSP stapling</a>, +- * formally known as the TLS Certificate Status Request extension, is an +- * alternative approach to the Online Certificate Status Protocol (OCSP) +- * for checking the revocation status of X.509 digital certificates. +- */ +-package io.netty.handler.ssl.ocsp; +diff --git a/pom.xml b/pom.xml +index bedd6d6903..75a2da328a 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -465,16 +465,6 @@ + <version>3.0.0-alpha-5</version> + </dependency> + +- <!-- Our own Tomcat Native fork - completely optional, used for accelerating SSL with OpenSSL. --> +- <dependency> +- <groupId>${project.groupId}</groupId> +- <artifactId>${tcnative.artifactId}</artifactId> +- <version>${tcnative.version}</version> +- <classifier>${tcnative.classifier}</classifier> +- <scope>compile</scope> +- <optional>true</optional> +- </dependency> +- + <!-- + Bouncy Castle - completely optional, only needed when: + - you generate a temporary self-signed certificate using SelfSignedCertificate, and -- -2.9.4 +2.26.2
diff --git a/0005-Remove-optional-dep-log4j.patch b/0005-Remove-optional-dep-log4j.patch new file mode 100644 index 0000000..9dcd6e7 --- /dev/null +++ b/0005-Remove-optional-dep-log4j.patch @@ -0,0 +1,911 @@ +From 1762f36e7ed797747ae692ea2c78001d45b35449 Mon Sep 17 00:00:00 2001 +From: Mat Booth mat.booth@redhat.com +Date: Mon, 7 Sep 2020 14:29:44 +0100 +Subject: [PATCH 5/5] Remove optional dep log4j + +--- + common/pom.xml | 15 - + .../logging/InternalLoggerFactory.java | 14 +- + .../util/internal/logging/Log4J2Logger.java | 143 ----- + .../internal/logging/Log4J2LoggerFactory.java | 35 - + .../util/internal/logging/Log4JLogger.java | 597 ------------------ + .../internal/logging/Log4JLoggerFactory.java | 40 -- + 6 files changed, 2 insertions(+), 842 deletions(-) + delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java + delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java + delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java + delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java + +diff --git a/common/pom.xml b/common/pom.xml +index abc73161eb..60693fb81a 100644 +--- a/common/pom.xml ++++ b/common/pom.xml +@@ -63,21 +63,6 @@ + <artifactId>commons-logging</artifactId> + <optional>true</optional> + </dependency> +- <dependency> +- <groupId>log4j</groupId> +- <artifactId>log4j</artifactId> +- <optional>true</optional> +- </dependency> +- <dependency> +- <groupId>org.apache.logging.log4j</groupId> +- <artifactId>log4j-api</artifactId> +- <optional>true</optional> +- </dependency> +- <dependency> +- <groupId>org.apache.logging.log4j</groupId> +- <artifactId>log4j-core</artifactId> +- <scope>test</scope> +- </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> +diff --git a/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java b/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java +index 508f571820..98eb4e4f4d 100644 +--- a/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java ++++ b/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java +@@ -44,18 +44,8 @@ public abstract class InternalLoggerFactory { + f = new Slf4JLoggerFactory(true); + f.newInstance(name).debug("Using SLF4J as the default logging framework"); + } catch (Throwable ignore1) { +- try { +- f = Log4J2LoggerFactory.INSTANCE; +- f.newInstance(name).debug("Using Log4J2 as the default logging framework"); +- } catch (Throwable ignore2) { +- try { +- f = Log4JLoggerFactory.INSTANCE; +- f.newInstance(name).debug("Using Log4J as the default logging framework"); +- } catch (Throwable ignore3) { +- f = JdkLoggerFactory.INSTANCE; +- f.newInstance(name).debug("Using java.util.logging as the default logging framework"); +- } +- } ++ f = JdkLoggerFactory.INSTANCE; ++ f.newInstance(name).debug("Using java.util.logging as the default logging framework"); + } + return f; + } +diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java b/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java +deleted file mode 100644 +index 5c3593f203..0000000000 +--- a/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java ++++ /dev/null +@@ -1,143 +0,0 @@ +-/* +- * 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.util.internal.logging; +- +- +-import org.apache.logging.log4j.Level; +-import org.apache.logging.log4j.Logger; +-import org.apache.logging.log4j.spi.ExtendedLogger; +-import org.apache.logging.log4j.spi.ExtendedLoggerWrapper; +- +-import java.security.AccessController; +-import java.security.PrivilegedAction; +- +-import static io.netty.util.internal.logging.AbstractInternalLogger.EXCEPTION_MESSAGE; +- +-class Log4J2Logger extends ExtendedLoggerWrapper implements InternalLogger { +- +- private static final long serialVersionUID = 5485418394879791397L; +- private static final boolean VARARGS_ONLY; +- +- static { +- // Older Log4J2 versions have only log methods that takes the format + varargs. So we should not use +- // Log4J2 if the version is too old. +- // See https://github.com/netty/netty/issues/8217 +- VARARGS_ONLY = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { +- @Override +- public Boolean run() { +- try { +- Logger.class.getMethod("debug", String.class, Object.class); +- return false; +- } catch (NoSuchMethodException ignore) { +- // Log4J2 version too old. +- return true; +- } catch (SecurityException ignore) { +- // We could not detect the version so we will use Log4J2 if its on the classpath. +- return false; +- } +- } +- }); +- } +- +- Log4J2Logger(Logger logger) { +- super((ExtendedLogger) logger, logger.getName(), logger.getMessageFactory()); +- if (VARARGS_ONLY) { +- throw new UnsupportedOperationException("Log4J2 version mismatch"); +- } +- } +- +- @Override +- public String name() { +- return getName(); +- } +- +- @Override +- public void trace(Throwable t) { +- log(Level.TRACE, EXCEPTION_MESSAGE, t); +- } +- +- @Override +- public void debug(Throwable t) { +- log(Level.DEBUG, EXCEPTION_MESSAGE, t); +- } +- +- @Override +- public void info(Throwable t) { +- log(Level.INFO, EXCEPTION_MESSAGE, t); +- } +- +- @Override +- public void warn(Throwable t) { +- log(Level.WARN, EXCEPTION_MESSAGE, t); +- } +- +- @Override +- public void error(Throwable t) { +- log(Level.ERROR, EXCEPTION_MESSAGE, t); +- } +- +- @Override +- public boolean isEnabled(InternalLogLevel level) { +- return isEnabled(toLevel(level)); +- } +- +- @Override +- public void log(InternalLogLevel level, String msg) { +- log(toLevel(level), msg); +- } +- +- @Override +- public void log(InternalLogLevel level, String format, Object arg) { +- log(toLevel(level), format, arg); +- } +- +- @Override +- public void log(InternalLogLevel level, String format, Object argA, Object argB) { +- log(toLevel(level), format, argA, argB); +- } +- +- @Override +- public void log(InternalLogLevel level, String format, Object... arguments) { +- log(toLevel(level), format, arguments); +- } +- +- @Override +- public void log(InternalLogLevel level, String msg, Throwable t) { +- log(toLevel(level), msg, t); +- } +- +- @Override +- public void log(InternalLogLevel level, Throwable t) { +- log(toLevel(level), EXCEPTION_MESSAGE, t); +- } +- +- private static Level toLevel(InternalLogLevel level) { +- switch (level) { +- case INFO: +- return Level.INFO; +- case DEBUG: +- return Level.DEBUG; +- case WARN: +- return Level.WARN; +- case ERROR: +- return Level.ERROR; +- case TRACE: +- return Level.TRACE; +- default: +- throw new Error(); +- } +- } +-} +diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java b/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java +deleted file mode 100644 +index 8b895fbc07..0000000000 +--- a/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java ++++ /dev/null +@@ -1,35 +0,0 @@ +-/* +- * 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.util.internal.logging; +- +-import org.apache.logging.log4j.LogManager; +- +-public final class Log4J2LoggerFactory extends InternalLoggerFactory { +- +- public static final InternalLoggerFactory INSTANCE = new Log4J2LoggerFactory(); +- +- /** +- * @deprecated Use {@link #INSTANCE} instead. +- */ +- @Deprecated +- public Log4J2LoggerFactory() { +- } +- +- @Override +- public InternalLogger newInstance(String name) { +- return new Log4J2Logger(LogManager.getLogger(name)); +- } +-} +diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java b/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java +deleted file mode 100644 +index 27b9130a08..0000000000 +--- a/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java ++++ /dev/null +@@ -1,597 +0,0 @@ +-/* +- * Copyright 2012 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. +- */ +-/** +- * Copyright (c) 2004-2011 QOS.ch +- * All rights reserved. +- * +- * Permission is hereby granted, free of charge, to any person obtaining +- * a copy of this software and associated documentation files (the +- * "Software"), to deal in the Software without restriction, including +- * without limitation the rights to use, copy, modify, merge, publish, +- * distribute, sublicense, and/or sell copies of the Software, and to +- * permit persons to whom the Software is furnished to do so, subject to +- * the following conditions: +- * +- * The above copyright notice and this permission notice shall be +- * included in all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +- * +- */ +-package io.netty.util.internal.logging; +- +-import org.apache.log4j.Level; +-import org.apache.log4j.Logger; +- +-/** +- * <a href="http://logging.apache.org/log4j/1.2/index.html">Apache Log4J</a> +- * logger. +- */ +-class Log4JLogger extends AbstractInternalLogger { +- +- private static final long serialVersionUID = 2851357342488183058L; +- +- final transient Logger logger; +- +- /** +- * Following the pattern discussed in pages 162 through 168 of "The complete +- * log4j manual". +- */ +- static final String FQCN = Log4JLogger.class.getName(); +- +- // Does the log4j version in use recognize the TRACE level? +- // The trace level was introduced in log4j 1.2.12. +- final boolean traceCapable; +- +- Log4JLogger(Logger logger) { +- super(logger.getName()); +- this.logger = logger; +- traceCapable = isTraceCapable(); +- } +- +- private boolean isTraceCapable() { +- try { +- logger.isTraceEnabled(); +- return true; +- } catch (NoSuchMethodError ignored) { +- return false; +- } +- } +- +- /** +- * Is this logger instance enabled for the TRACE level? +- * +- * @return True if this Logger is enabled for level TRACE, false otherwise. +- */ +- @Override +- public boolean isTraceEnabled() { +- if (traceCapable) { +- return logger.isTraceEnabled(); +- } else { +- return logger.isDebugEnabled(); +- } +- } +- +- /** +- * Log a message object at level TRACE. +- * +- * @param msg +- * - the message object to be logged +- */ +- @Override +- public void trace(String msg) { +- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, null); +- } +- +- /** +- * Log a message at level TRACE according to the specified format and +- * argument. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for level TRACE. +- * </p> +- * +- * @param format +- * the format string +- * @param arg +- * the argument +- */ +- @Override +- public void trace(String format, Object arg) { +- if (isTraceEnabled()) { +- FormattingTuple ft = MessageFormatter.format(format, arg); +- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft +- .getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log a message at level TRACE according to the specified format and +- * arguments. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the TRACE level. +- * </p> +- * +- * @param format +- * the format string +- * @param argA +- * the first argument +- * @param argB +- * the second argument +- */ +- @Override +- public void trace(String format, Object argA, Object argB) { +- if (isTraceEnabled()) { +- FormattingTuple ft = MessageFormatter.format(format, argA, argB); +- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft +- .getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log a message at level TRACE according to the specified format and +- * arguments. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the TRACE level. +- * </p> +- * +- * @param format +- * the format string +- * @param arguments +- * an array of arguments +- */ +- @Override +- public void trace(String format, Object... arguments) { +- if (isTraceEnabled()) { +- FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); +- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft +- .getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log an exception (throwable) at level TRACE with an accompanying message. +- * +- * @param msg +- * the message accompanying the exception +- * @param t +- * the exception (throwable) to log +- */ +- @Override +- public void trace(String msg, Throwable t) { +- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, t); +- } +- +- /** +- * Is this logger instance enabled for the DEBUG level? +- * +- * @return True if this Logger is enabled for level DEBUG, false otherwise. +- */ +- @Override +- public boolean isDebugEnabled() { +- return logger.isDebugEnabled(); +- } +- +- /** +- * Log a message object at level DEBUG. +- * +- * @param msg +- * - the message object to be logged +- */ +- @Override +- public void debug(String msg) { +- logger.log(FQCN, Level.DEBUG, msg, null); +- } +- +- /** +- * Log a message at level DEBUG according to the specified format and +- * argument. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for level DEBUG. +- * </p> +- * +- * @param format +- * the format string +- * @param arg +- * the argument +- */ +- @Override +- public void debug(String format, Object arg) { +- if (logger.isDebugEnabled()) { +- FormattingTuple ft = MessageFormatter.format(format, arg); +- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log a message at level DEBUG according to the specified format and +- * arguments. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the DEBUG level. +- * </p> +- * +- * @param format +- * the format string +- * @param argA +- * the first argument +- * @param argB +- * the second argument +- */ +- @Override +- public void debug(String format, Object argA, Object argB) { +- if (logger.isDebugEnabled()) { +- FormattingTuple ft = MessageFormatter.format(format, argA, argB); +- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log a message at level DEBUG according to the specified format and +- * arguments. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the DEBUG level. +- * </p> +- * +- * @param format +- * the format string +- * @param arguments an array of arguments +- */ +- @Override +- public void debug(String format, Object... arguments) { +- if (logger.isDebugEnabled()) { +- FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); +- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log an exception (throwable) at level DEBUG with an accompanying message. +- * +- * @param msg +- * the message accompanying the exception +- * @param t +- * the exception (throwable) to log +- */ +- @Override +- public void debug(String msg, Throwable t) { +- logger.log(FQCN, Level.DEBUG, msg, t); +- } +- +- /** +- * Is this logger instance enabled for the INFO level? +- * +- * @return True if this Logger is enabled for the INFO level, false otherwise. +- */ +- @Override +- public boolean isInfoEnabled() { +- return logger.isInfoEnabled(); +- } +- +- /** +- * Log a message object at the INFO level. +- * +- * @param msg +- * - the message object to be logged +- */ +- @Override +- public void info(String msg) { +- logger.log(FQCN, Level.INFO, msg, null); +- } +- +- /** +- * Log a message at level INFO according to the specified format and argument. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the INFO level. +- * </p> +- * +- * @param format +- * the format string +- * @param arg +- * the argument +- */ +- @Override +- public void info(String format, Object arg) { +- if (logger.isInfoEnabled()) { +- FormattingTuple ft = MessageFormatter.format(format, arg); +- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log a message at the INFO level according to the specified format and +- * arguments. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the INFO level. +- * </p> +- * +- * @param format +- * the format string +- * @param argA +- * the first argument +- * @param argB +- * the second argument +- */ +- @Override +- public void info(String format, Object argA, Object argB) { +- if (logger.isInfoEnabled()) { +- FormattingTuple ft = MessageFormatter.format(format, argA, argB); +- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log a message at level INFO according to the specified format and +- * arguments. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the INFO level. +- * </p> +- * +- * @param format +- * the format string +- * @param argArray +- * an array of arguments +- */ +- @Override +- public void info(String format, Object... argArray) { +- if (logger.isInfoEnabled()) { +- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); +- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log an exception (throwable) at the INFO level with an accompanying +- * message. +- * +- * @param msg +- * the message accompanying the exception +- * @param t +- * the exception (throwable) to log +- */ +- @Override +- public void info(String msg, Throwable t) { +- logger.log(FQCN, Level.INFO, msg, t); +- } +- +- /** +- * Is this logger instance enabled for the WARN level? +- * +- * @return True if this Logger is enabled for the WARN level, false otherwise. +- */ +- @Override +- public boolean isWarnEnabled() { +- return logger.isEnabledFor(Level.WARN); +- } +- +- /** +- * Log a message object at the WARN level. +- * +- * @param msg +- * - the message object to be logged +- */ +- @Override +- public void warn(String msg) { +- logger.log(FQCN, Level.WARN, msg, null); +- } +- +- /** +- * Log a message at the WARN level according to the specified format and +- * argument. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the WARN level. +- * </p> +- * +- * @param format +- * the format string +- * @param arg +- * the argument +- */ +- @Override +- public void warn(String format, Object arg) { +- if (logger.isEnabledFor(Level.WARN)) { +- FormattingTuple ft = MessageFormatter.format(format, arg); +- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log a message at the WARN level according to the specified format and +- * arguments. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the WARN level. +- * </p> +- * +- * @param format +- * the format string +- * @param argA +- * the first argument +- * @param argB +- * the second argument +- */ +- @Override +- public void warn(String format, Object argA, Object argB) { +- if (logger.isEnabledFor(Level.WARN)) { +- FormattingTuple ft = MessageFormatter.format(format, argA, argB); +- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log a message at level WARN according to the specified format and +- * arguments. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the WARN level. +- * </p> +- * +- * @param format +- * the format string +- * @param argArray +- * an array of arguments +- */ +- @Override +- public void warn(String format, Object... argArray) { +- if (logger.isEnabledFor(Level.WARN)) { +- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); +- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log an exception (throwable) at the WARN level with an accompanying +- * message. +- * +- * @param msg +- * the message accompanying the exception +- * @param t +- * the exception (throwable) to log +- */ +- @Override +- public void warn(String msg, Throwable t) { +- logger.log(FQCN, Level.WARN, msg, t); +- } +- +- /** +- * Is this logger instance enabled for level ERROR? +- * +- * @return True if this Logger is enabled for level ERROR, false otherwise. +- */ +- @Override +- public boolean isErrorEnabled() { +- return logger.isEnabledFor(Level.ERROR); +- } +- +- /** +- * Log a message object at the ERROR level. +- * +- * @param msg +- * - the message object to be logged +- */ +- @Override +- public void error(String msg) { +- logger.log(FQCN, Level.ERROR, msg, null); +- } +- +- /** +- * Log a message at the ERROR level according to the specified format and +- * argument. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the ERROR level. +- * </p> +- * +- * @param format +- * the format string +- * @param arg +- * the argument +- */ +- @Override +- public void error(String format, Object arg) { +- if (logger.isEnabledFor(Level.ERROR)) { +- FormattingTuple ft = MessageFormatter.format(format, arg); +- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log a message at the ERROR level according to the specified format and +- * arguments. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the ERROR level. +- * </p> +- * +- * @param format +- * the format string +- * @param argA +- * the first argument +- * @param argB +- * the second argument +- */ +- @Override +- public void error(String format, Object argA, Object argB) { +- if (logger.isEnabledFor(Level.ERROR)) { +- FormattingTuple ft = MessageFormatter.format(format, argA, argB); +- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log a message at level ERROR according to the specified format and +- * arguments. +- * +- * <p> +- * This form avoids superfluous object creation when the logger is disabled +- * for the ERROR level. +- * </p> +- * +- * @param format +- * the format string +- * @param argArray +- * an array of arguments +- */ +- @Override +- public void error(String format, Object... argArray) { +- if (logger.isEnabledFor(Level.ERROR)) { +- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); +- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); +- } +- } +- +- /** +- * Log an exception (throwable) at the ERROR level with an accompanying +- * message. +- * +- * @param msg +- * the message accompanying the exception +- * @param t +- * the exception (throwable) to log +- */ +- @Override +- public void error(String msg, Throwable t) { +- logger.log(FQCN, Level.ERROR, msg, t); +- } +-} +diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java b/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java +deleted file mode 100644 +index 399a279df3..0000000000 +--- a/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java ++++ /dev/null +@@ -1,40 +0,0 @@ +-/* +- * Copyright 2012 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.util.internal.logging; +- +-import org.apache.log4j.Logger; +- +-/** +- * Logger factory which creates an +- * <a href="http://logging.apache.org/log4j/1.2/index.html">Apache Log4J</a> +- * logger. +- */ +-public class Log4JLoggerFactory extends InternalLoggerFactory { +- +- public static final InternalLoggerFactory INSTANCE = new Log4JLoggerFactory(); +- +- /** +- * @deprecated Use {@link #INSTANCE} instead. +- */ +- @Deprecated +- public Log4JLoggerFactory() { +- } +- +- @Override +- public InternalLogger newInstance(String name) { +- return new Log4JLogger(Logger.getLogger(name)); +- } +-} +-- +2.26.2 + diff --git a/netty.spec b/netty.spec index 5a630f0..90e1234 100644 --- a/netty.spec +++ b/netty.spec @@ -1,13 +1,9 @@ -# Disable generation of debuginfo package -%global debug_package %{nil} %global namedreltag .Final %global namedversion %{version}%{?namedreltag}
-%bcond_without jp_minimal - Name: netty -Version: 4.1.13 -Release: 19%{?dist} +Version: 4.1.51 +Release: 1%{?dist} Summary: An asynchronous event-driven network application framework and tools for Java License: ASL 2.0 URL: https://netty.io/ @@ -16,42 +12,25 @@ Source0: https://github.com/netty/netty/archive/netty-%%7Bnamedversion%7D.tar # We don't have the plugin and want to avoid groovy dependency # This script is written in bash+sed and performs the same task Source1: codegen.bash -Patch0: 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch -Patch1: 0002-Remove-NPN.patch -Patch2: 0003-Remove-conscrypt-ALPN.patch -Patch3: 0004-Remove-jetty-ALPN.patch +Patch0: 0001-Remove-optional-dep-Blockhound.patch +Patch1: 0002-Remove-optional-dep-conscrypt.patch +Patch2: 0003-Remove-optional-deps-jetty-alpn-and-npn.patch +Patch3: 0004-Remove-optional-dep-tcnative.patch +Patch4: 0005-Remove-optional-dep-log4j.patch
BuildRequires: maven-local -BuildRequires: mvn(ant-contrib:ant-contrib) BuildRequires: mvn(com.jcraft:jzlib) BuildRequires: mvn(commons-logging:commons-logging) BuildRequires: mvn(kr.motd.maven:os-maven-plugin) -BuildRequires: mvn(log4j:log4j:1.2.17) BuildRequires: mvn(org.apache.felix:maven-bundle-plugin) -BuildRequires: mvn(org.apache.maven.plugins:maven-antrun-plugin) -BuildRequires: mvn(org.apache.maven.plugins:maven-dependency-plugin) BuildRequires: mvn(org.apache.maven.plugins:maven-remote-resources-plugin) +BuildRequires: mvn(org.bouncycastle:bcpkix-jdk15on) BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin) BuildRequires: mvn(org.codehaus.mojo:exec-maven-plugin) -BuildRequires: mvn(org.fusesource.hawtjni:maven-hawtjni-plugin) BuildRequires: mvn(org.jctools:jctools-core) BuildRequires: mvn(org.slf4j:slf4j-api) -%if %{without jp_minimal} -BuildRequires: mvn(com.fasterxml:aalto-xml) -BuildRequires: mvn(com.github.jponge:lzma-java) -BuildRequires: mvn(com.ning:compress-lzf) -BuildRequires: mvn(net.jpountz.lz4:lz4) -BuildRequires: mvn(org.apache.logging.log4j:log4j-api) -BuildRequires: mvn(org.bouncycastle:bcpkix-jdk15on) -BuildRequires: mvn(org.jboss.marshalling:jboss-marshalling) -BuildRequires: mvn(org.eclipse.jetty.alpn:alpn-api) -%endif
-%ifarch %{arm} -# Speed up builds on 32bit arm -# Disable temporarily due to https://bugzilla.redhat.com/show_bug.cgi?id=1818078 -#BuildRequires: java-1.8.0-openjdk-aarch32-devel -%endif +BuildArch: noarch
%description Netty is a NIO client server framework which enables quick and easy @@ -79,9 +58,8 @@ Summary: API documentation for %{name} %patch0 -p1 %patch1 -p1 %patch2 -p1 -%if %{with jp_minimal} %patch3 -p1 -%endif +%patch4 -p1
# remove unnecessary dependency on parent POM %pom_remove_parent . bom dev-tools @@ -89,15 +67,8 @@ Summary: API documentation for %{name} # Disable all in one jar %pom_disable_module all
-# Missing Mavenized rxtx -%pom_disable_module "transport-rxtx" -# Missing com.barchart.udt:barchart-udt-bundle:jar:2.3.0 -%pom_disable_module "transport-udt" -# Not needed +# Not needed for RPM builds %pom_disable_module "example" -%pom_disable_module "testsuite" -%pom_disable_module "testsuite-autobahn" -%pom_disable_module "testsuite-osgi" %pom_disable_module "tarball" %pom_disable_module "microbench"
@@ -112,7 +83,6 @@ Summary: API documentation for %{name}
%pom_remove_plugin :maven-antrun-plugin %pom_remove_plugin :maven-dependency-plugin -# style checker %pom_remove_plugin :xml-maven-plugin %pom_remove_plugin -r :maven-checkstyle-plugin %pom_remove_plugin -r :animal-sniffer-maven-plugin @@ -143,6 +113,10 @@ cp %{SOURCE1} common/codegen.bash ' %pom_remove_plugin :groovy-maven-plugin common
+# We don't have com.oracle.substratevm +%pom_remove_dep "com.oracle.substratevm:" common +rm common/src/main/java/io/netty/util/internal/svm/* + # The protobuf-javanano API was discontinued upstream and obsoleted in Fedora # so disable support for protobuf in the codecs module %pom_remove_dep -r "com.google.protobuf:protobuf-java" @@ -150,31 +124,41 @@ cp %{SOURCE1} common/codegen.bash rm codec/src/main/java/io/netty/handler/codec/protobuf/* sed -i '/import.*protobuf/d' codec/src/main/java/io/netty/handler/codec/DatagramPacket*.java
-%if %{with jp_minimal} +# JBoss marshalling not available in Fedora %pom_remove_dep -r "org.jboss.marshalling:jboss-marshalling" rm codec/src/main/java/io/netty/handler/codec/marshalling/* -%pom_remove_dep -r org.bouncycastle -rm handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java -sed -i '/BouncyCastleSelfSignedCertGenerator/s/.*/throw new UnsupportedOperationException();/' \ - handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java -%pom_remove_dep -r com.fasterxml:aalto-xml -%pom_disable_module codec-xml + +# Various compression codecs not available in Fedora %pom_remove_dep -r com.github.jponge:lzma-java rm codec/src/*/java/io/netty/handler/codec/compression/Lzma*.java %pom_remove_dep -r com.ning:compress-lzf rm codec/src/*/java/io/netty/handler/codec/compression/Lzf*.java %pom_remove_dep -r net.jpountz.lz4:lz4 rm codec/src/*/java/io/netty/handler/codec/compression/Lz4*.java -%pom_remove_dep -r org.apache.logging.log4j: -rm common/*/main/java/io/netty/util/internal/logging/Log4J2*.java
-# Disable rarely needed native artifacts +# Disable other codecs with extra dependencies +%pom_remove_dep -r com.fasterxml:aalto-xml +%pom_disable_module codec-xml + +# Disable unneeded transport artifacts %pom_disable_module transport-native-epoll %pom_disable_module transport-native-kqueue - -%endif - -%pom_xpath_inject "pom:execution[pom:id = 'build-native-lib']/pom:configuration" '<verbose>true</verbose>' transport-native-epoll/pom.xml +%pom_disable_module transport-native-unix-common +%pom_disable_module transport-rxtx +%pom_disable_module transport-sctp +%pom_disable_module transport-udt + +# Disable macos native bit +%pom_disable_module resolver-dns-native-macos + +# Disable test suites +%pom_disable_module testsuite +%pom_disable_module testsuite-autobahn +%pom_disable_module testsuite-http2 +%pom_disable_module testsuite-native-image +%pom_disable_module testsuite-osgi +%pom_disable_module testsuite-shading +%pom_disable_module transport-native-unix-common-tests
# Upstream has jctools bundled. %pom_xpath_remove "pom:build/pom:plugins/pom:plugin[pom:artifactId = 'maven-bundle-plugin']/pom:executions/pom:execution[pom:id = 'generate-manifest']/pom:configuration/pom:instructions/pom:Import-Package" common/pom.xml @@ -184,11 +168,7 @@ rm common/*/main/java/io/netty/util/internal/logging/Log4J2*.java # the linux classifier. %mvn_package ":::linux*:"
-%mvn_package ':*-tests' __noinstall - %build -export JAVA_HOME=%{_jvmdir}/java - # Ensure we use distro compile flags export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS"
@@ -204,6 +184,10 @@ export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS" %license LICENSE.txt NOTICE.txt
%changelog +* Mon Sep 07 2020 Mat Booth mat.booth@redhat.com - 4.1.51-1 +- Update to latest upstream version +- Native bits were not used by anything, so package is now noarch + * Tue Jul 28 2020 Fedora Release Engineering releng@fedoraproject.org - 4.1.13-19 - Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
diff --git a/sources b/sources index 39533ac..a39ea3d 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (netty-4.1.13.Final.tar.gz) = f0a269adf5b6552eb2f0f12614c2093e0ccfd5a5bb38521dcf39c3827160c8983adcfe1bbcf93a24e71506e323ae723a837621046657fec0df50c59a07aee54c +SHA512 (netty-4.1.51.Final.tar.gz) = 3b6e00b48710ada4e2c3fbcd71a2c82804dded30c8fa99f10dc609e063642ab5351fe0c26183b03a429439d2351b51ca4cfe803e68dfc5929156faafb1a47800