diff --git a/.gitignore b/.gitignore index e69de29..488860d 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +/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 +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 @@ + log4j-core + test + +- +- io.projectreactor.tools +- blockhound +- true +- + + org.mockito + mockito-core +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. +- *

+- * 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>() { +- @Override +- public Predicate apply(final Predicate p) { +- return new Predicate() { +- @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 @@ + testsuite-osgi + testsuite-shading + testsuite-native-image +- transport-blockhound-tests + microbench + bom + +@@ -717,12 +716,6 @@ + test + + +- +- +- io.projectreactor.tools +- blockhound +- 1.0.3.RELEASE +- + + + +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 @@ +- +- +- +- +- 4.0.0 +- +- io.netty +- netty-parent +- 4.1.51.Final +- +- +- netty-transport-blockhound-tests +- jar +- +- Tests for the BlockHound integration. +- +- +- Netty/Transport/BlockHound/Tests +- +- +- +- java13 +- +- 13 +- +- +- -XX:+AllowRedefinitionToAddDeleteMethods +- +- +- +- java14 +- +- 14 +- +- +- -XX:+AllowRedefinitionToAddDeleteMethods +- +- +- +- +- +- 1.8 +- 1.8 +- +- --add-exports java.base/sun.security.x509=ALL-UNNAMED +- true +- +- +- +- +- ${project.groupId} +- netty-transport +- ${project.version} +- +- +- ${project.groupId} +- netty-handler +- ${project.version} +- +- +- ${project.groupId} +- ${tcnative.artifactId} +- ${tcnative.classifier} +- true +- +- +- +- org.bouncycastle +- bcpkix-jdk15on +- true +- +- +- io.projectreactor.tools +- blockhound +- test +- +- +- +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 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() { +- @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-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 +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 @@ + alpn-api + true + +- +- ${conscrypt.groupId} +- ${conscrypt.artifactId} +- ${conscrypt.classifier} +- true +- + + org.mockito + mockito-core +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 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(applicationNegotiator.protocols())), +- "protocolSelector"); +- } +- +- private void selectProtocol() throws SSLException { +- try { +- String protocol = Conscrypt.getApplicationProtocol(getWrappedEngine()); +- protocolSelector.select(protocol != null ? Collections.singletonList(protocol) +- : Collections.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 @@ + true + + +- +- +- ${conscrypt.groupId} +- ${conscrypt.artifactId} +- ${conscrypt.classifier} +- ${conscrypt.version} +- compile +- true +- +- + +- +- org.eclipse.jetty.npn +- npn-api +- 1.1.1.v20141010 +- provided +- +- +- org.eclipse.jetty.alpn +- alpn-api +- 1.1.2.v20150522 +- provided +- +- + + + com.google.protobuf +-- +2.26.2 + diff --git a/0004-Remove-optional-dep-tcnative.patch b/0004-Remove-optional-dep-tcnative.patch new file mode 100644 index 0000000..6ed11bd --- /dev/null +++ b/0004-Remove-optional-dep-tcnative.patch @@ -0,0 +1,8567 @@ +From c60f3b8d7ca0575bba15682a329dced786f898da Mon Sep 17 00:00:00 2001 +From: Mat Booth +Date: Mon, 7 Sep 2020 13:41:44 +0100 +Subject: [PATCH 4/5] Remove optional dep tcnative + +--- + 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/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 + +diff --git a/handler/pom.xml b/handler/pom.xml +index be8206dc89..e28cc6f7af 100644 +--- a/handler/pom.xml ++++ b/handler/pom.xml +@@ -60,12 +60,6 @@ + netty-codec + ${project.version} + +- +- ${project.groupId} +- ${tcnative.artifactId} +- ${tcnative.classifier} +- true +- + + org.bouncycastle + bcpkix-jdk15on +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 94e951f7f5..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java ++++ /dev/null +@@ -1,494 +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 io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; +- +-import java.util.Collections; +-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; +- +-/** +- * Converts a Java cipher suite string to an OpenSSL cipher suite string and vice versa. +- * +- * @see Wikipedia page about cipher suite +- */ +-final class CipherSuiteConverter { +- +- private static final InternalLogger logger = InternalLoggerFactory.getInstance(CipherSuiteConverter.class); +- +- /** +- * 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]+)-(.*)$"); +- +- /** +- * Java-to-OpenSSL cipher suite conversion map +- * Note that the Java cipher suite has the protocol prefix (TLS_, SSL_) +- */ +- private static final ConcurrentMap j2o = PlatformDependent.newConcurrentHashMap(); +- +- /** +- * 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> o2j = PlatformDependent.newConcurrentHashMap(); +- +- private static final Map j2oTls13; +- private static final Map> o2jTls13; +- +- static { +- Map j2oTls13Map = new HashMap(); +- 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> o2jTls13Map = new HashMap>(); +- 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); +- } +- +- /** +- * 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 p2j = o2j.get(key); +- if (p2j == null) { +- return false; +- } else { +- return value.equals(p2j.get(protocol)); +- } +- } +- +- /** +- * 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); +- } +- +- private static String cacheFromJava(String javaCipherSuite, boolean boringSSL) { +- String converted = j2oTls13.get(javaCipherSuite); +- if (converted != null) { +- return boringSSL ? converted : javaCipherSuite; +- } +- +- String openSslCipherSuite = toOpenSslUncached(javaCipherSuite, boringSSL); +- if (openSslCipherSuite == null) { +- return null; +- } +- +- // Cache the mapping. +- j2o.putIfAbsent(javaCipherSuite, openSslCipherSuite); +- +- // Cache the reverse mapping after stripping the protocol prefix (TLS_ or SSL_) +- final String javaCipherSuiteSuffix = javaCipherSuite.substring(4); +- Map p2j = new HashMap(4); +- p2j.put("", javaCipherSuiteSuffix); +- p2j.put("SSL", "SSL_" + javaCipherSuiteSuffix); +- p2j.put("TLS", "TLS_" + javaCipherSuiteSuffix); +- o2j.put(openSslCipherSuite, p2j); +- +- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuite, openSslCipherSuite); +- +- return openSslCipherSuite; +- } +- +- static String toOpenSslUncached(String javaCipherSuite, boolean boringSSL) { +- String converted = j2oTls13.get(javaCipherSuite); +- if (converted != null) { +- return boringSSL ? converted : javaCipherSuite; +- } +- +- Matcher m = JAVA_CIPHERSUITE_PATTERN.matcher(javaCipherSuite); +- if (!m.matches()) { +- return null; +- } +- +- 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 { +- return handshakeAlgo + '-' + bulkCipher + '-' + hmacAlgo; +- } +- } +- +- 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 handshakeAlgo.replace('_', '-'); +- } +- +- 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"); +- } +- } +- +- if ("3DES_EDE_CBC".equals(bulkCipher)) { +- return "DES-CBC3"; +- } +- +- if ("RC4_128".equals(bulkCipher) || "RC4_40".equals(bulkCipher)) { +- return "RC4"; +- } +- +- if ("DES40_CBC".equals(bulkCipher) || "DES_CBC_40".equals(bulkCipher)) { +- return "DES-CBC"; +- } +- +- if ("RC2_CBC_40".equals(bulkCipher)) { +- return "RC2-CBC"; +- } +- +- return bulkCipher.replace('_', '-'); +- } +- +- private static String toOpenSslHmacAlgo(String hmacAlgo) { +- // Java and OpenSSL use the same algorithm names for: +- // +- // * SHA +- // * SHA256 +- // * MD5 +- // +- return hmacAlgo; +- } +- +- /** +- * 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}. +- */ +- static String toJava(String openSslCipherSuite, String protocol) { +- Map 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; +- } +- +- private static Map cacheFromOpenSsl(String openSslCipherSuite) { +- Map converted = o2jTls13.get(openSslCipherSuite); +- if (converted != null) { +- return converted; +- } +- +- String javaCipherSuiteSuffix = toJavaUncached0(openSslCipherSuite, false); +- if (javaCipherSuiteSuffix == null) { +- return null; +- } +- +- final String javaCipherSuiteSsl = "SSL_" + javaCipherSuiteSuffix; +- final String javaCipherSuiteTls = "TLS_" + javaCipherSuiteSuffix; +- +- // Cache the mapping. +- final Map p2j = new HashMap(4); +- p2j.put("", javaCipherSuiteSuffix); +- p2j.put("SSL", javaCipherSuiteSsl); +- p2j.put("TLS", javaCipherSuiteTls); +- o2j.putIfAbsent(openSslCipherSuite, p2j); +- +- // Cache the reverse mapping after adding the protocol prefix (TLS_ or SSL_) +- j2o.putIfAbsent(javaCipherSuiteTls, openSslCipherSuite); +- j2o.putIfAbsent(javaCipherSuiteSsl, openSslCipherSuite); +- +- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteTls, openSslCipherSuite); +- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteSsl, openSslCipherSuite); +- +- return p2j; +- } +- +- static String toJavaUncached(String openSslCipherSuite) { +- return toJavaUncached0(openSslCipherSuite, true); +- } +- +- private static String toJavaUncached0(String openSslCipherSuite, boolean checkTls13) { +- if (checkTls13) { +- Map converted = o2jTls13.get(openSslCipherSuite); +- if (converted != null) { +- return converted.get("TLS"); +- } +- } +- +- Matcher m = OPENSSL_CIPHERSUITE_PATTERN.matcher(openSslCipherSuite); +- if (!m.matches()) { +- return null; +- } +- +- 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; +- } +- +- handshakeAlgo = toJavaHandshakeAlgo(handshakeAlgo, export); +- String bulkCipher = toJavaBulkCipher(m.group(2), export); +- String hmacAlgo = toJavaHmacAlgo(m.group(3)); +- +- 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 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"; +- } +- +- handshakeAlgo = handshakeAlgo.replace('-', '_'); +- if (export) { +- return handshakeAlgo + "_EXPORT"; +- } else { +- return handshakeAlgo; +- } +- } +- +- 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 ("DES-CBC3".equals(bulkCipher)) { +- return "3DES_EDE_CBC"; +- } +- +- if ("RC4".equals(bulkCipher)) { +- if (export) { +- return "RC4_40"; +- } else { +- return "RC4_128"; +- } +- } +- +- if ("DES-CBC".equals(bulkCipher)) { +- if (export) { +- return "DES_CBC_40"; +- } else { +- return "DES_CBC"; +- } +- } +- +- if ("RC2-CBC".equals(bulkCipher)) { +- if (export) { +- return "RC2_CBC_40"; +- } else { +- return "RC2_CBC"; +- } +- } +- +- return bulkCipher.replace('-', '_'); +- } +- +- 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 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 (cipherBuilder.length() == 0 && cipherTLSv13Builder.length() == 0) { +- throw new IllegalArgumentException("empty cipher suites"); +- } +- if (cipherBuilder.length() > 0) { +- cipherBuilder.setLength(cipherBuilder.length() - 1); +- } +- if (cipherTLSv13Builder.length() > 0) { +- cipherTLSv13Builder.setLength(cipherTLSv13Builder.length() - 1); +- } +- } +- +- private CipherSuiteConverter() { } +-} +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 fcea5266f2..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java ++++ /dev/null +@@ -1,126 +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.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.X509Certificate; +- +-final class DefaultOpenSslKeyMaterial extends AbstractReferenceCounted implements OpenSslKeyMaterial { +- +- private static final ResourceLeakDetector leakDetector = +- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(DefaultOpenSslKeyMaterial.class); +- private final ResourceLeakTracker leak; +- private final X509Certificate[] x509CertificateChain; +- private long chain; +- private long privateKey; +- +- DefaultOpenSslKeyMaterial(long chain, long privateKey, X509Certificate[] x509CertificateChain) { +- this.chain = chain; +- this.privateKey = privateKey; +- this.x509CertificateChain = x509CertificateChain; +- leak = leakDetector.track(this); +- } +- +- @Override +- public X509Certificate[] certificateChain() { +- return x509CertificateChain.clone(); +- } +- +- @Override +- public long certificateChainAddress() { +- if (refCnt() <= 0) { +- throw new IllegalReferenceCountException(); +- } +- return chain; +- } +- +- @Override +- public long privateKeyAddress() { +- if (refCnt() <= 0) { +- throw new IllegalReferenceCountException(); +- } +- return privateKey; +- } +- +- @Override +- protected void deallocate() { +- SSL.freeX509Chain(chain); +- chain = 0; +- SSL.freePrivateKey(privateKey); +- privateKey = 0; +- if (leak != null) { +- boolean closed = leak.close(this); +- assert closed; +- } +- } +- +- @Override +- public DefaultOpenSslKeyMaterial retain() { +- if (leak != null) { +- leak.record(); +- } +- 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/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java +deleted file mode 100644 +index d7d44cf3e7..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java ++++ /dev/null +@@ -1,610 +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 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.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 static io.netty.handler.ssl.SslUtils.*; +- +-/** +- * Tells if {@code netty-tcnative} and its OpenSSL support +- * are available. +- */ +-public final class OpenSsl { +- +- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class); +- private static final Throwable UNAVAILABILITY_CAUSE; +- +- static final List DEFAULT_CIPHERS; +- static final Set AVAILABLE_CIPHER_SUITES; +- private static final Set AVAILABLE_OPENSSL_CIPHER_SUITES; +- private static final Set 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 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 defaultCiphers = new ArrayList(); +- final Set availableOpenSslCipherSuites = new LinkedHashSet(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 availableJavaCipherSuites = new LinkedHashSet( +- 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 availableCipherSuites = new LinkedHashSet( +- 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 protocols = new LinkedHashSet(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; +- } +- } +- +- /** +- * Returns a self-signed {@link X509Certificate} for {@code netty.io}. +- */ +- 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); +- } +- } +- } +- +- /** +- * Returns {@code true} if and only if +- * {@code netty-tcnative} and its OpenSSL support +- * are available. +- */ +- public static boolean isAvailable() { +- return UNAVAILABILITY_CAUSE == null; +- } +- +- /** +- * Returns {@code true} if the used version of openssl supports +- * ALPN. +- * +- * @deprecated use {@link SslProvider#isAlpnSupported(SslProvider)} with {@link SslProvider#OPENSSL}. +- */ +- @Deprecated +- public static boolean isAlpnSupported() { +- return version() >= 0x10002000L; +- } +- +- /** +- * Returns {@code true} if the used version of OpenSSL supports OCSP stapling. +- */ +- public static boolean isOcspSupported() { +- return SUPPORTS_OCSP; +- } +- +- /** +- * 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 {@code netty-tcnative} 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 +- * {@code netty-tcnative} 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 availableCipherSuites() { +- return availableOpenSslCipherSuites(); +- } +- +- /** +- * 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 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 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 static boolean supportsHostnameValidation() { +- return isAvailable(); +- } +- +- 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 libNames = new LinkedHashSet(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 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])); +- } +- +- private static boolean initializeTcNative(String engine) throws Exception { +- return Library.initialize("provided", engine); +- } +- +- 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/OpenSslCachingKeyMaterialProvider.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java +deleted file mode 100644 +index 07b67d9fa7..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java ++++ /dev/null +@@ -1,79 +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 javax.net.ssl.X509KeyManager; +-import java.util.Iterator; +-import java.util.concurrent.ConcurrentHashMap; +-import java.util.concurrent.ConcurrentMap; +- +-/** +- * {@link OpenSslKeyMaterialProvider} that will cache the {@link OpenSslKeyMaterial} to reduce the overhead +- * of parsing the chain and the key for generation of the material. +- */ +-final class OpenSslCachingKeyMaterialProvider extends OpenSslKeyMaterialProvider { +- +- private final int maxCachedEntries; +- private volatile boolean full; +- private final ConcurrentMap cache = new ConcurrentHashMap(); +- +- OpenSslCachingKeyMaterialProvider(X509KeyManager keyManager, String password, int maxCachedEntries) { +- super(keyManager, password); +- this.maxCachedEntries = maxCachedEntries; +- } +- +- @Override +- 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 +- void destroy() { +- // Remove and release all entries. +- do { +- Iterator 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/OpenSslCachingX509KeyManagerFactory.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java +deleted file mode 100644 +index 7f67bc8198..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java ++++ /dev/null +@@ -1,81 +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.util.internal.ObjectUtil; +- +-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; +- +-/** +- * 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 OpenSslCachingX509KeyManagerFactory extends KeyManagerFactory { +- +- private final int maxCachedEntries; +- +- public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory) { +- this(factory, 1024); +- } +- +- 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/OpenSslCertificateException.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java +deleted file mode 100644 +index f20b2d3ba0..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java ++++ /dev/null +@@ -1,81 +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.CertificateVerifier; +- +-import java.security.cert.CertificateException; +- +-/** +- * 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; +- +- private final int errorCode; +- +- /** +- * Construct a new exception with the +- * error code. +- */ +- public OpenSslCertificateException(int errorCode) { +- this((String) null, errorCode); +- } +- +- /** +- * Construct a new exception with the msg and +- * error code . +- */ +- public OpenSslCertificateException(String msg, int errorCode) { +- super(msg); +- this.errorCode = checkErrorCode(errorCode); +- } +- +- /** +- * Construct a new exception with the msg, cause and +- * error code . +- */ +- public OpenSslCertificateException(String message, Throwable cause, int errorCode) { +- super(message, cause); +- this.errorCode = checkErrorCode(errorCode); +- } +- +- /** +- * Construct a new exception with the cause and +- * error code . +- */ +- public OpenSslCertificateException(Throwable cause, int errorCode) { +- this(null, cause, errorCode); +- } +- +- /** +- * Return the error code to use. +- */ +- public int errorCode() { +- return errorCode; +- } +- +- 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/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java +deleted file mode 100644 +index 7f9b39a8dd..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java ++++ /dev/null +@@ -1,208 +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 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.KeyManagerFactory; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.TrustManager; +-import javax.net.ssl.TrustManagerFactory; +- +-import static io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext; +- +-/** +- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- *

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}. +- */ +-public final class OpenSslClientContext extends OpenSslContext { +- private final OpenSslSessionContext sessionContext; +- +- /** +- * Creates a new instance. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- 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. +- * {@code null} to use the system default +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslClientContext(File certChainFile) throws SSLException { +- this(certChainFile, null); +- } +- +- /** +- * 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} +- */ +- @Deprecated +- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws SSLException { +- this(null, trustManagerFactory); +- } +- +- /** +- * Creates a new instance. +- * +- * @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 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 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} +- */ +- @Deprecated +- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable 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 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} +- */ +- @Deprecated +- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable 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. +- * {@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} +- */ +- @Deprecated +- public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, +- File keyCertChainFile, File keyFile, String keyPassword, +- KeyManagerFactory keyManagerFactory, Iterable 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, KeyStore.getDefaultType()); +- } +- +- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, +- KeyManagerFactory keyManagerFactory, Iterable 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 { +- OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword); +- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, +- keyCertChain, key, keyPassword, keyManagerFactory, keyStore); +- success = true; +- } finally { +- if (!success) { +- release(); +- } +- } +- } +- +- @Override +- public OpenSslSessionContext sessionContext() { +- return sessionContext; +- } +-} +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 f18c0643fc..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java ++++ /dev/null +@@ -1,58 +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 io.netty.buffer.ByteBufAllocator; +- +-import java.security.cert.Certificate; +- +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +- +-/** +- * 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 abstract class OpenSslContext extends ReferenceCountedOpenSslContext { +- OpenSslContext(Iterable 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); +- } +- +- OpenSslContext(Iterable 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 +- final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) { +- return new OpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode); +- } +- +- @Override +- @SuppressWarnings("FinalizeDeclaration") +- protected final void finalize() throws Throwable { +- super.finalize(); +- OpenSsl.releaseIfNeeded(this); +- } +-} +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 a700dabf39..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java ++++ /dev/null +@@ -1,41 +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 io.netty.buffer.ByteBufAllocator; +- +-import javax.net.ssl.SSLEngine; +- +-/** +- * Implements a {@link SSLEngine} using +- * OpenSSL BIO abstractions. +- *

+- * 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 final class OpenSslEngine extends ReferenceCountedOpenSslEngine { +- OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int peerPort, +- boolean jdkCompatibilityMode) { +- super(context, alloc, peerHost, peerPort, jdkCompatibilityMode, false); +- } +- +- @Override +- @SuppressWarnings("FinalizeDeclaration") +- protected void finalize() throws Throwable { +- super.finalize(); +- OpenSsl.releaseIfNeeded(this); +- } +-} +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 02131b4b26..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java ++++ /dev/null +@@ -1,35 +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; +- +-interface OpenSslEngineMap { +- +- /** +- * 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/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 +- * +- * 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.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; +- +- +-/** +- * 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 KEY_TYPES = new HashMap(); +- 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); +- } +- +- private final OpenSslKeyMaterialProvider provider; +- +- OpenSslKeyMaterialManager(OpenSslKeyMaterialProvider provider) { +- this.provider = provider; +- } +- +- void setKeyMaterialServerSide(ReferenceCountedOpenSslEngine engine) throws SSLException { +- String[] authMethods = engine.authMethods(); +- if (authMethods.length == 0) { +- return; +- } +- Set aliases = new HashSet(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; +- } +- } +- } +- } +- } +- +- 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); +- } +- } +- +- private boolean setKeyMaterial(ReferenceCountedOpenSslEngine engine, String alias) throws SSLException { +- OpenSslKeyMaterial keyMaterial = null; +- try { +- 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 { +- 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); +- } +- +- 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; +- +- try { +- pkeyBio = toBIO(UnpooledByteBufAllocator.DEFAULT, key); +- pkey = SSL.parsePrivateKey(pkeyBio, password); +- } catch (Exception e) { +- throw new SSLException("PrivateKey type not supported " + key.getFormat(), e); +- } finally { +- SSL.freeBIO(pkeyBio); +- if (pkey != 0) { +- SSL.freePrivateKey(pkey); +- } +- } +- } +- +- 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 { +- 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 { +- SSL.freeBIO(chainBio); +- if (chain != 0) { +- SSL.freeX509Chain(chain); +- } +- if (encoded != null) { +- encoded.release(); +- } +- } +- } +- +- /** +- * Returns the underlying {@link X509KeyManager} that is used. +- */ +- X509KeyManager keyManager() { +- return keyManager; +- } +- +- /** +- * Returns the {@link OpenSslKeyMaterial} or {@code null} (if none) that should be used during the handshake by +- * OpenSSL. +- */ +- 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 { +- 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 { +- SSL.freeBIO(chainBio); +- SSL.freeBIO(pkeyBio); +- if (chain != 0) { +- SSL.freeX509Chain(chain); +- } +- if (pkey != 0) { +- SSL.freePrivateKey(pkey); +- } +- encoded.release(); +- } +- } +- +- /** +- * Will be invoked once the provider should be destroyed. +- */ +- 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; +- +-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; +- } +- +- @Override +- public String getAlgorithm() { +- return "unknown"; +- } +- +- @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; +- } +- +- /** +- * 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() +- */ +- @Override +- public void destroy() { +- release(refCnt()); +- } +- +- /** +- * 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() +- */ +- @Override +- public boolean isDestroyed() { +- return refCnt() == 0; +- } +- +- /** +- * 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}. +- */ +- 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/OpenSslPrivateKeyMethod.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java +deleted file mode 100644 +index d9fc877269..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java ++++ /dev/null +@@ -1,62 +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.handler.ssl; +- +-import io.netty.internal.tcnative.SSLPrivateKeyMethod; +-import io.netty.util.internal.UnstableApi; +- +-import javax.net.ssl.SSLEngine; +- +-/** +- * Allow to customize private key signing / decrypting (when using RSA). Only supported when using BoringSSL atm. +- */ +-@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; +- +- /** +- * Signs the input with the given key and returns the signed bytes. +- * +- * @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 +- */ +- byte[] sign(SSLEngine engine, int signatureAlgorithm, byte[] input) throws Exception; +- +- /** +- * 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 +- */ +- byte[] decrypt(SSLEngine engine, byte[] input) throws Exception; +-} +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 da342de0f2..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java ++++ /dev/null +@@ -1,367 +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 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; +- +-/** +- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- *

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 OpenSslServerContext extends OpenSslContext { +- private final OpenSslServerSessionContext 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); +- } +- +- /** +- * 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); +- } +- +- /** +- * 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 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. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, +- Iterable ciphers, Iterable nextProtocols, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(certChainFile, keyFile, keyPassword, ciphers, +- toApplicationProtocolConfig(nextProtocols), 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 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 ciphers, ApplicationProtocolConfig config, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers, +- 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 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 ciphers, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, +- ciphers, null, 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 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 ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(null, null, 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 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 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 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 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 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 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()); +- } +- +- OpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable 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); +- } +- +- @SuppressWarnings("deprecation") +- private OpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable 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); +- +- // 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(); +- } +- } +- } +- +- @Override +- public OpenSslServerSessionContext sessionContext() { +- return sessionContext; +- } +-} +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 691ee0b661..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.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 io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +- +-import java.util.concurrent.locks.Lock; +- +- +-/** +- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side. +- */ +-public final class OpenSslServerSessionContext extends OpenSslSessionContext { +- OpenSslServerSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) { +- super(context, provider); +- } +- +- @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(); +- } +- } +- +- @Override +- public int getSessionCacheSize() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return (int) SSLContext.getSessionCacheSize(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- @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(); +- } +- } +- +- @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 +- * man SSL_CTX_set_session_id_context +- * +- * @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; +- +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +-import io.netty.internal.tcnative.SessionTicketKey; +-import io.netty.util.internal.ObjectUtil; +- +-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; +- +-/** +- * OpenSSL specific {@link SSLSessionContext} implementation. +- */ +-public abstract class OpenSslSessionContext implements SSLSessionContext { +- private static final Enumeration EMPTY = new EmptyEnumeration(); +- +- private final OpenSslSessionStats stats; +- +- // 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; +- +- 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, OpenSslKeyMaterialProvider provider) { +- this.context = context; +- this.provider = provider; +- stats = new OpenSslSessionStats(context); +- } +- +- final boolean useKeyManager() { +- return provider != null; +- } +- +- @Override +- public SSLSession getSession(byte[] bytes) { +- ObjectUtil.checkNotNull(bytes, "bytes"); +- return null; +- } +- +- @Override +- public Enumeration 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. 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 +- * +- * BoringSSL 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(); +- } +- } +- +- /** +- * 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; +- } +- +- final void destroy() { +- if (provider != null) { +- provider.destroy(); +- } +- } +- +- private static final class EmptyEnumeration implements Enumeration { +- @Override +- public boolean hasMoreElements() { +- return false; +- } +- +- @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. +- */ +- +-package io.netty.handler.ssl; +- +-import io.netty.internal.tcnative.SSLContext; +- +-import java.util.concurrent.locks.Lock; +- +-/** +- * Stats exposed by an OpenSSL session context. +- * +- * @see SSL_CTX_sess_number +- */ +-public final class OpenSslSessionStats { +- +- private 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. +- OpenSslSessionStats(ReferenceCountedOpenSslContext context) { +- this.context = context; +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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 { +- readerLock.unlock(); +- } +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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(); +- } +- } +- +- /** +- * 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 the number of times a client did not present a ticket and we issued a new one +- */ +- public long ticketKeyNew() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTicketKeyNew(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of times a client presented a ticket derived from an older key, +- * and we upgraded to the primary key. +- */ +- public long ticketKeyRenew() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTicketKeyRenew(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of times a client presented a ticket derived from the primary key. +- */ +- 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 { +- +- /** +- * 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; +- +- /** +- * 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 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(); +- } +- +- /** +- * Get AES Key. +- * @return the AES key of the session ticket key +- */ +- 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; +- +-import io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.SuppressJava6Requirement; +- +-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; +- +-/** +- * Provide a way to use {@code TLSv1.3} with Java versions prior to 11 by adding a +- * = 7 && session instanceof ExtendedOpenSslSession) { +- final ExtendedOpenSslSession extendedOpenSslSession = (ExtendedOpenSslSession) session; +- return new ExtendedOpenSslSession(extendedOpenSslSession) { +- @Override +- public List getRequestedServerNames() { +- return extendedOpenSslSession.getRequestedServerNames(); +- } +- +- @Override +- public String[] getPeerSupportedSignatureAlgorithms() { +- return extendedOpenSslSession.getPeerSupportedSignatureAlgorithms(); +- } +- +- @Override +- public String getProtocol() { +- return SslUtils.PROTOCOL_TLS_V1_2; +- } +- }; +- } else { +- return new SSLSession() { +- @Override +- public byte[] getId() { +- return session.getId(); +- } +- +- @Override +- public SSLSessionContext getSessionContext() { +- return session.getSessionContext(); +- } +- +- @Override +- public long getCreationTime() { +- return session.getCreationTime(); +- } +- +- @Override +- public long getLastAccessedTime() { +- return session.getLastAccessedTime(); +- } +- +- @Override +- public void invalidate() { +- session.invalidate(); +- } +- +- @Override +- public boolean isValid() { +- return session.isValid(); +- } +- +- @Override +- public void putValue(String s, Object o) { +- session.putValue(s, o); +- } +- +- @Override +- public Object getValue(String s) { +- return session.getValue(s); +- } +- +- @Override +- public void removeValue(String s) { +- session.removeValue(s); +- } +- +- @Override +- public String[] getValueNames() { +- return session.getValueNames(); +- } +- +- @Override +- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { +- return session.getPeerCertificates(); +- } +- +- @Override +- public Certificate[] getLocalCertificates() { +- return session.getLocalCertificates(); +- } +- +- @Override +- public javax.security.cert.X509Certificate[] getPeerCertificateChain() +- throws SSLPeerUnverifiedException { +- return session.getPeerCertificateChain(); +- } +- +- @Override +- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { +- return session.getPeerPrincipal(); +- } +- +- @Override +- public Principal getLocalPrincipal() { +- return session.getLocalPrincipal(); +- } +- +- @Override +- public String getCipherSuite() { +- return session.getCipherSuite(); +- } +- +- @Override +- public String getProtocol() { +- return SslUtils.PROTOCOL_TLS_V1_2; +- } +- +- @Override +- public String getPeerHost() { +- return session.getPeerHost(); +- } +- +- @Override +- public int getPeerPort() { +- return session.getPeerPort(); +- } +- +- @Override +- public int getPacketBufferSize() { +- return session.getPacketBufferSize(); +- } +- +- @Override +- public int getApplicationBufferSize() { +- return session.getApplicationBufferSize(); +- } +- }; +- } +- } +- }; +- } +- return engine; +- } +- +- @Override +- public void checkClientTrusted(X509Certificate[] x509Certificates, final String s, SSLEngine sslEngine) +- throws CertificateException { +- tm.checkClientTrusted(x509Certificates, s, wrapEngine(sslEngine)); +- } +- +- @Override +- public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) +- throws CertificateException { +- tm.checkServerTrusted(x509Certificates, s, wrapEngine(sslEngine)); +- } +- +- @Override +- public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { +- tm.checkClientTrusted(x509Certificates, s); +- } +- +- @Override +- public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { +- tm.checkServerTrusted(x509Certificates, s); +- } +- +- @Override +- public X509Certificate[] getAcceptedIssuers() { +- return tm.getAcceptedIssuers(); +- } +-} +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 2a86332fe1..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java ++++ /dev/null +@@ -1,413 +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 io.netty.util.ReferenceCountUtil; +-import io.netty.util.internal.ObjectUtil; +- +-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.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.Map; +- +-/** +- * 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. +- * +- * +- * +- * 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 { +- +- private final OpenSslKeyManagerFactorySpi spi; +- +- public OpenSslX509KeyManagerFactory() { +- this(newOpenSslKeyManagerFactorySpi(null)); +- } +- +- public OpenSslX509KeyManagerFactory(Provider provider) { +- this(newOpenSslKeyManagerFactorySpi(provider)); +- } +- +- public OpenSslX509KeyManagerFactory(String algorithm, Provider provider) throws NoSuchAlgorithmException { +- this(newOpenSslKeyManagerFactorySpi(algorithm, provider)); +- } +- +- private OpenSslX509KeyManagerFactory(OpenSslKeyManagerFactorySpi spi) { +- super(spi, spi.kmf.getProvider(), spi.kmf.getAlgorithm()); +- this.spi = spi; +- } +- +- 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 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)); +- } +- +- OpenSslKeyMaterialProvider newProvider() { +- return spi.newProvider(); +- } +- +- private static final class OpenSslKeyManagerFactorySpi extends KeyManagerFactorySpi { +- final KeyManagerFactory kmf; +- private volatile ProviderFactory providerFactory; +- +- OpenSslKeyManagerFactorySpi(KeyManagerFactory kmf) { +- this.kmf = ObjectUtil.checkNotNull(kmf, "kmf"); +- } +- +- @Override +- 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"); +- } +- +- kmf.init(keyStore, chars); +- providerFactory = new ProviderFactory(ReferenceCountedOpenSslContext.chooseX509KeyManager( +- kmf.getKeyManagers()), password(chars), Collections.list(keyStore.aliases())); +- } +- +- private static String password(char[] password) { +- if (password == null || password.length == 0) { +- return null; +- } +- return new String(password); +- } +- +- @Override +- protected void engineInit(ManagerFactoryParameters managerFactoryParameters) +- throws InvalidAlgorithmParameterException { +- throw new InvalidAlgorithmParameterException("Not supported"); +- } +- +- @Override +- protected KeyManager[] engineGetKeyManagers() { +- ProviderFactory providerFactory = this.providerFactory; +- if (providerFactory == null) { +- throw new IllegalStateException("engineInit(...) not called yet"); +- } +- return new KeyManager[] { providerFactory.keyManager }; +- } +- +- OpenSslKeyMaterialProvider newProvider() { +- ProviderFactory providerFactory = this.providerFactory; +- if (providerFactory == null) { +- throw new IllegalStateException("engineInit(...) not called yet"); +- } +- return providerFactory.newProvider(); +- } +- +- private static final class ProviderFactory { +- private final X509KeyManager keyManager; +- private final String password; +- private final Iterable aliases; +- +- ProviderFactory(X509KeyManager keyManager, String password, Iterable aliases) { +- this.keyManager = keyManager; +- this.password = password; +- this.aliases = aliases; +- } +- +- OpenSslKeyMaterialProvider newProvider() { +- return new OpenSslPopulatedKeyMaterialProvider(keyManager, +- password, aliases); +- } +- +- /** +- * {@link OpenSslKeyMaterialProvider} implementation that pre-compute the {@link OpenSslKeyMaterial} for +- * all aliases. +- */ +- private static final class OpenSslPopulatedKeyMaterialProvider extends OpenSslKeyMaterialProvider { +- private final Map materialMap; +- +- OpenSslPopulatedKeyMaterialProvider( +- X509KeyManager keyManager, String password, Iterable aliases) { +- super(keyManager, password); +- materialMap = new HashMap(); +- 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"); +- } +- } +- +- @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(); +- } +- } +- } +- } +- +- /** +- * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its {@link PrivateKey} directly from +- * an {@code OpenSSL engine} via the +- * ENGINE_load_private_key +- * function. +- */ +- public static OpenSslX509KeyManagerFactory newEngineBased(File certificateChain, String password) +- throws CertificateException, IOException, +- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { +- return newEngineBased(SslContext.toX509Certificates(certificateChain), password); +- } +- +- /** +- * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its {@link PrivateKey} directly from +- * an {@code OpenSSL engine} via the +- * ENGINE_load_private_key +- * 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; +- } +- +- /** +- * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[], String)}. +- */ +- public static OpenSslX509KeyManagerFactory newKeyless(File chain) +- throws CertificateException, IOException, +- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { +- return newKeyless(SslContext.toX509Certificates(chain)); +- } +- +- /** +- * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[], String)}. +- */ +- public static OpenSslX509KeyManagerFactory newKeyless(InputStream chain) +- throws CertificateException, IOException, +- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { +- return newKeyless(SslContext.toX509Certificates(chain)); +- } +- +- /** +- * Returns a new initialized {@link OpenSslX509KeyManagerFactory} which will provide its private key by using the +- * {@link OpenSslPrivateKeyMethod}. +- */ +- 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; +- } +- +- private static final class OpenSslKeyStore extends KeyStore { +- private OpenSslKeyStore(final X509Certificate[] certificateChain, final boolean keyless) { +- super(new KeyStoreSpi() { +- +- 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 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; +- +-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; +- +-/** +- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- *

Instances of this class must be {@link #release() released} or else native memory will leak! +- * +- *

Instances of this class must not 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 SUPPORTED_KEY_TYPES = Collections.unmodifiableSet(new LinkedHashSet( +- 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; +- +- ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, +- KeyManagerFactory keyManagerFactory, Iterable 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 OpenSslSessionContext sessionContext() { +- return sessionContext; +- } +- +- 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); +- } +- +- 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); +- } +- +- // 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); +- +- 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()); +- +- // 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 +- +- 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(); +- } +- } +- } +- +- @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)); +- } +- } +- +- // No cache is currently supported for client side mode. +- static final class OpenSslClientSessionContext extends OpenSslSessionContext { +- OpenSslClientSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) { +- super(context, provider); +- } +- +- @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; +- } +- } +- +- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier { +- private final X509TrustManager manager; +- +- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) { +- super(engineMap); +- this.manager = manager; +- } +- +- @Override +- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) +- throws Exception { +- manager.checkServerTrusted(peerCerts, auth); +- } +- } +- +- @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.checkServerTrusted(peerCerts, auth, engine); +- } +- } +- +- 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; +- } +- +- @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; +- } +- try { +- final Set keyTypesSet = supportedClientKeyTypes(keyTypeBytes); +- final String[] keyTypes = keyTypesSet.toArray(new String[0]); +- 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]); +- } +- } +- keyManagerHolder.setKeyMaterialClientSide(engine, keyTypes, issuers); +- } catch (Throwable cause) { +- logger.debug("request of key failed", cause); +- engine.initHandshakeException(cause); +- } +- } +- +- /** +- * 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 supportedClientKeyTypes(byte[] clientCertificateTypes) { +- if (clientCertificateTypes == null) { +- // Try all of the supported key types. +- return SUPPORTED_KEY_TYPES; +- } +- Set result = new HashSet(clientCertificateTypes.length); +- for (byte keyTypeCode : clientCertificateTypes) { +- String keyType = clientKeyType(keyTypeCode); +- if (keyType == null) { +- // Unsupported client key type -- ignore +- continue; +- } +- result.add(keyType); +- } +- return result; +- } +- +- 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; +- +-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; +- +-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; +- +-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; +- +-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; +- +-/** +- * An implementation of {@link SslContext} which works with libraries that support the +- * OpenSsl C library API. +- *

Instances of this class must be {@link #release() released} or else native memory will leak! +- * +- *

Instances of this class must not 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); +- +- 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 leakDetector = +- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class); +- +- // TODO: Maybe make configurable ? +- protected static final int VERIFY_DEPTH = 10; +- +- /** +- * The OpenSSL SSL_CTX object. +- * +- * {@link #ctxLock} must be hold while using ctx! +- */ +- protected long ctx; +- private final List unmodifiableCiphers; +- private final long sessionCacheSize; +- private final long sessionTimeout; +- private final OpenSslApplicationProtocolNegotiator apn; +- private final int mode; +- +- // Reference Counting +- private final ResourceLeakTracker leak; +- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { +- @Override +- public ReferenceCounted touch(Object hint) { +- if (leak != null) { +- leak.record(hint); +- } +- +- return ReferenceCountedOpenSslContext.this; +- } +- +- @Override +- protected void deallocate() { +- destroy(); +- if (leak != null) { +- boolean closed = leak.close(ReferenceCountedOpenSslContext.this); +- assert closed; +- } +- } +- }; +- +- final Certificate[] keyCertChain; +- final ClientAuth clientAuth; +- final String[] protocols; +- final boolean enableOcsp; +- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap(); +- final ReadWriteLock ctxLock = new ReentrantReadWriteLock(); +- +- private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE; +- +- @SuppressWarnings("deprecation") +- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR = +- new OpenSslApplicationProtocolNegotiator() { +- @Override +- public ApplicationProtocolConfig.Protocol protocol() { +- return ApplicationProtocolConfig.Protocol.NONE; +- } +- +- @Override +- public List protocols() { +- return Collections.emptyList(); +- } +- +- @Override +- public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() { +- return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL; +- } +- +- @Override +- public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() { +- return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT; +- } +- }; +- +- static { +- Integer dhLen = null; +- +- 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); +- } +- } +- } catch (Throwable ignore) { +- // ignore +- } +- DH_KEY_LENGTH = dhLen; +- } +- +- ReferenceCountedOpenSslContext(Iterable 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); +- } +- +- ReferenceCountedOpenSslContext(Iterable 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); +- +- OpenSsl.ensureAvailability(); +- +- if (enableOcsp && !OpenSsl.isOcspSupported()) { +- throw new IllegalStateException("OCSP is not supported."); +- } +- +- 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"); +- } +- leak = leakDetection ? leakDetector.track(this) : null; +- this.mode = mode; +- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE; +- this.protocols = protocols; +- this.enableOcsp = enableOcsp; +- +- this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone(); +- +- 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); +- } +- +- 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); +- } +- +- 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; +- } +- +- 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); +- +- if (DH_KEY_LENGTH != null) { +- SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH); +- } +- +- List 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(); +- } +- } +- +- /* 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); +- +- /* 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 (enableOcsp) { +- SSLContext.enableOcsp(ctx, isClient()); +- } +- +- SSLContext.setUseTasks(ctx, USE_TASKS); +- success = true; +- } finally { +- if (!success) { +- release(); +- } +- } +- } +- +- 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(); +- } +- } +- +- @Override +- public final List cipherSuites() { +- return unmodifiableCiphers; +- } +- +- @Override +- public final long sessionCacheSize() { +- return sessionCacheSize; +- } +- +- @Override +- public final long sessionTimeout() { +- return sessionTimeout; +- } +- +- @Override +- public ApplicationProtocolNegotiator applicationProtocolNegotiator() { +- return apn; +- } +- +- @Override +- public final boolean isClient() { +- return mode == SSL.SSL_MODE_CLIENT; +- } +- +- @Override +- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) { +- return newEngine0(alloc, peerHost, peerPort, true); +- } +- +- @Override +- protected final SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) { +- return new SslHandler(newEngine0(alloc, null, -1, false), startTls); +- } +- +- @Override +- protected final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls) { +- return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), startTls); +- } +- +- @Override +- protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor executor) { +- return new SslHandler(newEngine0(alloc, null, -1, false), startTls, executor); +- } +- +- @Override +- protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, +- boolean startTls, Executor executor) { +- return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), executor); +- } +- +- SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) { +- return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode, true); +- } +- +- /** +- * Returns a new server-side {@link SSLEngine} with the current configuration. +- */ +- @Override +- public final SSLEngine newEngine(ByteBufAllocator alloc) { +- return newEngine(alloc, null, -1); +- } +- +- /** +- * 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(); +- } +- +- /** +- * Returns the stats of this context. +- * +- * @deprecated use {@link #sessionContext#stats()} +- */ +- @Deprecated +- public final OpenSslSessionStats stats() { +- return sessionContext().stats(); +- } +- +- /** +- * {@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"); +- } +- } +- +- /** +- * {@deprecated Renegotiation is not supported} +- * @return {@code true} because renegotiation is not supported. +- */ +- @Deprecated +- public boolean getRejectRemoteInitiatedRenegotiation() { +- return true; +- } +- +- /** +- * 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 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 SSLContext.getSslCtx(ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * 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 { +- SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, method)); +- } finally { +- writerLock.unlock(); +- } +- } +- +- public final void setUseTasks(boolean useTasks) { +- Lock writerLock = ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.setUseTasks(ctx, useTasks); +- } finally { +- writerLock.unlock(); +- } +- } +- +- // 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); +- } +- +- SSLContext.free(ctx); +- ctx = 0; +- +- OpenSslSessionContext context = sessionContext(); +- if (context != null) { +- context.destroy(); +- } +- } +- } finally { +- writerLock.unlock(); +- } +- } +- +- 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; +- } +- +- 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"); +- } +- +- protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) { +- for (KeyManager km : kms) { +- if (km instanceof X509KeyManager) { +- return (X509KeyManager) km; +- } +- } +- throw new IllegalStateException("no X509KeyManager found"); +- } +- +- /** +- * Translate a {@link ApplicationProtocolConfig} object to a +- * {@link OpenSslApplicationProtocolNegotiator} object. +- * +- * @param config The configuration which defines the translation +- * @return The results of the translation +- */ +- @SuppressWarnings("deprecation") +- 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(); +- } +- } +- +- @SuppressJava6Requirement(reason = "Guarded by java version check") +- static boolean useExtendedTrustManager(X509TrustManager trustManager) { +- return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager; +- } +- +- @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); +- } +- +- abstract static class AbstractCertificateVerifier extends CertificateVerifier { +- private final OpenSslEngineMap engineMap; +- +- AbstractCertificateVerifier(OpenSslEngineMap engineMap) { +- this.engineMap = engineMap; +- } +- +- @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; +- } +- 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); +- +- // 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) { +- return translateToError(cause); +- } +- +- // Could not detect a specific error code to use, so fallback to a default code. +- return CertificateVerifier.X509_V_ERR_UNSPECIFIED; +- } +- } +- +- @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; +- } +- +- // 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; +- } +- +- abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, +- String auth) throws Exception; +- } +- +- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap { +- private final Map engines = PlatformDependent.newConcurrentHashMap(); +- +- @Override +- public ReferenceCountedOpenSslEngine remove(long ssl) { +- return engines.remove(ssl); +- } +- +- @Override +- public void add(ReferenceCountedOpenSslEngine engine) { +- engines.put(engine.sslPointer(), engine); +- } +- +- @Override +- public ReferenceCountedOpenSslEngine get(long ssl) { +- return engines.get(ssl); +- } +- } +- +- 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()); +- +- if (key != null) { +- keyBio = toBIO(ByteBufAllocator.DEFAULT, key); +- } +- +- 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(); +- } +- } +- } +- +- static void freeBio(long bio) { +- if (bio != 0) { +- SSL.freeBIO(bio); +- } +- } +- +- /** +- * Return the pointer to a in-memory BIO +- * 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; +- } +- +- PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key); +- try { +- return toBIO(allocator, pem.retain()); +- } finally { +- pem.release(); +- } +- } +- +- /** +- * Return the pointer to a in-memory BIO +- * 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; +- } +- +- if (certChain.length == 0) { +- throw new IllegalArgumentException("certChain can't be empty"); +- } +- +- PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain); +- try { +- return toBIO(allocator, pem.retain()); +- } finally { +- pem.release(); +- } +- } +- +- 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(); +- +- 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 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(); +- } +- } +- +- /** +- * 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. +- */ +- static OpenSslKeyMaterialProvider providerFor(KeyManagerFactory factory, String password) { +- if (factory instanceof OpenSslX509KeyManagerFactory) { +- return ((OpenSslX509KeyManagerFactory) factory).newProvider(); +- } +- +- 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); +- } +- +- 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; +- } +- +- 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 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 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; +- } +- } +- +- 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; +- +-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; +- +-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; +- +-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; +- +-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; +- +-/** +- * Implements a {@link SSLEngine} using +- * OpenSSL BIO abstractions. +- *

Instances of this class must be {@link #release() released} or else native memory will leak! +- * +- *

Instances of this class must 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 { +- +- private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class); +- +- private static final ResourceLeakDetector 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 +- }; +- +- /** +- * 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; +- +- 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); +- +- // 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 +- } +- +- private HandshakeState handshakeState = HandshakeState.NOT_STARTED; +- private boolean receivedShutdown; +- private volatile boolean destroyed; +- private volatile String applicationProtocol; +- private volatile boolean needTask; +- +- // Reference Counting +- private final ResourceLeakTracker leak; +- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { +- @Override +- public ReferenceCounted touch(Object hint) { +- if (leak != null) { +- leak.record(hint); +- } +- +- return ReferenceCountedOpenSslEngine.this; +- } +- +- @Override +- protected void deallocate() { +- shutdown(); +- if (leak != null) { +- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this); +- assert closed; +- } +- parentContext.release(); +- } +- }; +- +- private volatile ClientAuth clientAuth = ClientAuth.NONE; +- private volatile Certificate[] localCertificateChain; +- +- // Updated once a new handshake is started and so the SSLSession reused. +- private volatile long lastAccessed = -1; +- +- private String endPointIdentificationAlgorithm; +- // Store as object as AlgorithmConstraints only exists since java 7. +- private Object algorithmConstraints; +- private List sniHostNames; +- +- // 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; +- +- // SSL Engine status variables +- private boolean isInboundDone; +- private boolean outboundClosed; +- +- 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; +- +- /** +- * 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 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; +- } +- } +- } +- +- @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 algorithmList = new LinkedHashSet(algs.length); +- for (String alg: algs) { +- String converted = SignatureAlgorithmConverter.toJavaName(alg); +- +- if (converted != null) { +- algorithmList.add(converted); +- } +- } +- peerSupportedSignatureAlgorithms = algorithmList.toArray(new String[0]); +- } +- } +- } +- return peerSupportedSignatureAlgorithms.clone(); +- } +- } +- +- @Override +- public List getStatusResponses() { +- byte[] ocspResponse = null; +- if (enableOcsp && clientMode) { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (!isDestroyed()) { +- ocspResponse = SSL.getOcspResponse(ssl); +- } +- } +- } +- return ocspResponse == null ? +- Collections.emptyList() : Collections.singletonList(ocspResponse); +- } +- }; +- } else { +- session = new DefaultOpenSslSession(context.sessionContext()); +- } +- 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; +- } +- +- 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()); +- +- // 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); +- +- if (context.protocols != null) { +- setEnabledProtocols(context.protocols); +- } +- +- // 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); +- } +- +- if (enableOcsp) { +- SSL.enableOcsp(ssl); +- } +- +- if (!jdkCompatibilityMode) { +- SSL.setMode(ssl, SSL.getMode(ssl) | SSL.SSL_MODE_ENABLE_PARTIAL_WRITE); +- } +- +- // 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(); +- +- PlatformDependent.throwException(cause); +- } +- } +- +- // 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); +- } +- +- 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; +- } +- +- final synchronized SecretKeySpec masterKey() { +- if (isDestroyed()) { +- return null; +- } +- return new SecretKeySpec(SSL.getMasterKey(ssl), "AES"); +- } +- +- /** +- * 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); +- } +- } +- } +- +- /** +- * 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 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; +- default: +- return session; +- } +- } +- +- /** +- * 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); +- } +- } finally { +- buf.release(); +- } +- } +- 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, 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); +- +- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false); +- return buf; +- } catch (Throwable cause) { +- buf.release(); +- PlatformDependent.throwException(cause); +- } +- } +- 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, bufferAddress(dst) + pos, dst.limit() - pos); +- if (sslRead > 0) { +- dst.position(pos + sslRead); +- } +- } 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 sslRead; +- } +- +- /** +- * Visible only for testing! +- */ +- final synchronized int maxWrapOverhead() { +- return maxWrapOverhead; +- } +- +- /** +- * Visible only for testing! +- */ +- final synchronized int maxEncryptedPacketLength() { +- return maxEncryptedPacketLength0(); +- } +- +- /** +- * 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; +- } +- +- /** +- * 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); +- } +- +- final synchronized int sslPending() { +- return sslPending0(); +- } +- +- /** +- * It is assumed this method is called in a synchronized block (or the constructor)! +- */ +- private void calculateMaxWrapOverhead() { +- maxWrapOverhead = SSL.getMaxWrapOverhead(ssl); +- +- // 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 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); +- } +- +- private boolean isBytesAvailableEnoughForWrap(int bytesAvailable, int plaintextLength, int numComponents) { +- return bytesAvailable - (long) maxWrapOverhead * numComponents >= plaintextLength; +- } +- +- @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"); +- } +- +- if (offset >= srcs.length || offset + length > srcs.length) { +- throw new IndexOutOfBoundsException( +- "offset: " + offset + ", length: " + length + +- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))"); +- } +- +- 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); +- } +- +- // 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; +- } +- +- // 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); +- } +- } +- +- 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; +- } +- +- 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; +- } +- } +- +- // 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); +- } +- } +- +- // There was no pending data in the network BIO -- encrypt any application data +- int bytesConsumed = 0; +- assert bytesProduced == 0; +- +- // Flush any data that may have been written implicitly by OpenSSL in case a shutdown/alert occurs. +- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); +- +- 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); +- } +- +- for (; offset < endOffset; ++offset) { +- final ByteBuffer src = srcs[offset]; +- final int remaining = src.remaining(); +- if (remaining == 0) { +- continue; +- } +- +- 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)); +- } +- +- // 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; +- +- if (bytesWritten > 0) { +- bytesConsumed += bytesWritten; +- +- 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(); +- +- bytesProduced += bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO); +- +- // 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); +- } +- +- 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); +- } +- } +- } +- 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(); +- } +- } +- } +- } +- +- private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int bytesConsumed, int bytesProduced) { +- return newResult(OK, hs, bytesConsumed, bytesProduced); +- } +- +- 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; +- +- // 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 SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus hs, +- int bytesConsumed, int bytesProduced) throws SSLException { +- return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED), +- bytesConsumed, bytesProduced); +- } +- +- 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); +- } +- +- /** +- * Log the error, shutdown the engine and throw an exception. +- */ +- private SSLException shutdownWithError(String operations, int sslError) { +- return shutdownWithError(operations, sslError, SSL.getLastErrorNumber()); +- } +- +- 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); +- } +- +- // There was an internal error -- shutdown +- shutdown(); +- if (handshakeState == HandshakeState.FINISHED) { +- return new SSLException(errorString); +- } +- +- 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; +- } +- +- 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(); +- } +- +- 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(); +- } +- +- 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); +- } +- } +- } +- +- if (++srcsOffset >= srcsEndOffset) { +- break; +- } +- } finally { +- if (bioWriteCopyBuf != null) { +- bioWriteCopyBuf.release(); +- } +- } +- } +- } finally { +- SSL.bioClearByteBuffer(networkBIO); +- rejectRemoteInitiatedRenegotiation(); +- } +- +- // 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(); +- } +- +- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced); +- } +- } +- +- 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); +- } +- +- private void closeAll() throws SSLException { +- receivedShutdown = true; +- closeOutbound(); +- closeInbound(); +- } +- +- 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"); +- } +- } +- +- public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException { +- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length); +- } +- +- private ByteBuffer[] singleSrcBuffer(ByteBuffer src) { +- singleSrcBuffer[0] = src; +- return singleSrcBuffer; +- } +- +- private void resetSingleSrcBuffer() { +- singleSrcBuffer[0] = null; +- } +- +- private ByteBuffer[] singleDstBuffer(ByteBuffer src) { +- singleDstBuffer[0] = src; +- return singleDstBuffer; +- } +- +- private void resetSingleDstBuffer() { +- singleDstBuffer[0] = null; +- } +- +- @Override +- 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 +- public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException { +- try { +- return wrap(singleSrcBuffer(src), dst); +- } finally { +- resetSingleSrcBuffer(); +- } +- } +- +- @Override +- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException { +- try { +- return unwrap(singleSrcBuffer(src), singleDstBuffer(dst)); +- } finally { +- resetSingleSrcBuffer(); +- resetSingleDstBuffer(); +- } +- } +- +- @Override +- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException { +- try { +- return unwrap(singleSrcBuffer(src), dsts); +- } finally { +- resetSingleSrcBuffer(); +- } +- } +- +- @Override +- 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 +- public final synchronized void closeInbound() throws SSLException { +- if (isInboundDone) { +- return; +- } +- +- isInboundDone = true; +- +- if (isOutboundDone()) { +- // Only call shutdown if there is no outbound data pending. +- // See https://github.com/netty/netty/issues/6167 +- shutdown(); +- } +- +- if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown) { +- throw new SSLException( +- "Inbound closed before receiving peer's close_notify: possible truncation attack?"); +- } +- } +- +- @Override +- public final synchronized boolean isInboundDone() { +- return isInboundDone; +- } +- +- @Override +- public final synchronized void closeOutbound() { +- if (outboundClosed) { +- return; +- } +- +- outboundClosed = true; +- +- 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(); +- } +- } +- +- /** +- * 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; +- } +- SSL.clearError(); +- } +- 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); +- } +- +- @Override +- public final String[] getSupportedCipherSuites() { +- return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[0]); +- } +- +- @Override +- 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; +- } +- } +- if (enabled == null) { +- return EmptyArrays.EMPTY_STRINGS; +- } else { +- Set enabledSet = new LinkedHashSet(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); +- } +- Collections.addAll(enabledSet, extraCiphers); +- } +- return enabledSet.toArray(new String[0]); +- } +- } +- +- @Override +- public final void setEnabledCipherSuites(String[] cipherSuites) { +- checkNotNull(cipherSuites, "cipherSuites"); +- +- final StringBuilder buf = new StringBuilder(); +- final StringBuilder bufTLSv13 = new StringBuilder(); +- +- CipherSuiteConverter.convertToCipherStrings(Arrays.asList(cipherSuites), buf, bufTLSv13, OpenSsl.isBoringSSL()); +- final String cipherSuiteSpec = buf.toString(); +- final String cipherSuiteSpecTLSv13 = bufTLSv13.toString(); +- +- if (!OpenSsl.isTlsv13Supported() && !cipherSuiteSpecTLSv13.isEmpty()) { +- throw new IllegalArgumentException("TLSv1.3 is not supported by this java version."); +- } +- 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); +- +- if (OpenSsl.isTlsv13Supported()) { +- // Set TLSv1.3 ciphers. +- SSL.setCipherSuites(ssl, cipherSuiteSpecTLSv13, true); +- } +- +- } catch (Exception e) { +- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e); +- } +- } else { +- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec); +- } +- } +- } +- +- @Override +- public final String[] getSupportedProtocols() { +- return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[0]); +- } +- +- @Override +- public final String[] getEnabledProtocols() { +- List enabled = new ArrayList(6); +- // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is always enabled +- enabled.add(PROTOCOL_SSL_V2_HELLO); +- +- int opts; +- synchronized (this) { +- if (!isDestroyed()) { +- opts = SSL.getOptions(ssl); +- } else { +- return enabled.toArray(new String[0]); +- } +- } +- 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]); +- } +- +- 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 +- 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); +- +- 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]; +- } +- +- // Disable protocols we do not want +- SSL.setOptions(ssl, opts); +- } else { +- throw new IllegalStateException("failed to enable protocols: " + Arrays.asList(protocols)); +- } +- } +- } +- +- @Override +- public final SSLSession getSession() { +- return session; +- } +- +- @Override +- public final synchronized void beginHandshake() throws SSLException { +- switch (handshakeState) { +- case STARTED_IMPLICITLY: +- checkEngineClosed(); +- +- // 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. +- +- 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(); +- } +- } +- +- private void checkEngineClosed() throws SSLException { +- if (isDestroyed()) { +- throw new SSLException("engine closed"); +- } +- } +- +- 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; +- } +- +- private static boolean isEmpty(Object[] arr) { +- return arr == null || arr.length == 0; +- } +- +- private static boolean isEmpty(byte[] cert) { +- return cert == null || cert.length == 0; +- } +- +- 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; +- } +- +- /** +- * 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); +- } +- } +- +- private SSLEngineResult.HandshakeStatus handshake() throws SSLException { +- if (needTask) { +- return NEED_TASK; +- } +- if (handshakeState == HandshakeState.FINISHED) { +- return FINISHED; +- } +- +- checkEngineClosed(); +- +- 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(); +- } +- +- // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the AbstractCertificateVerifier. +- engineMap.add(this); +- if (lastAccessed == -1) { +- lastAccessed = System.currentTimeMillis(); +- } +- +- 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)); +- } +- +- 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; +- } +- +- // 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(); +- } +- +- // 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; +- } +- +- 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 +- 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; +- } +- +- 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; +- } +- +- private boolean needPendingStatus() { +- return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed() +- && (handshakeState != HandshakeState.FINISHED || isInboundDone() || isOutboundDone()); +- } +- +- /** +- * Converts the specified OpenSSL cipher suite to the Java cipher suite. +- */ +- private String toJavaCipherSuite(String openSslCipherSuite) { +- if (openSslCipherSuite == null) { +- return null; +- } +- +- String version = SSL.getVersion(ssl); +- String prefix = toJavaCipherSuitePrefix(version); +- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix); +- } +- +- /** +- * 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); +- } +- +- switch (c) { +- case 'T': +- return "TLS"; +- case 'S': +- return "SSL"; +- default: +- return "UNKNOWN"; +- } +- } +- +- @Override +- public final void setUseClientMode(boolean clientMode) { +- if (clientMode != this.clientMode) { +- throw new UnsupportedOperationException(); +- } +- } +- +- @Override +- public final boolean getUseClientMode() { +- return clientMode; +- } +- +- @Override +- public final void setNeedClientAuth(boolean b) { +- setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE); +- } +- +- @Override +- public final boolean getNeedClientAuth() { +- return clientAuth == ClientAuth.REQUIRE; +- } +- +- @Override +- public final void setWantClientAuth(boolean b) { +- setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE); +- } +- +- @Override +- public final boolean getWantClientAuth() { +- return clientAuth == ClientAuth.OPTIONAL; +- } +- +- /** +- * See SSL_set_verify 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 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()); +- } +- } +- clientAuth = mode; +- } +- } +- +- @Override +- public final void setEnableSessionCreation(boolean b) { +- if (b) { +- throw new UnsupportedOperationException(); +- } +- } +- +- @Override +- public final boolean getEnableSessionCreation() { +- return false; +- } +- +- @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; +- } +- +- @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."); +- } +- +- boolean isDestroyed = isDestroyed(); +- if (version >= 8) { +- if (!isDestroyed) { +- if (clientMode) { +- final List 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(); +- } +- +- 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); +- } +- +- private static boolean isEndPointVerificationEnabled(String endPointIdentificationAlgorithm) { +- return endPointIdentificationAlgorithm != null && !endPointIdentificationAlgorithm.isEmpty(); +- } +- +- private boolean isDestroyed() { +- return destroyed; +- } +- +- final boolean checkSniHostnameMatch(byte[] hostname) { +- return Java8SslUtils.checkSniHostnameMatch(matchers, hostname); +- } +- +- @Override +- public String getNegotiatedApplicationProtocol() { +- return applicationProtocol; +- } +- +- private static long bufferAddress(ByteBuffer b) { +- assert b.isDirect(); +- if (PlatformDependent.hasUnsafe()) { +- return PlatformDependent.directBufferAddress(b); +- } +- return Buffer.address(b); +- } +- +- private final class DefaultOpenSslSession implements OpenSslSession { +- private final OpenSslSessionContext sessionContext; +- +- // 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 cipher; +- private byte[] id; +- private long creationTime; +- private volatile int applicationBufferSize = MAX_PLAINTEXT_LENGTH; +- +- // lazy init for memory reasons +- private Map values; +- +- DefaultOpenSslSession(OpenSslSessionContext sessionContext) { +- this.sessionContext = sessionContext; +- } +- +- private SSLSessionBindingEvent newSSLSessionBindingEvent(String name) { +- return new SSLSessionBindingEvent(session, name); +- } +- +- @Override +- public byte[] getId() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (id == null) { +- return EmptyArrays.EMPTY_BYTES; +- } +- return id.clone(); +- } +- } +- +- @Override +- public SSLSessionContext getSessionContext() { +- return sessionContext; +- } +- +- @Override +- public long getCreationTime() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (creationTime == 0 && !isDestroyed()) { +- creationTime = SSL.getTime(ssl) * 1000L; +- } +- } +- 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 boolean isValid() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (!isDestroyed()) { +- return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L) < (SSL.getTime(ssl) * 1000L); +- } +- } +- return false; +- } +- +- @Override +- public void putValue(String name, Object value) { +- ObjectUtil.checkNotNull(name, "name"); +- ObjectUtil.checkNotNull(value, "value"); +- +- final Object old; +- synchronized (this) { +- Map values = this.values; +- if (values == null) { +- // Use size of 2 to keep the memory overhead small +- values = this.values = new HashMap(2); +- } +- old = values.put(name, value); +- } +- +- if (value instanceof SSLSessionBindingListener) { +- // Use newSSLSessionBindingEvent so we alway use the wrapper if needed. +- ((SSLSessionBindingListener) value).valueBound(newSSLSessionBindingEvent(name)); +- } +- notifyUnbound(old, name); +- } +- +- @Override +- public Object getValue(String name) { +- ObjectUtil.checkNotNull(name, "name"); +- synchronized (this) { +- if (values == null) { +- return null; +- } +- return values.get(name); +- } +- } +- +- @Override +- public void removeValue(String name) { +- ObjectUtil.checkNotNull(name, "name"); +- +- final Object old; +- synchronized (this) { +- Map values = this.values; +- if (values == null) { +- return; +- } +- old = values.remove(name); +- } +- +- notifyUnbound(old, name); +- } +- +- @Override +- public String[] getValueNames() { +- synchronized (this) { +- Map values = this.values; +- if (values == null || values.isEmpty()) { +- return EmptyArrays.EMPTY_STRINGS; +- } +- return values.keySet().toArray(new String[0]); +- } +- } +- +- 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)); +- } +- } +- +- /** +- * 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); +- +- initPeerCerts(); +- selectApplicationProtocol(); +- calculateMaxWrapOverhead(); +- +- handshakeState = HandshakeState.FINISHED; +- } else { +- throw new SSLException("Already closed"); +- } +- } +- } +- +- /** +- * 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); +- } +- } +- } +- } +- +- 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]); +- } +- } +- +- /** +- * Select the application protocol used. +- */ +- private void selectApplicationProtocol() throws SSLException { +- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior = apn.selectedListenerFailureBehavior(); +- List 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(); +- } +- } +- +- private String selectApplicationProtocol(List 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); +- } +- } +- } +- } +- +- @Override +- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (isEmpty(peerCerts)) { +- throw new SSLPeerUnverifiedException("peer not verified"); +- } +- return peerCerts.clone(); +- } +- } +- +- @Override +- public Certificate[] getLocalCertificates() { +- Certificate[] localCerts = ReferenceCountedOpenSslEngine.this.localCertificateChain; +- if (localCerts == null) { +- return null; +- } +- return localCerts.clone(); +- } +- +- @Override +- public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (isEmpty(x509PeerCerts)) { +- throw new SSLPeerUnverifiedException("peer not verified"); +- } +- return x509PeerCerts.clone(); +- } +- } +- +- @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(); +- } +- +- @Override +- public Principal getLocalPrincipal() { +- Certificate[] local = ReferenceCountedOpenSslEngine.this.localCertificateChain; +- if (local == null || local.length == 0) { +- return null; +- } +- return ((java.security.cert.X509Certificate) local[0]).getIssuerX500Principal(); +- } +- +- @Override +- public String getCipherSuite() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (cipher == null) { +- return SslUtils.INVALID_CIPHER; +- } +- return cipher; +- } +- } +- +- @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; +- } +- } +- } +- return protocol; +- } +- +- @Override +- public String getPeerHost() { +- return ReferenceCountedOpenSslEngine.this.getPeerHost(); +- } +- +- @Override +- public int getPeerPort() { +- return ReferenceCountedOpenSslEngine.this.getPeerPort(); +- } +- +- @Override +- public int getPacketBufferSize() { +- return maxEncryptedPacketLength(); +- } +- +- @Override +- public int getApplicationBufferSize() { +- return applicationBufferSize; +- } +- +- @Override +- public void tryExpandApplicationBufferSize(int packetLengthDataOnly) { +- if (packetLengthDataOnly > MAX_PLAINTEXT_LENGTH && applicationBufferSize != MAX_RECORD_SIZE) { +- applicationBufferSize = MAX_RECORD_SIZE; +- } +- } +- } +-} +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 bac027a3b4..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java ++++ /dev/null +@@ -1,286 +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.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 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.X509ExtendedTrustManager; +-import javax.net.ssl.X509TrustManager; +- +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +- +-/** +- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- *

Instances of this class must be {@link #release() released} or else native memory will leak! +- * +- *

Instances of this class must not 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 static final boolean ENABLE_SESSION_TICKET = +- SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension", false); +- +- ReferenceCountedOpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable 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 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(); +- } +- } +- } +- +- @Override +- public OpenSslServerSessionContext sessionContext() { +- return sessionContext; +- } +- +- 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"); +- +- 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); +- +- 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); +- } +- +- 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 +- +- setVerifyCallback(ctx, engineMap, manager); +- +- 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); +- } +- } +- +- 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); +- } +- +- OpenSslServerSessionContext sessionContext = new OpenSslServerSessionContext(thiz, keyMaterialProvider); +- sessionContext.setSessionIdContext(ID); +- +- keyMaterialProvider = null; +- +- return sessionContext; +- } finally { +- if (keyMaterialProvider != null) { +- keyMaterialProvider.destroy(); +- } +- } +- } +- +- @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)); +- } +- } +- +- private static final class OpenSslServerCertificateCallback implements CertificateCallback { +- private final OpenSslEngineMap engineMap; +- private final OpenSslKeyMaterialManager keyManagerHolder; +- +- OpenSslServerCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) { +- this.engineMap = engineMap; +- this.keyManagerHolder = keyManagerHolder; +- } +- +- @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 { +- // 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); +- } +- } +- } +- +- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier { +- private final X509TrustManager manager; +- +- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) { +- super(engineMap); +- this.manager = manager; +- } +- +- @Override +- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) +- throws Exception { +- manager.checkClientTrusted(peerCerts, auth); +- } +- } +- +- @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 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 { + } + + private static SslProvider defaultProvider() { +- if (OpenSsl.isAvailable()) { +- return SslProvider.OPENSSL; +- } else { +- return SslProvider.JDK; +- } ++ return SslProvider.JDK; + } + + /** +@@ -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; +- } +- +- @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; + + /** + * Returns {@code true} if the specified {@link SslProvider} supports +@@ -45,9 +36,6 @@ public enum SslProvider { + switch (provider) { + case JDK: + return JdkAlpnApplicationProtocolNegotiator.isAlpnSupported(); +- case OPENSSL: +- case OPENSSL_REFCNT: +- return OpenSsl.isAlpnSupported(); + default: + throw new Error("Unknown SslProvider: " + provider); + } +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 c45c50e1e3..0000000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java ++++ /dev/null +@@ -1,61 +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.UnstableApi; +- +-import javax.net.ssl.SSLHandshakeException; +- +-/** +- * 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 final ReferenceCountedOpenSslEngine engine; +- +- protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) { +- this.engine = ObjectUtil.checkNotNull(engine, "engine"); +- } +- +- /** +- * @see ReferenceCountedOpenSslEngine#getOcspResponse() +- */ +- protected abstract boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception; +- +- @Override +- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { +- if (evt instanceof SslHandshakeCompletionEvent) { +- ctx.pipeline().remove(this); +- +- SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt; +- if (event.isSuccess() && !verify(ctx, engine)) { +- throw new SSLHandshakeException("Bad OCSP response"); +- } +- } +- +- 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. +- */ +- +-/** +- * OCSP stapling, +- * 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 @@ + 3.0.0-alpha-5 + + +- +- +- ${project.groupId} +- ${tcnative.artifactId} +- ${tcnative.version} +- ${tcnative.classifier} +- compile +- true +- +- +