The package rpms/netty.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/netty.git/commit/?id=342e6b392cd9....
Change:
-%ifarch %{arm}
Thanks.
Full change:
============
commit 342e6b392cd905be34a8918ca862d2dca9a3dcd8
Author: Mat Booth <mat.booth(a)redhat.com>
Date: Mon Sep 7 14:53:52 2020 +0100
Update to latest upstream version
Native bits were not used by anything, so package is now noarch
diff --git a/.gitignore b/.gitignore
index 859e799..488860d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-/netty-4.0.42.Final.tar.gz
-/netty-4.1.13.Final.tar.gz
+/netty-*.tar.gz
+/*.src.rpm
diff --git a/0001-Remove-optional-dep-Blockhound.patch
b/0001-Remove-optional-dep-Blockhound.patch
new file mode 100644
index 0000000..783b2f8
--- /dev/null
+++ b/0001-Remove-optional-dep-Blockhound.patch
@@ -0,0 +1,633 @@
+From 14fa8d4afda0fa1a31a2591298dc5c18e08dab1f Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 12:17:31 +0100
+Subject: [PATCH 1/5] Remove optional dep Blockhound
+
+---
+ common/pom.xml | 5 -
+ .../java/io/netty/util/internal/Hidden.java | 113 ---------
+ ...ockhound.integration.BlockHoundIntegration | 14 -
+ pom.xml | 7 -
+ transport-blockhound-tests/pom.xml | 92 -------
+ .../NettyBlockHoundIntegrationTest.java | 239 ------------------
+ .../netty/util/internal/localhost_server.key | 28 --
+ .../netty/util/internal/localhost_server.pem | 17 --
+ .../io/netty/util/internal/mutual_auth_ca.pem | 19 --
+ 9 files changed, 534 deletions(-)
+ delete mode 100644 common/src/main/java/io/netty/util/internal/Hidden.java
+ delete mode 100644
common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
+ delete mode 100644 transport-blockhound-tests/pom.xml
+ delete mode 100644
transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
+ delete mode 100644
transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key
+ delete mode 100644
transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem
+ delete mode 100644
transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem
+
+diff --git a/common/pom.xml b/common/pom.xml
+index 706279177a..abc73161eb 100644
+--- a/common/pom.xml
++++ b/common/pom.xml
+@@ -78,11 +78,6 @@
+ <artifactId>log4j-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+- <dependency>
+- <groupId>io.projectreactor.tools</groupId>
+- <artifactId>blockhound</artifactId>
+- <optional>true</optional>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git a/common/src/main/java/io/netty/util/internal/Hidden.java
b/common/src/main/java/io/netty/util/internal/Hidden.java
+deleted file mode 100644
+index 7fd6d08396..0000000000
+--- a/common/src/main/java/io/netty/util/internal/Hidden.java
++++ /dev/null
+@@ -1,113 +0,0 @@
+-/*
+- * Copyright 2019 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-package io.netty.util.internal;
+-
+-import io.netty.util.concurrent.FastThreadLocalThread;
+-import reactor.blockhound.BlockHound;
+-import reactor.blockhound.integration.BlockHoundIntegration;
+-
+-import java.util.function.Function;
+-import java.util.function.Predicate;
+-
+-/**
+- * Contains classes that must be have public visibility but are not public API.
+- */
+-class Hidden {
+-
+- /**
+- * This class integrates Netty with BlockHound.
+- * <p>
+- * It is public but only because of the ServiceLoader's limitations
+- * and SHOULD NOT be considered a public API.
+- */
+- @UnstableApi
+- @SuppressJava6Requirement(reason = "BlockHound is Java 8+, but this class is
only loaded by it's SPI")
+- public static final class NettyBlockHoundIntegration implements
BlockHoundIntegration {
+-
+- @Override
+- public void applyTo(BlockHound.Builder builder) {
+- builder.allowBlockingCallsInside(
+- "io.netty.channel.nio.NioEventLoop",
+- "handleLoopException"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.channel.kqueue.KQueueEventLoop",
+- "handleLoopException"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.channel.epoll.EpollEventLoop",
+- "handleLoopException"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.HashedWheelTimer$Worker",
+- "waitForNextTick"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.SingleThreadEventExecutor",
+- "confirmShutdown"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.handler.ssl.SslHandler",
+- "handshake"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.handler.ssl.SslHandler",
+- "runAllDelegatedTasks"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.GlobalEventExecutor",
+- "takeTask");
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.GlobalEventExecutor",
+- "addTask");
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.SingleThreadEventExecutor",
+- "takeTask");
+-
+- builder.allowBlockingCallsInside(
+-
"io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback",
+- "verify");
+-
+- builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>,
Predicate<Thread>>() {
+- @Override
+- public Predicate<Thread> apply(final Predicate<Thread> p) {
+- return new Predicate<Thread>() {
+- @Override
+- @SuppressJava6Requirement(reason = "Predicate#test")
+- public boolean test(Thread thread) {
+- return p.test(thread) || thread instanceof
FastThreadLocalThread;
+- }
+- };
+- }
+- });
+- }
+-
+- @Override
+- public int compareTo(BlockHoundIntegration o) {
+- return 0;
+- }
+- }
+-}
+diff --git
a/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
b/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
+deleted file mode 100644
+index 5cf376dd8c..0000000000
+---
a/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
++++ /dev/null
+@@ -1,14 +0,0 @@
+-# Copyright 2019 The Netty Project
+-#
+-# The Netty Project licenses this file to you under the Apache License,
+-# version 2.0 (the "License"); you may not use this file except in compliance
+-# with the License. You may obtain a copy of the License at:
+-#
+-#
http://www.apache.org/licenses/LICENSE-2.0
+-#
+-# Unless required by applicable law or agreed to in writing, software
+-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+-# License for the specific language governing permissions and limitations
+-# under the License.
+-io.netty.util.internal.Hidden$NettyBlockHoundIntegration
+\ No newline at end of file
+diff --git a/pom.xml b/pom.xml
+index d00e3e88e0..d548aa5513 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -416,7 +416,6 @@
+ <module>testsuite-osgi</module>
+ <module>testsuite-shading</module>
+ <module>testsuite-native-image</module>
+- <module>transport-blockhound-tests</module>
+ <module>microbench</module>
+ <module>bom</module>
+ </modules>
+@@ -717,12 +716,6 @@
+ <scope>test</scope>
+ </dependency>
+
+- <!-- BlockHound integration -->
+- <dependency>
+- <groupId>io.projectreactor.tools</groupId>
+- <artifactId>blockhound</artifactId>
+- <version>1.0.3.RELEASE</version>
+- </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+diff --git a/transport-blockhound-tests/pom.xml b/transport-blockhound-tests/pom.xml
+deleted file mode 100644
+index 359accd3c4..0000000000
+--- a/transport-blockhound-tests/pom.xml
++++ /dev/null
+@@ -1,92 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<!--
+- ~ Copyright 2019 The Netty Project
+- ~
+- ~ The Netty Project licenses this file to you under the Apache License,
+- ~ version 2.0 (the "License"); you may not use this file except in
compliance
+- ~ with the License. You may obtain a copy of the License at:
+- ~
+- ~
http://www.apache.org/licenses/LICENSE-2.0
+- ~
+- ~ Unless required by applicable law or agreed to in writing, software
+- ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- ~ License for the specific language governing permissions and limitations
+- ~ under the License.
+- -->
+-<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+-
+- <modelVersion>4.0.0</modelVersion>
+- <parent>
+- <groupId>io.netty</groupId>
+- <artifactId>netty-parent</artifactId>
+- <version>4.1.51.Final</version>
+- </parent>
+-
+- <artifactId>netty-transport-blockhound-tests</artifactId>
+- <packaging>jar</packaging>
+- <description>
+- Tests for the BlockHound integration.
+- </description>
+-
+- <name>Netty/Transport/BlockHound/Tests</name>
+-
+- <profiles>
+- <profile>
+- <id>java13</id>
+- <activation>
+- <jdk>13</jdk>
+- </activation>
+- <properties>
+-
<argLine.common>-XX:+AllowRedefinitionToAddDeleteMethods</argLine.common>
+- </properties>
+- </profile>
+- <profile>
+- <id>java14</id>
+- <activation>
+- <jdk>14</jdk>
+- </activation>
+- <properties>
+-
<argLine.common>-XX:+AllowRedefinitionToAddDeleteMethods</argLine.common>
+- </properties>
+- </profile>
+- </profiles>
+-
+- <properties>
+- <maven.compiler.source>1.8</maven.compiler.source>
+- <maven.compiler.target>1.8</maven.compiler.target>
+- <!-- Needed for SelfSignedCertificate -->
+- <argLine.java9.extras>--add-exports
java.base/sun.security.x509=ALL-UNNAMED</argLine.java9.extras>
+- <skipJapicmp>true</skipJapicmp>
+- </properties>
+-
+- <dependencies>
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>netty-transport</artifactId>
+- <version>${project.version}</version>
+- </dependency>
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>netty-handler</artifactId>
+- <version>${project.version}</version>
+- </dependency>
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>${tcnative.artifactId}</artifactId>
+- <classifier>${tcnative.classifier}</classifier>
+- <optional>true</optional>
+- </dependency>
+-
+- <dependency>
+- <groupId>org.bouncycastle</groupId>
+- <artifactId>bcpkix-jdk15on</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>io.projectreactor.tools</groupId>
+- <artifactId>blockhound</artifactId>
+- <scope>test</scope>
+- </dependency>
+- </dependencies>
+-</project>
+diff --git
a/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
b/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
+deleted file mode 100644
+index 58e9284370..0000000000
+---
a/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
++++ /dev/null
+@@ -1,239 +0,0 @@
+-/*
+- * Copyright 2019 The Netty Project
+-
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+-
+- *
http://www.apache.org/licenses/LICENSE-2.0
+-
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal;
+-
+-import io.netty.bootstrap.Bootstrap;
+-import io.netty.bootstrap.ServerBootstrap;
+-import io.netty.buffer.UnpooledByteBufAllocator;
+-import io.netty.channel.Channel;
+-import io.netty.channel.ChannelFuture;
+-import io.netty.channel.ChannelHandlerContext;
+-import io.netty.channel.ChannelInboundHandlerAdapter;
+-import io.netty.channel.ChannelInitializer;
+-import io.netty.channel.EventLoopGroup;
+-import io.netty.channel.nio.NioEventLoopGroup;
+-import io.netty.channel.socket.nio.NioServerSocketChannel;
+-import io.netty.channel.socket.nio.NioSocketChannel;
+-import io.netty.handler.ssl.SslContext;
+-import io.netty.handler.ssl.SslContextBuilder;
+-import io.netty.handler.ssl.SslHandler;
+-import io.netty.handler.ssl.SslHandshakeCompletionEvent;
+-import io.netty.handler.ssl.SslProvider;
+-import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+-import io.netty.handler.ssl.util.SelfSignedCertificate;
+-import io.netty.util.ReferenceCountUtil;
+-import io.netty.util.concurrent.DefaultThreadFactory;
+-import io.netty.util.concurrent.EventExecutor;
+-import io.netty.util.concurrent.GlobalEventExecutor;
+-import io.netty.util.concurrent.ImmediateEventExecutor;
+-import io.netty.util.concurrent.ImmediateExecutor;
+-import io.netty.util.concurrent.ScheduledFuture;
+-import io.netty.util.concurrent.SingleThreadEventExecutor;
+-import io.netty.util.internal.Hidden.NettyBlockHoundIntegration;
+-import org.hamcrest.Matchers;
+-import org.junit.BeforeClass;
+-import org.junit.Test;
+-import reactor.blockhound.BlockHound;
+-import reactor.blockhound.BlockingOperationError;
+-import reactor.blockhound.integration.BlockHoundIntegration;
+-
+-import java.net.InetSocketAddress;
+-import java.util.ServiceLoader;
+-import java.util.concurrent.CountDownLatch;
+-import java.util.concurrent.ExecutionException;
+-import java.util.concurrent.Executor;
+-import java.util.concurrent.ExecutorService;
+-import java.util.concurrent.Executors;
+-import java.util.concurrent.FutureTask;
+-import java.util.concurrent.TimeUnit;
+-
+-import static org.junit.Assert.assertThat;
+-import static org.junit.Assert.assertTrue;
+-import static org.junit.Assert.fail;
+-
+-public class NettyBlockHoundIntegrationTest {
+-
+- @BeforeClass
+- public static void setUpClass() {
+- BlockHound.install();
+- }
+-
+- @Test
+- public void testServiceLoader() {
+- for (BlockHoundIntegration integration :
ServiceLoader.load(BlockHoundIntegration.class)) {
+- if (integration instanceof NettyBlockHoundIntegration) {
+- return;
+- }
+- }
+-
+- fail("NettyBlockHoundIntegration cannot be loaded with
ServiceLoader");
+- }
+-
+- @Test
+- public void testBlockingCallsInNettyThreads() throws Exception {
+- final FutureTask<Void> future = new FutureTask<>(() -> {
+- Thread.sleep(0);
+- return null;
+- });
+- GlobalEventExecutor.INSTANCE.execute(future);
+-
+- try {
+- future.get(5, TimeUnit.SECONDS);
+- fail("Expected an exception due to a blocking call but none was
thrown");
+- } catch (ExecutionException e) {
+- assertThat(e.getCause(),
Matchers.instanceOf(BlockingOperationError.class));
+- }
+- }
+-
+- @Test(timeout = 5000L)
+- public void testGlobalEventExecutorTakeTask() throws InterruptedException {
+- testEventExecutorTakeTask(GlobalEventExecutor.INSTANCE);
+- }
+-
+- @Test(timeout = 5000L)
+- public void testSingleThreadEventExecutorTakeTask() throws InterruptedException {
+- SingleThreadEventExecutor executor =
+- new SingleThreadEventExecutor(null, new
DefaultThreadFactory("test"), true) {
+- @Override
+- protected void run() {
+- while (!confirmShutdown()) {
+- Runnable task = takeTask();
+- if (task != null) {
+- task.run();
+- }
+- }
+- }
+- };
+- testEventExecutorTakeTask(executor);
+- }
+-
+- private static void testEventExecutorTakeTask(EventExecutor eventExecutor) throws
InterruptedException {
+- CountDownLatch latch = new CountDownLatch(1);
+- ScheduledFuture<?> f = eventExecutor.schedule(latch::countDown, 10,
TimeUnit.MILLISECONDS);
+- f.sync();
+- latch.await();
+- }
+-
+- // Tests copied from io.netty.handler.ssl.SslHandlerTest
+- @Test
+- public void testHandshakeWithExecutorThatExecuteDirectory() throws Exception {
+- testHandshakeWithExecutor(Runnable::run);
+- }
+-
+- @Test
+- public void testHandshakeWithImmediateExecutor() throws Exception {
+- testHandshakeWithExecutor(ImmediateExecutor.INSTANCE);
+- }
+-
+- @Test
+- public void testHandshakeWithImmediateEventExecutor() throws Exception {
+- testHandshakeWithExecutor(ImmediateEventExecutor.INSTANCE);
+- }
+-
+- @Test
+- public void testHandshakeWithExecutor() throws Exception {
+- ExecutorService executorService = Executors.newCachedThreadPool();
+- try {
+- testHandshakeWithExecutor(executorService);
+- } finally {
+- executorService.shutdown();
+- }
+- }
+-
+- @Test
+- public void testTrustManagerVerify() throws Exception {
+- final SslContext sslClientCtx =
+- SslContextBuilder.forClient()
+- .trustManager(ResourcesUtil.getFile(getClass(),
"mutual_auth_ca.pem"))
+- .build();
+-
+- final SslContext sslServerCtx =
+- SslContextBuilder.forServer(ResourcesUtil.getFile(getClass(),
"localhost_server.pem"),
+- ResourcesUtil.getFile(getClass(),
"localhost_server.key"),
+- null)
+- .build();
+-
+- final SslHandler clientSslHandler =
sslClientCtx.newHandler(UnpooledByteBufAllocator.DEFAULT);
+- final SslHandler serverSslHandler =
sslServerCtx.newHandler(UnpooledByteBufAllocator.DEFAULT);
+-
+- testHandshake(sslClientCtx, clientSslHandler, serverSslHandler);
+- }
+-
+- private static void testHandshakeWithExecutor(Executor executor) throws Exception {
+- String tlsVersion = "TLSv1.2";
+- final SslContext sslClientCtx = SslContextBuilder.forClient()
+- .trustManager(InsecureTrustManagerFactory.INSTANCE)
+- .sslProvider(SslProvider.JDK).protocols(tlsVersion).build();
+-
+- final SelfSignedCertificate cert = new SelfSignedCertificate();
+- final SslContext sslServerCtx = SslContextBuilder.forServer(cert.key(),
cert.cert())
+- .sslProvider(SslProvider.JDK).protocols(tlsVersion).build();
+-
+- final SslHandler clientSslHandler =
sslClientCtx.newHandler(UnpooledByteBufAllocator.DEFAULT, executor);
+- final SslHandler serverSslHandler =
sslServerCtx.newHandler(UnpooledByteBufAllocator.DEFAULT, executor);
+-
+- testHandshake(sslClientCtx, clientSslHandler, serverSslHandler);
+- }
+-
+- private static void testHandshake(SslContext sslClientCtx, SslHandler
clientSslHandler,
+- SslHandler serverSslHandler) throws Exception {
+- EventLoopGroup group = new NioEventLoopGroup();
+- Channel sc = null;
+- Channel cc = null;
+- try {
+- sc = new ServerBootstrap()
+- .group(group)
+- .channel(NioServerSocketChannel.class)
+- .childHandler(serverSslHandler)
+- .bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
+-
+- ChannelFuture future = new Bootstrap()
+- .group(group)
+- .channel(NioSocketChannel.class)
+- .handler(new ChannelInitializer<Channel>() {
+- @Override
+- protected void initChannel(Channel ch) {
+- ch.pipeline()
+- .addLast(clientSslHandler)
+- .addLast(new ChannelInboundHandlerAdapter() {
+-
+- @Override
+- public void userEventTriggered(ChannelHandlerContext
ctx, Object evt) {
+- if (evt instanceof SslHandshakeCompletionEvent
&&
+- ((SslHandshakeCompletionEvent)
evt).cause() != null) {
+- ((SslHandshakeCompletionEvent)
evt).cause().printStackTrace();
+- }
+- ctx.fireUserEventTriggered(evt);
+- }
+- });
+- }
+- }).connect(sc.localAddress());
+- cc = future.syncUninterruptibly().channel();
+-
+- assertTrue(clientSslHandler.handshakeFuture().await().isSuccess());
+- assertTrue(serverSslHandler.handshakeFuture().await().isSuccess());
+- } finally {
+- if (cc != null) {
+- cc.close().syncUninterruptibly();
+- }
+- if (sc != null) {
+- sc.close().syncUninterruptibly();
+- }
+- group.shutdownGracefully();
+- ReferenceCountUtil.release(sslClientCtx);
+- }
+- }
+-}
+diff --git
a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key
b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key
+deleted file mode 100644
+index 9aa6611400..0000000000
+---
a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key
++++ /dev/null
+@@ -1,28 +0,0 @@
+------BEGIN PRIVATE KEY-----
+-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDYrLtMlZzoe2BP
+-iCURF3So5XNLfsOLcAVERXXjnxqX6Mex55WdJiy6uWTFKbRHWJdbWELdZxVl5+GX
+-pMv3OdkKZt+19ZdSfByv6bB5RNdZOEGnKOHSY2XdnzYnF5JBaWEx0fvtvIPZOUlW
+-DWgsQzJk1UQhu+XnBc7P1hHYNvwsVNOR+HD9LGebDy+UcfiL34XwAyBdHUsbcIr8
+-hltABcj6vNbqOLndpU86DxU9z9b1PDmkFVfisElhpDEhpxmTCwI22Us1GC8D81LM
+-ZzMlbWSzTfNPEuqNzJYGiFt/XPwPkPPyVvti0XWPBQpwzJFFUX5xKsOGERolELRT
+-0yNQYznFAgMBAAECggEAOFR/xSNITbB1k3ejm1PrwlUUqlXkZIXU+LDOO0UL1t5v
+-vDKm1Not2sWECzYSZlID132UtJauG3YzUgdH95gUcv3XvyiAFLOriZhJht181vcn
+-KlwYiWfJ/dn8bCFWpqbM2/TpeB8AcCLSjAqkQI2ftlMziUmeNXdvEt1mej2hRay1
+-ULfoxlC0mftNRQptD5gBFzrc47O4mVpVEQt4yS3Qyzp2/9ds9UkhaCIFpXPVCalZ
+-ds7R+bDDP+wiYTkUcd8fvelaMkD3Wcy8DedGRShhILZvBYTDdWcpJ7+e5EkNlEq4
+-+Ys4Y/u6aFDJD53g3zCaJhatmdAZcct2MMmWH1vewQKBgQD3Y2S245cad1D9AqYD
+-ChZGp95EfRo3EzXk4VkE50bjZXjHq9fD8T0CWEZGWQZrXJCR+vBpEURy0mrPD8se
+-QQ0Q5+I27RadtfPnMd6ry9nDGMPxyd/10vzU6LazzLNE+uf9ljF1RHZu1iDAvInR
+-r1cQGbn/wKBF6BurPPIXABZEuQKBgQDgN6JHbIfDzHKhwEoUTvRrYJsTXqplD+h0
+-Whg+kSQyhtKdlpINFOoEj8FUNJvTjG8les1aoajyWIqikVdvHto/mrxrSIeRkEmt
+-X+KG+5ld2n466tzv1DmVcIGXSrBrH3lA0i6R8Ly26FLSqw0Z12fx5GUUa1qaVRqo
+-rwcrIZovbQKBgHa2mojs9AC+Sv3uvG1u9LuZKJ7jDaZqMI2R2d7xgOH0Op5Ohy6+
+-39D1PVvasqroc3Op4J36rEcRVDHi2Uy+WJ/JNpO2+AhcXRuPodP88ZWel8C6aB+V
+-zL/6oFntnAU5BgR5g2hLny2W0YbLsrMNmhDe15O0AvUo6cYla+K/pu/5AoGACr/g
+-EdiMMcDthf+4DX0zjqpVBPq25J18oYdoPierOpjoJBIB8oqcJZfWxvi2t8+1zHA0
+-xDGX7fZ8vwqEzJkIEaCTg/k4NqxaO+uq6pnJYoyFHMIB0aW1FQsNy3kTOC+MGqV5
+-Ahoukf5VajA1MpX3L8upZO84qsmFu6yYhWLZB4kCgYBlgSD5G4q6rX4ELa3XG61h
+-fDtu75IYEsjWm4vgJzHjeYT2xPIm9OFFYXjPghto0f1oH37ODD3DoXmsnmddgpmn
+-tH7aRWWHsSpB5zVgftV4urNCIsm87LWw8mvUGgCwYV1CtCX8warKokfeoA2ltz4u
+-oeuUzo98hN+aKRU5RO6Bmg==
+------END PRIVATE KEY-----
+diff --git
a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem
b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem
+deleted file mode 100644
+index 70759b29e5..0000000000
+---
a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem
++++ /dev/null
+@@ -1,17 +0,0 @@
+------BEGIN CERTIFICATE-----
+-MIICozCCAYsCAnS/MA0GCSqGSIb3DQEBDQUAMBgxFjAUBgNVBAMTDU5ldHR5VGVz
+-dFJvb3QwIBcNMTcwMjE3MDMzMzQ0WhgPMjExNzAxMjQwMzMzNDRaMBQxEjAQBgNV
+-BAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANis
+-u0yVnOh7YE+IJREXdKjlc0t+w4twBURFdeOfGpfox7HnlZ0mLLq5ZMUptEdYl1tY
+-Qt1nFWXn4Zeky/c52Qpm37X1l1J8HK/psHlE11k4Qaco4dJjZd2fNicXkkFpYTHR
+-++28g9k5SVYNaCxDMmTVRCG75ecFzs/WEdg2/CxU05H4cP0sZ5sPL5Rx+IvfhfAD
+-IF0dSxtwivyGW0AFyPq81uo4ud2lTzoPFT3P1vU8OaQVV+KwSWGkMSGnGZMLAjbZ
+-SzUYLwPzUsxnMyVtZLNN808S6o3MlgaIW39c/A+Q8/JW+2LRdY8FCnDMkUVRfnEq
+-w4YRGiUQtFPTI1BjOcUCAwEAATANBgkqhkiG9w0BAQ0FAAOCAQEAQNXnwE2MJFy5
+-ti07xyi8h/mY0Kl1dwZUqx4F9D9eoxLCq2/p3h/Z18AlOmjdW06pvC2sGtQtyEqL
+-YjuQFbMjXRo9c+6+d+xwdDKTu7+XOTHvznJ8xJpKnFOlohGq/n3efBIJSsaeasTU
+-slFzmdKYABDZzbsQ4X6YCIOF4XVdEQqmXpS+uEbn5C2sVtG+LXI8srmkVGpCcRew
+-SuTGanwxLparhBBeN1ARjKzNxXUWuK2UKZ9p8c7n7TXGhd12ZNTcLhk4rCnOFq1J
+-ySFvP5YL2q29fpEt+Tq0zm3V7An2qtaNDp26cEdevtKPjRyOLkCJx8OlZxc9DZvJ
+-HjalFDoRUw==
+------END CERTIFICATE-----
+diff --git
a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem
b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem
+deleted file mode 100644
+index 9c9241bc65..0000000000
+---
a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem
++++ /dev/null
+@@ -1,19 +0,0 @@
+------BEGIN CERTIFICATE-----
+-MIIDLDCCAhSgAwIBAgIJAO1m5pioZhLLMA0GCSqGSIb3DQEBDQUAMBgxFjAUBgNV
+-BAMTDU5ldHR5VGVzdFJvb3QwHhcNMTcwMjE3MDMzMzQ0WhcNMTcwMzE5MDMzMzQ0
+-WjAYMRYwFAYDVQQDEw1OZXR0eVRlc3RSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
+-AQ8AMIIBCgKCAQEAnC7Y/p/TSWI1KxBKETfFKaRWCPEkoYn5G973WbCF0VDT90PX
+-xK6yHvhqNdDQZPmddgfDAQfjekHeeIFkjCKlvQu0js0G4Bubz4NffNumd/Mgsix8
+-SWJ13lPk+Ly4PDv0bK1zB6BxP1qQm1qxVwsPy9zNP8ylJrM0Div4TXHmnWOfc0JD
+-4/XPpfeUHH1tt/GMtsS2Gx6EpTVPD2w7LDKUza1/rQ7d9sqmFpgsNcI9Db/sAtFP
+-lK2iJku5WIXQkmHimn4bqZ9wkiXJ85pm5ggGQqGMPSbe+2Lh24AvZMIBiwPbkjEU
+-EDFXEJfKOC3Dl71JgWOthtHZ9vcCRDQ3Sky6AQIDAQABo3kwdzAdBgNVHQ4EFgQU
+-qT+cH8qrebiVPpKCBQDB6At2iOAwSAYDVR0jBEEwP4AUqT+cH8qrebiVPpKCBQDB
+-6At2iOChHKQaMBgxFjAUBgNVBAMTDU5ldHR5VGVzdFJvb3SCCQDtZuaYqGYSyzAM
+-BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQCEemXTIew4pR2cHEFpVsW2
+-bLHXLAnC23wBMT46D3tqyxscukMYjFuWosCdEsgRW8d50BXy9o4dHWeg94+aDo3A
+-DX4OTRN/veQGIG7dgM6poDzFuVJlSN0ubKKg6gpDD60IhopZpMviFAOsmzr7OXwS
+-9hjbTqUWujMIEHQ95sPlQFdSaavYSFfqhSltWmVCPSbArxrw0lZ2QcnUqGN47EFp
+-whc5wFB+rSw/ojU1jBLMvgvgzf/8V8zr1IBTDSiHNlknGqGpOOaookzUh95YRiAT
+-hH82y9bBeflqroOeztqMpONpWoZjlz0sWbJNvXztXINL7LaNmVYOcoUrCcxPS54T
+------END CERTIFICATE-----
+--
+2.26.2
+
diff --git a/0002-Remove-NPN-ALPN.patch b/0002-Remove-NPN-ALPN.patch
deleted file mode 100644
index 73749cc..0000000
--- a/0002-Remove-NPN-ALPN.patch
+++ /dev/null
@@ -1,884 +0,0 @@
-From cfb6f2a620525a94d6964c287792f2645bff4f4a Mon Sep 17 00:00:00 2001
-From: Severin Gehwolf <sgehwolf(a)redhat.com>
-Date: Thu, 20 Oct 2016 16:18:10 +0200
-Subject: [PATCH 2/2] Remove NPN ALPN
-
----
- .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 120 ---------
- .../io/netty/handler/ssl/JdkAlpnSslEngine.java | 124 ----------
- .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 ---------
- .../java/io/netty/handler/ssl/JdkNpnSslEngine.java | 122 ---------
- .../java/io/netty/handler/ssl/JdkSslContext.java | 44 ----
- .../io/netty/handler/ssl/JdkSslEngineTest.java | 273 ---------------------
- 6 files changed, 803 deletions(-)
- delete mode 100644
handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
- delete mode 100644
handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
-
-diff --git
a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-deleted file mode 100644
-index aaaf5b7..0000000
----
a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-+++ /dev/null
-@@ -1,120 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.SSLEngine;
--
--/**
-- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using
{@link SslProvider#JDK}.
-- */
--public final class JdkAlpnApplicationProtocolNegotiator extends
JdkBaseApplicationProtocolNegotiator {
-- private static final SslEngineWrapperFactory ALPN_WRAPPER = new
SslEngineWrapperFactory() {
-- {
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw new RuntimeException("ALPN unsupported. Is your classpatch
configured correctly?"
-- + " See
http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn...);
-- }
-- }
--
-- @Override
-- public SSLEngine wrapSslEngine(SSLEngine engine,
JdkApplicationProtocolNegotiator applicationNegotiator,
-- boolean isServer) {
-- return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer);
-- }
-- };
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(Iterable<String> protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(String... protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols
are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols,
Iterable<String> protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols
are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols,
String... protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not
common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not
common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
-- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY :
NO_FAIL_SELECTOR_FACTORY,
-- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY :
NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not
common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not
common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, String... protocols) {
-- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY :
NO_FAIL_SELECTOR_FACTORY,
-- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY :
NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for
selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which
protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory
selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, Iterable<String>
protocols) {
-- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for
selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which
protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory
selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
-- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
-deleted file mode 100644
-index bdf3aca..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
-+++ /dev/null
-@@ -1,124 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
--
--import org.eclipse.jetty.alpn.ALPN;
--import org.eclipse.jetty.alpn.ALPN.ClientProvider;
--import org.eclipse.jetty.alpn.ALPN.ServerProvider;
--
--final class JdkAlpnSslEngine extends JdkSslEngine {
-- private static boolean available;
--
-- static boolean isAvailable() {
-- updateAvailability();
-- return available;
-- }
--
-- private static void updateAvailability() {
-- if (available) {
-- return;
-- }
--
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.ALPNExtension", true, null);
-- available = true;
-- } catch (Exception ignore) {
-- // alpn-boot was not loaded.
-- }
-- }
--
-- JdkAlpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator
applicationNegotiator, boolean server) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
--
-- if (server) {
-- final ProtocolSelector protocolSelector =
checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new
LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- ALPN.put(engine, new ServerProvider() {
-- @Override
-- public String select(List<String> protocols) throws SSLException
{
-- try {
-- return protocolSelector.select(protocols);
-- } catch (SSLHandshakeException e) {
-- throw e;
-- } catch (Throwable t) {
-- SSLHandshakeException e = new
SSLHandshakeException(t.getMessage());
-- e.initCause(t);
-- throw e;
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
-- });
-- } else {
-- final ProtocolSelectionListener protocolListener =
checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this,
applicationNegotiator.protocols()),
-- "protocolListener");
-- ALPN.put(engine, new ClientProvider() {
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void selected(String protocol) throws SSLException {
-- try {
-- protocolListener.selected(protocol);
-- } catch (SSLHandshakeException e) {
-- throw e;
-- } catch (Throwable t) {
-- SSLHandshakeException e = new
SSLHandshakeException(t.getMessage());
-- e.initCause(t);
-- throw e;
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
-- });
-- }
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- ALPN.remove(getWrappedEngine());
-- super.closeInbound();
-- }
--
-- @Override
-- public void closeOutbound() {
-- ALPN.remove(getWrappedEngine());
-- super.closeOutbound();
-- }
--}
-diff --git
a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-deleted file mode 100644
-index c893f05..0000000
----
a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-+++ /dev/null
-@@ -1,120 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.SSLEngine;
--
--/**
-- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using
{@link SslProvider#JDK}.
-- */
--public final class JdkNpnApplicationProtocolNegotiator extends
JdkBaseApplicationProtocolNegotiator {
-- private static final SslEngineWrapperFactory NPN_WRAPPER = new
SslEngineWrapperFactory() {
-- {
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw new RuntimeException("NPN unsupported. Is your classpatch
configured correctly?"
-- + " See
http://www.eclipse.org/jetty/documentation/current/npn-chapter.html#npn-s...);
-- }
-- }
--
-- @Override
-- public SSLEngine wrapSslEngine(SSLEngine engine,
JdkApplicationProtocolNegotiator applicationNegotiator,
-- boolean isServer) {
-- return new JdkNpnSslEngine(engine, applicationNegotiator, isServer);
-- }
-- };
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(Iterable<String> protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(String... protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols
are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols,
Iterable<String> protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols
are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols,
String... protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not
common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not
common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY :
NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY :
NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not
common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not
common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, String... protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY :
NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY :
NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for
selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which
protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, Iterable<String>
protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for
selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which
protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
-deleted file mode 100644
-index 422727a..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
-+++ /dev/null
-@@ -1,122 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--
--package io.netty.handler.ssl;
--
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import io.netty.util.internal.PlatformDependent;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--
--import org.eclipse.jetty.npn.NextProtoNego;
--import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
--import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
--
--final class JdkNpnSslEngine extends JdkSslEngine {
-- private static boolean available;
--
-- static boolean isAvailable() {
-- updateAvailability();
-- return available;
-- }
--
-- private static void updateAvailability() {
-- if (available) {
-- return;
-- }
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.NextProtoNegoExtension", true,
null);
-- available = true;
-- } catch (Exception ignore) {
-- // npn-boot was not loaded.
-- }
-- }
--
-- JdkNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator
applicationNegotiator, boolean server) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
--
-- if (server) {
-- final ProtocolSelectionListener protocolListener =
checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this,
applicationNegotiator.protocols()),
-- "protocolListener");
-- NextProtoNego.put(engine, new ServerProvider() {
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
--
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void protocolSelected(String protocol) {
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- }
-- }
-- });
-- } else {
-- final ProtocolSelector protocolSelector =
checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new
LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- NextProtoNego.put(engine, new ClientProvider() {
-- @Override
-- public boolean supports() {
-- return true;
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
--
-- @Override
-- public String selectProtocol(List<String> protocols) {
-- try {
-- return protocolSelector.select(protocols);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- return null;
-- }
-- }
-- });
-- }
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeInbound();
-- }
--
-- @Override
-- public void closeOutbound() {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeOutbound();
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-index 0a120eb..cdad232 100644
---- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-@@ -270,50 +270,6 @@ public class JdkSslContext extends SslContext {
- switch(config.protocol()) {
- case NONE:
- return JdkDefaultApplicationProtocolNegotiator.INSTANCE;
-- case ALPN:
-- if (isServer) {
-- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true,
config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkAlpnApplicationProtocolNegotiator(false,
config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK
provider does not support ")
-- .append(config.selectorFailureBehavior()).append(" failure
behavior").toString());
-- }
-- } else {
-- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkAlpnApplicationProtocolNegotiator(false,
config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true,
config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK
provider does not support ")
-- .append(config.selectedListenerFailureBehavior()).append("
failure behavior").toString());
-- }
-- }
-- case NPN:
-- if (isServer) {
-- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkNpnApplicationProtocolNegotiator(false,
config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true,
config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK
provider does not support ")
-- .append(config.selectedListenerFailureBehavior()).append("
failure behavior").toString());
-- }
-- } else {
-- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true,
config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkNpnApplicationProtocolNegotiator(false,
config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK
provider does not support ")
-- .append(config.selectorFailureBehavior()).append(" failure
behavior").toString());
-- }
-- }
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK provider
does not support ")
- .append(config.protocol()).append(" protocol").toString());
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index 9a57230..090f996 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -15,262 +15,15 @@
- */
- package io.netty.handler.ssl;
-
--import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectorFactory;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
- import org.junit.Test;
-
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLHandshakeException;
--import java.util.List;
--import java.util.Set;
--import java.util.concurrent.TimeUnit;
--
--import static org.junit.Assert.assertNull;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeNoException;
--
- public class JdkSslEngineTest extends SSLEngineTest {
-- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL =
"my-protocol-http2";
-- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL =
"my-protocol-http1_1";
-- private static final String APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE =
"my-protocol-FOO";
--
-- @Test
-- public void testNpn() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization
error on class load.
-- // Check in this test just in case we have multiple tests that just the
class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig apn = failingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest();
-- } catch (SkipTestException e) {
-- // NPN availability is dependent on the java version. If NPN is not
available because of
-- // java version incompatibility don't fail the test, but instead just
skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testNpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization
error on class load.
-- // Check in this test just in case we have multiple tests that just the
class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- runTest(null);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not
available because of
-- // java version incompatibility don't fail the test, but instead just
skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testNpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization
error on class load.
-- // Check in this test just in case we have multiple tests that just the
class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig clientApn = failingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(clientException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // NPN availability is dependent on the java version. If NPN is not
available because of
-- // java version incompatibility don't fail the test, but instead just
skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testNpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization
error on class load.
-- // Check in this test just in case we have multiple tests that just the
class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.NPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(serverException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // NPN availability is dependent on the java version. If NPN is not
available because of
-- // java version incompatibility don't fail the test, but instead just
skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpn() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization
error on class load.
-- // Check in this test just in case we have multiple tests that just the
class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- ApplicationProtocolConfig apn = failingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest();
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not
available because of
-- // java version incompatibility don't fail the test, but instead just
skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization
error on class load.
-- // Check in this test just in case we have multiple tests that just the
class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- runTest(null);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not
available because of
-- // java version incompatibility don't fail the test, but instead just
skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception
{
-- try {
-- // Typical code will not have to check this, but will get a initialization
error on class load.
-- // Check in this test just in case we have multiple tests that just the
class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(serverException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not
available because of
-- // java version incompatibility don't fail the test, but instead just
skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization
error on class load.
-- // Check in this test just in case we have multiple tests that just the
class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- // Even the preferred application protocol appears second in the
client's list, it will be picked
-- // because it's the first one on server's list.
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- FALLBACK_APPLICATION_LEVEL_PROTOCOL,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL,
FALLBACK_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(serverApn, clientApn);
-- assertNull(serverException);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not
available because of
-- // java version incompatibility don't fail the test, but instead just
skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception
{
-- try {
-- // Typical code will not have to check this, but will get a initialization
error on class load.
-- // Check in this test just in case we have multiple tests that just the
class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- JdkApplicationProtocolNegotiator clientApn = new
JdkAlpnApplicationProtocolNegotiator(true, true,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- JdkApplicationProtocolNegotiator serverApn = new
JdkAlpnApplicationProtocolNegotiator(
-- new ProtocolSelectorFactory() {
-- @Override
-- public ProtocolSelector newSelector(SSLEngine engine,
Set<String> supportedProtocols) {
-- return new ProtocolSelector() {
-- @Override
-- public void unsupported() {
-- }
--
-- @Override
-- public String select(List<String> protocols) {
-- return APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE;
-- }
-- };
-- }
-- },
JdkBaseApplicationProtocolNegotiator.FAIL_SELECTION_LISTENER_FACTORY,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
--
-- SslContext serverSslCtx = new JdkSslServerContext(ssc.certificate(),
ssc.privateKey(), null, null,
-- IdentityCipherSuiteFilter.INSTANCE, serverApn, 0, 0);
-- SslContext clientSslCtx = new JdkSslClientContext(null,
InsecureTrustManagerFactory.INSTANCE, null,
-- IdentityCipherSuiteFilter.INSTANCE, clientApn, 0, 0);
--
-- setupHandlers(serverSslCtx, clientSslCtx);
-- assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(clientException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not
available because of
-- // java version incompatibility don't fail the test, but instead just
skip the test
-- assumeNoException(e);
-- }
-- }
-
- @Test
- public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception {
- testEnablingAnAlreadyDisabledSslProtocol(new String[]{}, new
String[]{PROTOCOL_TLS_V1_2});
- }
-
-- private void runTest() throws Exception {
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
- @Override
- protected SslProvider sslClientProvider() {
- return SslProvider.JDK;
-@@ -280,30 +33,4 @@ public class JdkSslEngineTest extends SSLEngineTest {
- protected SslProvider sslServerProvider() {
- return SslProvider.JDK;
- }
--
-- private ApplicationProtocolConfig failingNegotiator(Protocol protocol,
-- String... supportedProtocols) {
-- return new ApplicationProtocolConfig(protocol,
-- SelectorFailureBehavior.FATAL_ALERT,
-- SelectedListenerFailureBehavior.FATAL_ALERT,
-- supportedProtocols);
-- }
--
-- private ApplicationProtocolConfig acceptingNegotiator(Protocol protocol,
-- String... supportedProtocols)
{
-- return new ApplicationProtocolConfig(protocol,
-- SelectorFailureBehavior.NO_ADVERTISE,
-- SelectedListenerFailureBehavior.ACCEPT,
-- supportedProtocols);
-- }
--
-- private SkipTestException tlsExtensionNotFound(Protocol protocol) {
-- throw new SkipTestException(protocol + " not on classpath");
-- }
--
-- private static final class SkipTestException extends RuntimeException {
-- public SkipTestException(String message) {
-- super(message);
-- }
-- }
- }
---
-2.7.4
-
diff --git a/0002-Remove-NPN.patch b/0002-Remove-NPN.patch
deleted file mode 100644
index 77a340a..0000000
--- a/0002-Remove-NPN.patch
+++ /dev/null
@@ -1,353 +0,0 @@
-From f7b8e27b5f55c4a21cf84fb56a616b8bfd4af8da Mon Sep 17 00:00:00 2001
-From: Michael Simacek <msimacek(a)redhat.com>
-Date: Fri, 7 Jul 2017 16:07:23 +0200
-Subject: [PATCH 2/3] Remove NPN
-
----
- handler/pom.xml | 5 -
- .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 --------------------
- .../java/io/netty/handler/ssl/JdkSslContext.java | 30 -----
- .../io/netty/handler/ssl/JettyNpnSslEngine.java | 122 ---------------------
- .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +-
- 5 files changed, 1 insertion(+), 278 deletions(-)
- delete mode 100644
handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
-
-diff --git a/handler/pom.xml b/handler/pom.xml
-index d0ed1bc..52e63ca 100644
---- a/handler/pom.xml
-+++ b/handler/pom.xml
-@@ -55,11 +55,6 @@
- <optional>true</optional>
- </dependency>
- <dependency>
-- <groupId>org.eclipse.jetty.npn</groupId>
-- <artifactId>npn-api</artifactId>
-- <optional>true</optional>
-- </dependency>
-- <dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
- <optional>true</optional>
-diff --git
a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-deleted file mode 100644
-index 06b29b7..0000000
----
a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-+++ /dev/null
-@@ -1,120 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.SSLEngine;
--
--/**
-- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using
{@link SslProvider#JDK}.
-- */
--public final class JdkNpnApplicationProtocolNegotiator extends
JdkBaseApplicationProtocolNegotiator {
-- private static final SslEngineWrapperFactory NPN_WRAPPER = new
SslEngineWrapperFactory() {
-- {
-- if (!JettyNpnSslEngine.isAvailable()) {
-- throw new RuntimeException("NPN unsupported. Is your classpath
configured correctly?"
-- + " See
https://wiki.eclipse.org/Jetty/Feature/NPN");
-- }
-- }
--
-- @Override
-- public SSLEngine wrapSslEngine(SSLEngine engine,
JdkApplicationProtocolNegotiator applicationNegotiator,
-- boolean isServer) {
-- return new JettyNpnSslEngine(engine, applicationNegotiator, isServer);
-- }
-- };
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(Iterable<String> protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(String... protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols
are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols,
Iterable<String> protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols
are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols,
String... protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not
common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not
common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY :
NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY :
NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not
common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not
common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, String... protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY :
NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY :
NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for
selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which
protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, Iterable<String>
protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for
selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which
protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for
protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-index 0ad6639..d5b86ff 100644
---- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-@@ -288,47 +288,17 @@ public class JdkSslContext extends SslContext {
- case ALPN:
- if (isServer) {
- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true,
config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkAlpnApplicationProtocolNegotiator(false,
config.supportedProtocols());
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK
provider does not support ")
- .append(config.selectorFailureBehavior()).append(" failure
behavior").toString());
- }
- } else {
- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkAlpnApplicationProtocolNegotiator(false,
config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true,
config.supportedProtocols());
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK
provider does not support ")
- .append(config.selectedListenerFailureBehavior()).append("
failure behavior").toString());
- }
- }
-- case NPN:
-- if (isServer) {
-- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkNpnApplicationProtocolNegotiator(false,
config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true,
config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK
provider does not support ")
-- .append(config.selectedListenerFailureBehavior()).append("
failure behavior").toString());
-- }
-- } else {
-- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true,
config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkNpnApplicationProtocolNegotiator(false,
config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK
provider does not support ")
-- .append(config.selectorFailureBehavior()).append(" failure
behavior").toString());
-- }
-- }
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK provider
does not support ")
- .append(config.protocol()).append(" protocol").toString());
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
-deleted file mode 100644
-index 77e7366..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
-+++ /dev/null
-@@ -1,122 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--
--package io.netty.handler.ssl;
--
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import io.netty.util.internal.PlatformDependent;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--
--import org.eclipse.jetty.npn.NextProtoNego;
--import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
--import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
--
--final class JettyNpnSslEngine extends JdkSslEngine {
-- private static boolean available;
--
-- static boolean isAvailable() {
-- updateAvailability();
-- return available;
-- }
--
-- private static void updateAvailability() {
-- if (available) {
-- return;
-- }
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.NextProtoNegoExtension", true,
null);
-- available = true;
-- } catch (Exception ignore) {
-- // npn-boot was not loaded.
-- }
-- }
--
-- JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator
applicationNegotiator, boolean server) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
--
-- if (server) {
-- final ProtocolSelectionListener protocolListener =
checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this,
applicationNegotiator.protocols()),
-- "protocolListener");
-- NextProtoNego.put(engine, new ServerProvider() {
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
--
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void protocolSelected(String protocol) {
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- }
-- }
-- });
-- } else {
-- final ProtocolSelector protocolSelector =
checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new
LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- NextProtoNego.put(engine, new ClientProvider() {
-- @Override
-- public boolean supports() {
-- return true;
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
--
-- @Override
-- public String selectProtocol(List<String> protocols) {
-- try {
-- return protocolSelector.select(protocols);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- return null;
-- }
-- }
-- });
-- }
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeInbound();
-- }
--
-- @Override
-- public void closeOutbound() {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeOutbound();
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index d6cd94d..4489b16 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -46,7 +46,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
- NPN_DEFAULT {
- @Override
- boolean isAvailable() {
-- return JettyNpnSslEngine.isAvailable();
-+ return false;
- }
-
- @Override
---
-2.9.4
-
diff --git a/0002-Remove-optional-dep-conscrypt.patch
b/0002-Remove-optional-dep-conscrypt.patch
new file mode 100644
index 0000000..0a9cfef
--- /dev/null
+++ b/0002-Remove-optional-dep-conscrypt.patch
@@ -0,0 +1,444 @@
+From 1a72454998ec91895648443c176ec41e542903e8 Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 13:24:30 +0100
+Subject: [PATCH 2/5] Remove optional dep conscrypt
+
+---
+ handler/pom.xml | 6 -
+ .../java/io/netty/handler/ssl/Conscrypt.java | 81 --------
+ .../handler/ssl/ConscryptAlpnSslEngine.java | 196 ------------------
+ .../JdkAlpnApplicationProtocolNegotiator.java | 8 +-
+ .../java/io/netty/handler/ssl/SslHandler.java | 47 +----
+ pom.xml | 10 -
+ 6 files changed, 2 insertions(+), 346 deletions(-)
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
+ delete mode 100644
handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
+
+diff --git a/handler/pom.xml b/handler/pom.xml
+index c8e26119bd..378aeda2fe 100644
+--- a/handler/pom.xml
++++ b/handler/pom.xml
+@@ -81,12 +81,6 @@
+ <artifactId>alpn-api</artifactId>
+ <optional>true</optional>
+ </dependency>
+- <dependency>
+- <groupId>${conscrypt.groupId}</groupId>
+- <artifactId>${conscrypt.artifactId}</artifactId>
+- <classifier>${conscrypt.classifier}</classifier>
+- <optional>true</optional>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git a/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
b/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
+deleted file mode 100644
+index d2f015f90f..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
++++ /dev/null
+@@ -1,81 +0,0 @@
+-/*
+- * Copyright 2017 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.util.internal.PlatformDependent;
+-
+-import javax.net.ssl.SSLEngine;
+-import java.lang.reflect.InvocationTargetException;
+-import java.lang.reflect.Method;
+-
+-/**
+- * Contains methods that can be used to detect if conscrypt is usable.
+- */
+-final class Conscrypt {
+- // This class exists to avoid loading other conscrypt related classes using features
only available in JDK8+,
+- // because we need to maintain JDK6+ runtime compatibility.
+- private static final Method IS_CONSCRYPT_SSLENGINE = loadIsConscryptEngine();
+- private static final boolean CAN_INSTANCE_PROVIDER = canInstanceProvider();
+-
+- private static Method loadIsConscryptEngine() {
+- try {
+- Class<?> conscryptClass =
Class.forName("org.conscrypt.Conscrypt", true,
+- ConscryptAlpnSslEngine.class.getClassLoader());
+- return conscryptClass.getMethod("isConscrypt", SSLEngine.class);
+- } catch (Throwable ignore) {
+- // Conscrypt was not loaded.
+- return null;
+- }
+- }
+-
+- private static boolean canInstanceProvider() {
+- try {
+- Class<?> providerClass =
Class.forName("org.conscrypt.OpenSSLProvider", true,
+- ConscryptAlpnSslEngine.class.getClassLoader());
+- providerClass.newInstance();
+- return true;
+- } catch (Throwable ignore) {
+- return false;
+- }
+- }
+-
+- /**
+- * Indicates whether or not conscrypt is available on the current system.
+- */
+- static boolean isAvailable() {
+- return CAN_INSTANCE_PROVIDER && IS_CONSCRYPT_SSLENGINE != null
&&
+- ((PlatformDependent.javaVersion() >= 8 &&
+- // Only works on Java14 and earlier for now
+- // See
https://github.com/google/conscrypt/issues/838
+- PlatformDependent.javaVersion() < 15) ||
PlatformDependent.isAndroid());
+- }
+-
+- static boolean isEngineSupported(SSLEngine engine) {
+- return isAvailable() && isConscryptEngine(engine);
+- }
+-
+- private static boolean isConscryptEngine(SSLEngine engine) {
+- try {
+- return (Boolean) IS_CONSCRYPT_SSLENGINE.invoke(null, engine);
+- } catch (IllegalAccessException ignore) {
+- return false;
+- } catch (InvocationTargetException ex) {
+- throw new RuntimeException(ex);
+- }
+- }
+-
+- private Conscrypt() { }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
+deleted file mode 100644
+index d9767a7106..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
++++ /dev/null
+@@ -1,196 +0,0 @@
+-/*
+- * Copyright 2017 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static java.lang.Math.min;
+-
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-import java.nio.ByteBuffer;
+-import java.util.Collections;
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLEngineResult;
+-import javax.net.ssl.SSLException;
+-
+-import io.netty.util.internal.SystemPropertyUtil;
+-import org.conscrypt.AllocatedBuffer;
+-import org.conscrypt.BufferAllocator;
+-import org.conscrypt.Conscrypt;
+-import org.conscrypt.HandshakeListener;
+-
+-/**
+- * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN.
+- */
+-abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
+- private static final boolean USE_BUFFER_ALLOCATOR = SystemPropertyUtil.getBoolean(
+- "io.netty.handler.ssl.conscrypt.useBufferAllocator", true);
+-
+- static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, ByteBufAllocator
alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ClientEngine(engine, alloc, applicationNegotiator);
+- }
+-
+- static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine, ByteBufAllocator
alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ServerEngine(engine, alloc, applicationNegotiator);
+- }
+-
+- private ConscryptAlpnSslEngine(SSLEngine engine, ByteBufAllocator alloc,
List<String> protocols) {
+- super(engine);
+-
+- // Configure the Conscrypt engine to use Netty's buffer allocator. This is a
trade-off of memory vs
+- // performance.
+- //
+- // If no allocator is provided, the engine will internally allocate a direct
buffer of max packet size in
+- // order to optimize JNI calls (this happens the first time it is provided a
non-direct buffer from the
+- // application).
+- //
+- // Alternatively, if an allocator is provided, no internal buffer will be
created and direct buffers will be
+- // retrieved from the allocator on-demand.
+- if (USE_BUFFER_ALLOCATOR) {
+- Conscrypt.setBufferAllocator(engine, new BufferAllocatorAdapter(alloc));
+- }
+-
+- // Set the list of supported ALPN protocols on the engine.
+- Conscrypt.setApplicationProtocols(engine, protocols.toArray(new String[0]));
+- }
+-
+- /**
+- * Calculates the maximum size of the encrypted output buffer required to wrap the
given plaintext bytes. Assumes
+- * as a worst case that there is one TLS record per buffer.
+- *
+- * @param plaintextBytes the number of plaintext bytes to be wrapped.
+- * @param numBuffers the number of buffers that the plaintext bytes are spread
across.
+- * @return the maximum size of the encrypted output buffer required for the wrap
operation.
+- */
+- final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) {
+- // Assuming a max of one frame per component in a composite buffer.
+- long maxOverhead = (long) Conscrypt.maxSealOverhead(getWrappedEngine()) *
numBuffers;
+- // TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of
Integer.MAX_VALUE
+- return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead);
+- }
+-
+- final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws
SSLException {
+- return Conscrypt.unwrap(getWrappedEngine(), srcs, dests);
+- }
+-
+- private static final class ClientEngine extends ConscryptAlpnSslEngine {
+- private final ProtocolSelectionListener protocolListener;
+-
+- ClientEngine(SSLEngine engine, ByteBufAllocator alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- super(engine, alloc, applicationNegotiator.protocols());
+- // Register for completion of the handshake.
+- Conscrypt.setHandshakeListener(engine, new HandshakeListener() {
+- @Override
+- public void onHandshakeFinished() throws SSLException {
+- selectProtocol();
+- }
+- });
+-
+- protocolListener = checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this,
applicationNegotiator.protocols()),
+- "protocolListener");
+- }
+-
+- private void selectProtocol() throws SSLException {
+- String protocol = Conscrypt.getApplicationProtocol(getWrappedEngine());
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable e) {
+- throw toSSLHandshakeException(e);
+- }
+- }
+- }
+-
+- private static final class ServerEngine extends ConscryptAlpnSslEngine {
+- private final ProtocolSelector protocolSelector;
+-
+- ServerEngine(SSLEngine engine, ByteBufAllocator alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- super(engine, alloc, applicationNegotiator.protocols());
+-
+- // Register for completion of the handshake.
+- Conscrypt.setHandshakeListener(engine, new HandshakeListener() {
+- @Override
+- public void onHandshakeFinished() throws SSLException {
+- selectProtocol();
+- }
+- });
+-
+- protocolSelector =
checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this,
+- new
LinkedHashSet<String>(applicationNegotiator.protocols())),
+- "protocolSelector");
+- }
+-
+- private void selectProtocol() throws SSLException {
+- try {
+- String protocol = Conscrypt.getApplicationProtocol(getWrappedEngine());
+- protocolSelector.select(protocol != null ?
Collections.singletonList(protocol)
+- : Collections.<String>emptyList());
+- } catch (Throwable e) {
+- throw toSSLHandshakeException(e);
+- }
+- }
+- }
+-
+- private static final class BufferAllocatorAdapter extends BufferAllocator {
+- private final ByteBufAllocator alloc;
+-
+- BufferAllocatorAdapter(ByteBufAllocator alloc) {
+- this.alloc = alloc;
+- }
+-
+- @Override
+- public AllocatedBuffer allocateDirectBuffer(int capacity) {
+- return new BufferAdapter(alloc.directBuffer(capacity));
+- }
+- }
+-
+- private static final class BufferAdapter extends AllocatedBuffer {
+- private final ByteBuf nettyBuffer;
+- private final ByteBuffer buffer;
+-
+- BufferAdapter(ByteBuf nettyBuffer) {
+- this.nettyBuffer = nettyBuffer;
+- buffer = nettyBuffer.nioBuffer(0, nettyBuffer.capacity());
+- }
+-
+- @Override
+- public ByteBuffer nioBuffer() {
+- return buffer;
+- }
+-
+- @Override
+- public AllocatedBuffer retain() {
+- nettyBuffer.retain();
+- return this;
+- }
+-
+- @Override
+- public AllocatedBuffer release() {
+- nettyBuffer.release();
+- return this;
+- }
+- }
+-}
+diff --git
a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+index c4ca7b9b8c..2ed83a313b 100644
+---
a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
++++
b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+@@ -26,8 +26,7 @@ import javax.net.ssl.SSLEngine;
+ */
+ @Deprecated
+ public final class JdkAlpnApplicationProtocolNegotiator extends
JdkBaseApplicationProtocolNegotiator {
+- private static final boolean AVAILABLE = Conscrypt.isAvailable() ||
+- JdkAlpnSslUtils.supportsAlpn() ||
++ private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn() ||
+ JettyAlpnSslEngine.isAvailable();
+
+ private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new
AlpnWrapper() : new FailureWrapper();
+@@ -119,7 +118,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends
JdkBaseApplicati
+ public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
+ JdkApplicationProtocolNegotiator
applicationNegotiator, boolean isServer) {
+ throw new RuntimeException("ALPN unsupported. Is your classpath
configured correctly?"
+- + " For Conscrypt, add the appropriate Conscrypt JAR to
classpath and set the security provider."
+ + " For Jetty-ALPN, see "
+ +
"http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-starting");
+ }
+@@ -129,10 +127,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends
JdkBaseApplicati
+ @Override
+ public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
+ JdkApplicationProtocolNegotiator
applicationNegotiator, boolean isServer) {
+- if (Conscrypt.isEngineSupported(engine)) {
+- return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc,
applicationNegotiator)
+- : ConscryptAlpnSslEngine.newClientEngine(engine, alloc,
applicationNegotiator);
+- }
+ // ALPN support was recently backported to Java8 as
+ //
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8230977.
+ // Because of this lets not do a Java version runtime check but just depend
on if the required methods are
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+index de101967ba..8e11bbf4cc 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+@@ -228,50 +228,6 @@ public class SslHandler extends ByteToMessageDecoder implements
ChannelOutboundH
+ return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
+ }
+ },
+- CONSCRYPT(true, COMPOSITE_CUMULATOR) {
+- @Override
+- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int
len, ByteBuf out)
+- throws SSLException {
+- int nioBufferCount = in.nioBufferCount();
+- int writerIndex = out.writerIndex();
+- final SSLEngineResult result;
+- if (nioBufferCount > 1) {
+- /*
+- * Use a special unwrap method without additional memory copies.
+- */
+- try {
+- handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
out.writableBytes());
+- result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
+- in.nioBuffers(readerIndex, len),
+- handler.singleBuffer);
+- } finally {
+- handler.singleBuffer[0] = null;
+- }
+- } else {
+- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
+- toByteBuffer(out, writerIndex, out.writableBytes()));
+- }
+- out.writerIndex(writerIndex + result.bytesProduced());
+- return result;
+- }
+-
+- @Override
+- ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
+- int pendingBytes, int numComponents) {
+- return allocator.directBuffer(
+- ((ConscryptAlpnSslEngine)
handler.engine).calculateOutNetBufSize(pendingBytes, numComponents));
+- }
+-
+- @Override
+- int calculatePendingData(SslHandler handler, int guess) {
+- return guess;
+- }
+-
+- @Override
+- boolean jdkCompatibilityMode(SSLEngine engine) {
+- return true;
+- }
+- },
+ JDK(false, MERGE_CUMULATOR) {
+ @Override
+ SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int
len, ByteBuf out)
+@@ -324,8 +280,7 @@ public class SslHandler extends ByteToMessageDecoder implements
ChannelOutboundH
+ };
+
+ static SslEngineType forEngine(SSLEngine engine) {
+- return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE :
+- engine instanceof ConscryptAlpnSslEngine ? CONSCRYPT : JDK;
++ return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : JDK;
+ }
+
+ SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
+diff --git a/pom.xml b/pom.xml
+index d548aa5513..db3d7b0d38 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -489,16 +489,6 @@
+ <optional>true</optional>
+ </dependency>
+
+- <!-- Conscrypt - needed for running tests, used for acclerating SSL with
OpenSSL. -->
+- <dependency>
+- <groupId>${conscrypt.groupId}</groupId>
+- <artifactId>${conscrypt.artifactId}</artifactId>
+- <classifier>${conscrypt.classifier}</classifier>
+- <version>${conscrypt.version}</version>
+- <scope>compile</scope>
+- <optional>true</optional>
+- </dependency>
+-
+ <!--
+ Bouncy Castle - completely optional, only needed when:
+ - you generate a temporary self-signed certificate using SelfSignedCertificate,
and
+--
+2.26.2
+
diff --git a/0003-Remove-conscrypt-ALPN.patch b/0003-Remove-conscrypt-ALPN.patch
deleted file mode 100644
index e71ba5a..0000000
--- a/0003-Remove-conscrypt-ALPN.patch
+++ /dev/null
@@ -1,511 +0,0 @@
-From 039534e20546221c3466d1ceb663625c59edb0e7 Mon Sep 17 00:00:00 2001
-From: Michael Simacek <msimacek(a)redhat.com>
-Date: Tue, 11 Jul 2017 13:37:22 +0200
-Subject: [PATCH 3/3] Remove conscrypt ALPN
-
----
- handler/pom.xml | 6 -
- .../netty/handler/ssl/ConscryptAlpnSslEngine.java | 176 ---------------------
- .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 6 +-
- .../main/java/io/netty/handler/ssl/SslHandler.java | 35 ----
- .../ssl/ConscryptJdkSslEngineInteropTest.java | 76 ---------
- .../io/netty/handler/ssl/Java8SslTestUtils.java | 7 -
- .../ssl/JdkConscryptSslEngineInteropTest.java | 86 ----------
- .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +-
- 8 files changed, 2 insertions(+), 392 deletions(-)
- delete mode 100644
handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java
-
-diff --git a/handler/pom.xml b/handler/pom.xml
-index 52e63ca..69af32a 100644
---- a/handler/pom.xml
-+++ b/handler/pom.xml
-@@ -60,12 +60,6 @@
- <optional>true</optional>
- </dependency>
- <dependency>
-- <groupId>${conscrypt.groupId}</groupId>
-- <artifactId>${conscrypt.artifactId}</artifactId>
-- <classifier>${conscrypt.classifier}</classifier>
-- <optional>true</optional>
-- </dependency>
-- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-core</artifactId>
- </dependency>
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
-deleted file mode 100644
-index 8e7a544..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
-+++ /dev/null
-@@ -1,176 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import static java.lang.Math.min;
--
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import java.lang.reflect.Method;
--import java.nio.ByteBuffer;
--import java.util.Collections;
--import java.util.LinkedHashSet;
--import java.util.List;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLEngineResult;
--import javax.net.ssl.SSLException;
--
--import io.netty.util.internal.PlatformDependent;
--import org.conscrypt.Conscrypt;
--import org.conscrypt.HandshakeListener;
--
--/**
-- * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN.
-- */
--abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
-- private static final Class<?> ENGINES_CLASS = getEnginesClass();
--
-- /**
-- * Indicates whether or not conscrypt is available on the current system.
-- */
-- static boolean isAvailable() {
-- return ENGINES_CLASS != null && PlatformDependent.javaVersion() >=
8;
-- }
--
-- static boolean isEngineSupported(SSLEngine engine) {
-- return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS);
-- }
--
-- static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ClientEngine(engine, applicationNegotiator);
-- }
--
-- static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ServerEngine(engine, applicationNegotiator);
-- }
--
-- private ConscryptAlpnSslEngine(SSLEngine engine, List<String> protocols) {
-- super(engine);
--
-- // Set the list of supported ALPN protocols on the engine.
-- Conscrypt.Engines.setAlpnProtocols(engine, protocols.toArray(new
String[protocols.size()]));
-- }
--
-- /**
-- * Calculates the maximum size of the encrypted output buffer required to wrap the
given plaintext bytes. Assumes
-- * as a worst case that there is one TLS record per buffer.
-- *
-- * @param plaintextBytes the number of plaintext bytes to be wrapped.
-- * @param numBuffers the number of buffers that the plaintext bytes are spread
across.
-- * @return the maximum size of the encrypted output buffer required for the wrap
operation.
-- */
-- final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) {
-- // Assuming a max of one frame per component in a composite buffer.
-- long maxOverhead = (long) Conscrypt.Engines.maxSealOverhead(getWrappedEngine())
* numBuffers;
-- // TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of
Integer.MAX_VALUE
-- return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead);
-- }
--
-- final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws
SSLException {
-- return Conscrypt.Engines.unwrap(getWrappedEngine(), srcs, dests);
-- }
--
-- private static final class ClientEngine extends ConscryptAlpnSslEngine {
-- private final ProtocolSelectionListener protocolListener;
--
-- ClientEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- super(engine, applicationNegotiator.protocols());
-- // Register for completion of the handshake.
-- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() {
-- @Override
-- public void onHandshakeFinished() throws SSLException {
-- selectProtocol();
-- }
-- });
--
-- protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this,
applicationNegotiator.protocols()),
-- "protocolListener");
-- }
--
-- private void selectProtocol() throws SSLException {
-- String protocol =
Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine());
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable e) {
-- throw toSSLHandshakeException(e);
-- }
-- }
-- }
--
-- private static final class ServerEngine extends ConscryptAlpnSslEngine {
-- private final ProtocolSelector protocolSelector;
--
-- ServerEngine(SSLEngine engine, JdkApplicationProtocolNegotiator
applicationNegotiator) {
-- super(engine, applicationNegotiator.protocols());
--
-- // Register for completion of the handshake.
-- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() {
-- @Override
-- public void onHandshakeFinished() throws SSLException {
-- selectProtocol();
-- }
-- });
--
-- protocolSelector =
checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this,
-- new
LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- }
--
-- private void selectProtocol() throws SSLException {
-- try {
-- String protocol =
Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine());
-- protocolSelector.select(protocol != null ?
Collections.singletonList(protocol)
-- : Collections.<String>emptyList());
-- } catch (Throwable e) {
-- throw toSSLHandshakeException(e);
-- }
-- }
-- }
--
-- private static Class<?> getEnginesClass() {
-- try {
-- // Always use bootstrap class loader.
-- Class<?> engineClass =
Class.forName("org.conscrypt.Conscrypt$Engines", true,
-- ConscryptAlpnSslEngine.class.getClassLoader());
-- // Ensure that it also has the isConscrypt method.
-- getIsConscryptMethod(engineClass);
-- return engineClass;
-- } catch (Throwable ignore) {
-- // Conscrypt was not loaded.
-- return null;
-- }
-- }
--
-- private static boolean isConscryptEngine(SSLEngine engine, Class<?>
enginesClass) {
-- try {
-- Method method = getIsConscryptMethod(enginesClass);
-- return (Boolean) method.invoke(null, engine);
-- } catch (Throwable ignore) {
-- return false;
-- }
-- }
--
-- private static Method getIsConscryptMethod(Class<?> enginesClass) throws
NoSuchMethodException {
-- return enginesClass.getMethod("isConscrypt", SSLEngine.class);
-- }
--}
-diff --git
a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-index f82c7da..9c4ab9e 100644
----
a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-+++
b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine;
- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using
{@link SslProvider#JDK}.
- */
- public final class JdkAlpnApplicationProtocolNegotiator extends
JdkBaseApplicationProtocolNegotiator {
-- private static final boolean AVAILABLE = ConscryptAlpnSslEngine.isAvailable() ||
JettyAlpnSslEngine.isAvailable();
-+ private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable();
- private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new
AlpnWrapper() : new FailureWrapper();
-
- /**
-@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends
JdkBaseApplicati
- @Override
- public SSLEngine wrapSslEngine(SSLEngine engine,
JdkApplicationProtocolNegotiator applicationNegotiator,
- boolean isServer) {
-- if (ConscryptAlpnSslEngine.isEngineSupported(engine)) {
-- return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine,
applicationNegotiator)
-- : ConscryptAlpnSslEngine.newClientEngine(engine,
applicationNegotiator);
-- }
- if (JettyAlpnSslEngine.isAvailable()) {
- return isServer ? JettyAlpnSslEngine.newServerEngine(engine,
applicationNegotiator)
- : JettyAlpnSslEngine.newClientEngine(engine,
applicationNegotiator);
-diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-index 05c451a..8693011 100644
---- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-@@ -187,38 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements
ChannelOutboundH
- new ClosedChannelException(), SslHandler.class,
"channelInactive(...)");
-
- private enum SslEngineType {
-- CONSCRYPT(true, COMPOSITE_CUMULATOR) {
-- @Override
-- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int
len, ByteBuf out)
-- throws SSLException {
-- int nioBufferCount = in.nioBufferCount();
-- int writerIndex = out.writerIndex();
-- final SSLEngineResult result;
-- if (nioBufferCount > 1) {
-- /*
-- * Use a special unwrap method without additional memory copies.
-- */
-- try {
-- handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
out.writableBytes());
-- result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
-- in.nioBuffers(readerIndex, len),
-- handler.singleBuffer);
-- } finally {
-- handler.singleBuffer[0] = null;
-- }
-- } else {
-- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
-- toByteBuffer(out, writerIndex, out.writableBytes()));
-- }
-- out.writerIndex(writerIndex + result.bytesProduced());
-- return result;
-- }
--
-- @Override
-- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int
numComponents) {
-- return ((ConscryptAlpnSslEngine)
handler.engine).calculateOutNetBufSize(pendingBytes, numComponents);
-- }
-- },
- JDK(false, MERGE_CUMULATOR) {
- @Override
- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int
len, ByteBuf out)
-@@ -237,9 +205,6 @@ public class SslHandler extends ByteToMessageDecoder implements
ChannelOutboundH
- };
-
- static SslEngineType forEngine(SSLEngine engine) {
-- if (engine instanceof ConscryptAlpnSslEngine) {
-- return CONSCRYPT;
-- }
- return JDK;
- }
-
-diff --git
a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java
b/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java
-deleted file mode 100644
-index e217136..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java
-+++ /dev/null
-@@ -1,76 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import java.security.Provider;
--import org.junit.BeforeClass;
--import org.junit.Ignore;
--
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class ConscryptJdkSslEngineInteropTest extends SSLEngineTest {
--
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
-- }
-- return params;
-- }
--
-- public ConscryptJdkSslEngineInteropTest(BufferType type) {
-- super(type);
-- }
--
-- @BeforeClass
-- public static void checkConscrypt() {
-- assumeTrue(ConscryptAlpnSslEngine.isAvailable());
-- }
--
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected Provider clientSslContextProvider() {
-- return Java8SslTestUtils.conscryptProvider();
-- }
--
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
-- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws
Exception {
-- }
--
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
-- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws
Exception {
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java
b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java
-index cc2e6c6..f9cf771 100644
---- a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java
-@@ -16,12 +16,9 @@
-
- package io.netty.handler.ssl;
-
--import org.conscrypt.OpenSSLProvider;
--
- import javax.net.ssl.SNIMatcher;
- import javax.net.ssl.SNIServerName;
- import javax.net.ssl.SSLParameters;
--import java.security.Provider;
- import java.util.Collections;
-
- final class Java8SslTestUtils {
-@@ -37,8 +34,4 @@ final class Java8SslTestUtils {
- };
- parameters.setSNIMatchers(Collections.singleton(matcher));
- }
--
-- static Provider conscryptProvider() {
-- return new OpenSSLProvider();
-- }
- }
-diff --git
a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java
b/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java
-deleted file mode 100644
-index 0625f7a..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java
-+++ /dev/null
-@@ -1,86 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import java.security.Provider;
--import org.junit.BeforeClass;
--import org.junit.Ignore;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class JdkConscryptSslEngineInteropTest extends SSLEngineTest {
--
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
-- }
-- return params;
-- }
--
-- public JdkConscryptSslEngineInteropTest(BufferType type) {
-- super(type);
-- }
--
-- @BeforeClass
-- public static void checkConscrypt() {
-- assumeTrue(ConscryptAlpnSslEngine.isAvailable());
-- }
--
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected Provider serverSslContextProvider() {
-- return Java8SslTestUtils.conscryptProvider();
-- }
--
-- @Override
-- @Test
-- @Ignore("TODO: Make this work with Conscrypt")
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws
Exception {
-- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth();
-- }
--
-- @Override
-- @Test
-- @Ignore("TODO: Make this work with Conscrypt")
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws
Exception {
-- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth();
-- }
--
-- @Override
-- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) {
-- // TODO(scott): work around for a JDK issue. The exception should be
SSLHandshakeException.
-- return super.mySetupMutualAuthServerIsValidClientException(cause) ||
causedBySSLException(cause);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index 4489b16..e32fa0d 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -81,7 +81,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
-
- @Override
- boolean isAvailable() {
-- return ConscryptAlpnSslEngine.isAvailable();
-+ return false;
- }
-
- @Override
---
-2.9.4
-
diff --git a/0003-Remove-optional-deps-jetty-alpn-and-npn.patch
b/0003-Remove-optional-deps-jetty-alpn-and-npn.patch
new file mode 100644
index 0000000..6e74960
--- /dev/null
+++ b/0003-Remove-optional-deps-jetty-alpn-and-npn.patch
@@ -0,0 +1,405 @@
+From cb6b51eed1faef580120e19aa1b5404c19a9398b Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 13:26:20 +0100
+Subject: [PATCH 3/5] Remove optional deps jetty alpn and npn
+
+---
+ handler/pom.xml | 10 --
+ .../JdkAlpnApplicationProtocolNegotiator.java | 7 +-
+ .../JdkNpnApplicationProtocolNegotiator.java | 10 +-
+ .../netty/handler/ssl/JettyAlpnSslEngine.java | 157 ------------------
+ .../netty/handler/ssl/JettyNpnSslEngine.java | 122 --------------
+ pom.xml | 14 --
+ 6 files changed, 3 insertions(+), 317 deletions(-)
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
+
+diff --git a/handler/pom.xml b/handler/pom.xml
+index 378aeda2fe..be8206dc89 100644
+--- a/handler/pom.xml
++++ b/handler/pom.xml
+@@ -71,16 +71,6 @@
+ <artifactId>bcpkix-jdk15on</artifactId>
+ <optional>true</optional>
+ </dependency>
+- <dependency>
+- <groupId>org.eclipse.jetty.npn</groupId>
+- <artifactId>npn-api</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>org.eclipse.jetty.alpn</groupId>
+- <artifactId>alpn-api</artifactId>
+- <optional>true</optional>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git
a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+index 2ed83a313b..dbd5ed9f07 100644
+---
a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
++++
b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+@@ -26,8 +26,7 @@ import javax.net.ssl.SSLEngine;
+ */
+ @Deprecated
+ public final class JdkAlpnApplicationProtocolNegotiator extends
JdkBaseApplicationProtocolNegotiator {
+- private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn() ||
+- JettyAlpnSslEngine.isAvailable();
++ private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn();
+
+ private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new
AlpnWrapper() : new FailureWrapper();
+
+@@ -134,10 +133,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends
JdkBaseApplicati
+ if (JdkAlpnSslUtils.supportsAlpn()) {
+ return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer);
+ }
+- if (JettyAlpnSslEngine.isAvailable()) {
+- return isServer ? JettyAlpnSslEngine.newServerEngine(engine,
applicationNegotiator)
+- : JettyAlpnSslEngine.newClientEngine(engine,
applicationNegotiator);
+- }
+ throw new UnsupportedOperationException("ALPN not supported. Unable to
wrap SSLEngine of type '"
+ + engine.getClass().getName() + "')");
+ }
+diff --git
a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
+index 3c2863b66c..2703336e8b 100644
+---
a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
++++
b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
+@@ -25,17 +25,11 @@ import javax.net.ssl.SSLEngine;
+ @Deprecated
+ public final class JdkNpnApplicationProtocolNegotiator extends
JdkBaseApplicationProtocolNegotiator {
+ private static final SslEngineWrapperFactory NPN_WRAPPER = new
SslEngineWrapperFactory() {
+- {
+- if (!JettyNpnSslEngine.isAvailable()) {
+- throw new RuntimeException("NPN unsupported. Is your classpath
configured correctly?"
+- + " See
https://wiki.eclipse.org/Jetty/Feature/NPN");
+- }
+- }
+-
+ @Override
+ public SSLEngine wrapSslEngine(SSLEngine engine,
+ JdkApplicationProtocolNegotiator
applicationNegotiator, boolean isServer) {
+- return new JettyNpnSslEngine(engine, applicationNegotiator, isServer);
++ throw new UnsupportedOperationException("NPN not supported. Unable to
wrap SSLEngine of type '"
++ + engine.getClass().getName() + "')");
+ }
+ };
+
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
+deleted file mode 100644
+index ce9f14a57e..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
++++ /dev/null
+@@ -1,157 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-
+-import io.netty.util.internal.PlatformDependent;
+-import org.eclipse.jetty.alpn.ALPN;
+-
+-abstract class JettyAlpnSslEngine extends JdkSslEngine {
+- private static final boolean available = initAvailable();
+-
+- static boolean isAvailable() {
+- return available;
+- }
+-
+- private static boolean initAvailable() {
+- if (PlatformDependent.javaVersion() <= 8) {
+- try {
+- // Always use bootstrap class loader.
+- Class.forName("sun.security.ssl.ALPNExtension", true, null);
+- return true;
+- } catch (Throwable ignore) {
+- // alpn-boot was not loaded.
+- }
+- }
+- return false;
+- }
+-
+- static JettyAlpnSslEngine newClientEngine(SSLEngine engine,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ClientEngine(engine, applicationNegotiator);
+- }
+-
+- static JettyAlpnSslEngine newServerEngine(SSLEngine engine,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ServerEngine(engine, applicationNegotiator);
+- }
+-
+- private JettyAlpnSslEngine(SSLEngine engine) {
+- super(engine);
+- }
+-
+- private static final class ClientEngine extends JettyAlpnSslEngine {
+- ClientEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator
applicationNegotiator) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+- final ProtocolSelectionListener protocolListener =
checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this,
applicationNegotiator.protocols()),
+- "protocolListener");
+- ALPN.put(engine, new ALPN.ClientProvider() {
+- @Override
+- public List<String> protocols() {
+- return applicationNegotiator.protocols();
+- }
+-
+- @Override
+- public void selected(String protocol) throws SSLException {
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable t) {
+- throw toSSLHandshakeException(t);
+- }
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolListener.unsupported();
+- }
+- });
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeInbound();
+- }
+- }
+-
+- @Override
+- public void closeOutbound() {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeOutbound();
+- }
+- }
+- }
+-
+- private static final class ServerEngine extends JettyAlpnSslEngine {
+- ServerEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator
applicationNegotiator) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+- final ProtocolSelector protocolSelector =
checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this, new
LinkedHashSet<String>(applicationNegotiator.protocols())),
+- "protocolSelector");
+- ALPN.put(engine, new ALPN.ServerProvider() {
+- @Override
+- public String select(List<String> protocols) throws SSLException
{
+- try {
+- return protocolSelector.select(protocols);
+- } catch (Throwable t) {
+- throw toSSLHandshakeException(t);
+- }
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolSelector.unsupported();
+- }
+- });
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeInbound();
+- }
+- }
+-
+- @Override
+- public void closeOutbound() {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeOutbound();
+- }
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
+deleted file mode 100644
+index 77e7366e53..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
++++ /dev/null
+@@ -1,122 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-package io.netty.handler.ssl;
+-
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-import io.netty.util.internal.PlatformDependent;
+-
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-
+-import org.eclipse.jetty.npn.NextProtoNego;
+-import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
+-import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
+-
+-final class JettyNpnSslEngine extends JdkSslEngine {
+- private static boolean available;
+-
+- static boolean isAvailable() {
+- updateAvailability();
+- return available;
+- }
+-
+- private static void updateAvailability() {
+- if (available) {
+- return;
+- }
+- try {
+- // Always use bootstrap class loader.
+- Class.forName("sun.security.ssl.NextProtoNegoExtension", true,
null);
+- available = true;
+- } catch (Exception ignore) {
+- // npn-boot was not loaded.
+- }
+- }
+-
+- JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator
applicationNegotiator, boolean server) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+-
+- if (server) {
+- final ProtocolSelectionListener protocolListener =
checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this,
applicationNegotiator.protocols()),
+- "protocolListener");
+- NextProtoNego.put(engine, new ServerProvider() {
+- @Override
+- public void unsupported() {
+- protocolListener.unsupported();
+- }
+-
+- @Override
+- public List<String> protocols() {
+- return applicationNegotiator.protocols();
+- }
+-
+- @Override
+- public void protocolSelected(String protocol) {
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable t) {
+- PlatformDependent.throwException(t);
+- }
+- }
+- });
+- } else {
+- final ProtocolSelector protocolSelector =
checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this, new
LinkedHashSet<String>(applicationNegotiator.protocols())),
+- "protocolSelector");
+- NextProtoNego.put(engine, new ClientProvider() {
+- @Override
+- public boolean supports() {
+- return true;
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolSelector.unsupported();
+- }
+-
+- @Override
+- public String selectProtocol(List<String> protocols) {
+- try {
+- return protocolSelector.select(protocols);
+- } catch (Throwable t) {
+- PlatformDependent.throwException(t);
+- return null;
+- }
+- }
+- });
+- }
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- NextProtoNego.remove(getWrappedEngine());
+- super.closeInbound();
+- }
+-
+- @Override
+- public void closeOutbound() {
+- NextProtoNego.remove(getWrappedEngine());
+- super.closeOutbound();
+- }
+-}
+diff --git a/pom.xml b/pom.xml
+index db3d7b0d38..bedd6d6903 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -453,20 +453,6 @@
+ <optional>true</optional>
+ </dependency>
+
+- <!-- SPDY and HTTP/2 - completely optional -->
+- <dependency>
+- <groupId>org.eclipse.jetty.npn</groupId>
+- <artifactId>npn-api</artifactId>
+- <version>1.1.1.v20141010</version>
+- <scope>provided</scope> <!-- Provided by npn-boot -->
+- </dependency>
+- <dependency>
+- <groupId>org.eclipse.jetty.alpn</groupId>
+- <artifactId>alpn-api</artifactId>
+- <version>1.1.2.v20150522</version>
+- <scope>provided</scope> <!-- Provided by alpn-boot -->
+- </dependency>
+-
+ <!-- Google Protocol Buffers - completely optional -->
+ <dependency>
+ <groupId>com.google.protobuf</groupId>
+--
+2.26.2
+
diff --git a/0004-Remove-jetty-ALPN.patch b/0004-Remove-jetty-ALPN.patch
deleted file mode 100644
index 42b5415..0000000
--- a/0004-Remove-jetty-ALPN.patch
+++ /dev/null
@@ -1,217 +0,0 @@
-diff --git a/handler/pom.xml b/handler/pom.xml
-index 69af32a..b9e5596 100644
---- a/handler/pom.xml
-+++ b/handler/pom.xml
-@@ -54,11 +54,6 @@
- <artifactId>bcpkix-jdk15on</artifactId>
- <optional>true</optional>
- </dependency>
-- <dependency>
-- <groupId>org.eclipse.jetty.alpn</groupId>
-- <artifactId>alpn-api</artifactId>
-- <optional>true</optional>
-- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-core</artifactId>
-diff --git
a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-index 9c4ab9e..5cc1ab7 100644
----
a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-+++
b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine;
- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using
{@link SslProvider#JDK}.
- */
- public final class JdkAlpnApplicationProtocolNegotiator extends
JdkBaseApplicationProtocolNegotiator {
-- private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable();
-+ private static final boolean AVAILABLE = false;
- private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new
AlpnWrapper() : new FailureWrapper();
-
- /**
-@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends
JdkBaseApplicati
- @Override
- public SSLEngine wrapSslEngine(SSLEngine engine,
JdkApplicationProtocolNegotiator applicationNegotiator,
- boolean isServer) {
-- if (JettyAlpnSslEngine.isAvailable()) {
-- return isServer ? JettyAlpnSslEngine.newServerEngine(engine,
applicationNegotiator)
-- : JettyAlpnSslEngine.newClientEngine(engine,
applicationNegotiator);
-- }
- throw new RuntimeException("Unable to wrap SSLEngine of type " +
engine.getClass().getName());
- }
- }
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
-deleted file mode 100644
-index 624719a..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
-+++ /dev/null
-@@ -1,158 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--
--import io.netty.util.internal.PlatformDependent;
--import org.eclipse.jetty.alpn.ALPN;
--
--abstract class JettyAlpnSslEngine extends JdkSslEngine {
-- private static final boolean available = initAvailable();
--
-- static boolean isAvailable() {
-- return available;
-- }
--
-- private static boolean initAvailable() {
-- // TODO: Add support for ALPN when using Java9 and still be able to configure it
the Netty way.
-- if (PlatformDependent.javaVersion() <= 8) {
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.ALPNExtension", true, null);
-- return true;
-- } catch (Throwable ignore) {
-- // alpn-boot was not loaded.
-- }
-- }
-- return false;
-- }
--
-- static JettyAlpnSslEngine newClientEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ClientEngine(engine, applicationNegotiator);
-- }
--
-- static JettyAlpnSslEngine newServerEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ServerEngine(engine, applicationNegotiator);
-- }
--
-- private JettyAlpnSslEngine(SSLEngine engine) {
-- super(engine);
-- }
--
-- private static final class ClientEngine extends JettyAlpnSslEngine {
-- ClientEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator
applicationNegotiator) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
-- final ProtocolSelectionListener protocolListener =
checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this,
applicationNegotiator.protocols()),
-- "protocolListener");
-- ALPN.put(engine, new ALPN.ClientProvider() {
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void selected(String protocol) throws SSLException {
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable t) {
-- throw toSSLHandshakeException(t);
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
-- });
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeInbound();
-- }
-- }
--
-- @Override
-- public void closeOutbound() {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeOutbound();
-- }
-- }
-- }
--
-- private static final class ServerEngine extends JettyAlpnSslEngine {
-- ServerEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator
applicationNegotiator) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
-- final ProtocolSelector protocolSelector =
checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new
LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- ALPN.put(engine, new ALPN.ServerProvider() {
-- @Override
-- public String select(List<String> protocols) throws SSLException
{
-- try {
-- return protocolSelector.select(protocols);
-- } catch (Throwable t) {
-- throw toSSLHandshakeException(t);
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
-- });
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeInbound();
-- }
-- }
--
-- @Override
-- public void closeOutbound() {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeOutbound();
-- }
-- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index e32fa0d..a8014e5 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -62,7 +62,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
- ALPN_DEFAULT {
- @Override
- boolean isAvailable() {
-- return JettyAlpnSslEngine.isAvailable();
-+ return false;
- }
-
- @Override
diff --git a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch
b/0004-Remove-optional-dep-tcnative.patch
similarity index 54%
rename from 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch
rename to 0004-Remove-optional-dep-tcnative.patch
index aee0650..6ed11bd 100644
--- a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch
+++ b/0004-Remove-optional-dep-tcnative.patch
@@ -1,108 +1,94 @@
-From 39b320920d3473d8cbc94d4a35dad37fa236e278 Mon Sep 17 00:00:00 2001
-From: Severin Gehwolf <sgehwolf(a)redhat.com>
-Date: Thu, 20 Oct 2016 15:54:52 +0200
-Subject: [PATCH 1/3] Remove OpenSSL parts depending on tcnative.
+From c60f3b8d7ca0575bba15682a329dced786f898da Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 13:41:44 +0100
+Subject: [PATCH 4/5] Remove optional dep tcnative
---
- handler/pom.xml | 6 -
- .../main/java/io/netty/handler/ssl/OpenSsl.java | 503 -----
- .../handler/ssl/OpenSslCertificateException.java | 79 -
- .../io/netty/handler/ssl/OpenSslClientContext.java | 211 --
- .../java/io/netty/handler/ssl/OpenSslContext.java | 58 -
- .../java/io/netty/handler/ssl/OpenSslEngine.java | 40 -
- .../io/netty/handler/ssl/OpenSslEngineMap.java | 35 -
- .../ssl/OpenSslExtendedKeyMaterialManager.java | 40 -
- .../handler/ssl/OpenSslKeyMaterialManager.java | 179 --
- .../io/netty/handler/ssl/OpenSslServerContext.java | 373 ----
- .../handler/ssl/OpenSslServerSessionContext.java | 124 --
- .../netty/handler/ssl/OpenSslSessionContext.java | 137 --
- .../io/netty/handler/ssl/OpenSslSessionStats.java | 253 ---
- .../netty/handler/ssl/OpenSslSessionTicketKey.java | 78 -
- .../ssl/ReferenceCountedOpenSslClientContext.java | 298 ---
- .../ssl/ReferenceCountedOpenSslContext.java | 867 ---------
- .../handler/ssl/ReferenceCountedOpenSslEngine.java | 2037 --------------------
- .../ssl/ReferenceCountedOpenSslServerContext.java | 239 ---
- .../main/java/io/netty/handler/ssl/SslContext.java | 30 +-
- .../main/java/io/netty/handler/ssl/SslHandler.java | 47 +-
- .../netty/handler/ssl/ocsp/OcspClientHandler.java | 65 -
- .../io/netty/handler/ssl/ocsp/package-info.java | 23 -
- .../handler/ssl/JdkOpenSslEngineInteroptTest.java | 108 --
- .../ssl/OpenSslCertificateExceptionTest.java | 49 -
- .../handler/ssl/OpenSslClientContextTest.java | 38 -
- .../io/netty/handler/ssl/OpenSslEngineTest.java | 661 -------
- .../ssl/OpenSslJdkSslEngineInteroptTest.java | 114 --
- .../ssl/OpenSslRenegotiateSmallBIOTest.java | 23 -
- .../netty/handler/ssl/OpenSslRenegotiateTest.java | 36 -
- .../handler/ssl/OpenSslServerContextTest.java | 39 -
- .../io/netty/handler/ssl/OpenSslTestUtils.java | 27 -
- .../java/io/netty/handler/ssl/PemEncodedTest.java | 95 -
- .../ssl/ReferenceCountedOpenSslEngineTest.java | 57 -
- .../java/io/netty/handler/ssl/SniClientTest.java | 161 --
- .../java/io/netty/handler/ssl/SniHandlerTest.java | 496 -----
- .../netty/handler/ssl/SslContextBuilderTest.java | 132 --
- .../java/io/netty/handler/ssl/SslErrorTest.java | 255 ---
- .../java/io/netty/handler/ssl/SslHandlerTest.java | 58 +-
- .../java/io/netty/handler/ssl/ocsp/OcspTest.java | 501 -----
- 39 files changed, 10 insertions(+), 8562 deletions(-)
+ handler/pom.xml | 6 -
+ .../handler/ssl/CipherSuiteConverter.java | 494 ----
+ .../ssl/DefaultOpenSslKeyMaterial.java | 126 -
+ .../java/io/netty/handler/ssl/OpenSsl.java | 610 ----
+ .../OpenSslCachingKeyMaterialProvider.java | 79 -
+ .../OpenSslCachingX509KeyManagerFactory.java | 81 -
+ .../ssl/OpenSslCertificateException.java | 81 -
+ .../handler/ssl/OpenSslClientContext.java | 208 --
+ .../io/netty/handler/ssl/OpenSslContext.java | 58 -
+ .../io/netty/handler/ssl/OpenSslEngine.java | 41 -
+ .../netty/handler/ssl/OpenSslEngineMap.java | 35 -
+ .../ssl/OpenSslKeyMaterialManager.java | 127 -
+ .../ssl/OpenSslKeyMaterialProvider.java | 154 -
+ .../netty/handler/ssl/OpenSslPrivateKey.java | 191 --
+ .../handler/ssl/OpenSslPrivateKeyMethod.java | 62 -
+ .../handler/ssl/OpenSslServerContext.java | 367 ---
+ .../ssl/OpenSslServerSessionContext.java | 124 -
+ .../handler/ssl/OpenSslSessionContext.java | 158 --
+ .../handler/ssl/OpenSslSessionStats.java | 253 --
+ .../handler/ssl/OpenSslSessionTicketKey.java | 78 -
+ ...OpenSslTlsv13X509ExtendedTrustManager.java | 240 --
+ .../ssl/OpenSslX509KeyManagerFactory.java | 413 ---
+ .../ReferenceCountedOpenSslClientContext.java | 343 ---
+ .../ssl/ReferenceCountedOpenSslContext.java | 968 -------
+ .../ssl/ReferenceCountedOpenSslEngine.java | 2467 -----------------
+ .../ReferenceCountedOpenSslServerContext.java | 286 --
+ .../java/io/netty/handler/ssl/SslContext.java | 30 +-
+ .../java/io/netty/handler/ssl/SslHandler.java | 49 +-
+ .../handler/ssl/SslMasterKeyHandler.java | 3 -
+ .../io/netty/handler/ssl/SslProvider.java | 14 +-
+ .../handler/ssl/ocsp/OcspClientHandler.java | 61 -
+ .../netty/handler/ssl/ocsp/package-info.java | 23 -
+ pom.xml | 10 -
+ 33 files changed, 3 insertions(+), 8237 deletions(-)
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java
+ delete mode 100644
handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+ delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
+ delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
- delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java
delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
+ delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
+ delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+ delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java
+ delete mode 100644
handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
delete mode 100644
handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
delete mode 100644
handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
delete mode 100644
handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
delete mode 100644
handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
delete mode 100644
handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SniClientTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java
- delete mode 100644
handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
diff --git a/handler/pom.xml b/handler/pom.xml
-index 7535c45..d0ed1bc 100644
+index be8206dc89..e28cc6f7af 100644
--- a/handler/pom.xml
+++ b/handler/pom.xml
-@@ -50,12 +50,6 @@
+@@ -60,12 +60,6 @@
+ <artifactId>netty-codec</artifactId>
<version>${project.version}</version>
</dependency>
- <dependency>
+- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>${tcnative.artifactId}</artifactId>
- <classifier>${tcnative.classifier}</classifier>
- <optional>true</optional>
- </dependency>
-- <dependency>
+ <dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
- <optional>true</optional>
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java
b/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java
deleted file mode 100644
-index d2f091a..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+index 94e951f7f5..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java
+++ /dev/null
-@@ -1,503 +0,0 @@
+@@ -1,494 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -121,499 +107,490 @@ index d2f091a..0000000
-
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBuf;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.ReferenceCountUtil;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.internal.NativeLibraryLoader;
--import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.PlatformDependent;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
--import io.netty.internal.tcnative.Buffer;
--import io.netty.internal.tcnative.Library;
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
-
--import java.security.AccessController;
--import java.security.PrivilegedAction;
-import java.util.Collections;
--import java.util.LinkedHashSet;
--import java.util.Locale;
--import java.util.Set;
+-import java.util.HashMap;
+-import java.util.Map;
+-import java.util.concurrent.ConcurrentMap;
+-import java.util.regex.Matcher;
+-import java.util.regex.Pattern;
+-
+-import static java.util.Collections.singletonMap;
-
-/**
-- * Tells if <a
href="http://netty.io/wiki/forked-tomcat-native.html">{@code
netty-tcnative}</a> and its OpenSSL support
-- * are available.
+- * Converts a Java cipher suite string to an OpenSSL cipher suite string and vice
versa.
+- *
+- * @see <a
href="http://en.wikipedia.org/wiki/Cipher_suite">Wikipedia
page about cipher suite</a>
- */
--public final class OpenSsl {
+-final class CipherSuiteConverter {
-
-- private static final InternalLogger logger =
InternalLoggerFactory.getInstance(OpenSsl.class);
-- private static final String LINUX = "linux";
-- private static final String UNKNOWN = "unknown";
-- private static final Throwable UNAVAILABILITY_CAUSE;
+- private static final InternalLogger logger =
InternalLoggerFactory.getInstance(CipherSuiteConverter.class);
-
-- static final Set<String> AVAILABLE_CIPHER_SUITES;
-- private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES;
-- private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES;
-- private static final boolean SUPPORTS_KEYMANAGER_FACTORY;
-- private static final boolean SUPPORTS_HOSTNAME_VALIDATION;
-- private static final boolean USE_KEYMANAGER_FACTORY;
-- private static final boolean SUPPORTS_OCSP;
+- /**
+- * A_B_WITH_C_D, where:
+- *
+- * A - TLS or SSL (protocol)
+- * B - handshake algorithm (key exchange and authentication algorithms to be
precise)
+- * C - bulk cipher
+- * D - HMAC algorithm
+- *
+- * This regular expression assumes that:
+- *
+- * 1) A is always TLS or SSL, and
+- * 2) D is always a single word.
+- */
+- private static final Pattern JAVA_CIPHERSUITE_PATTERN =
+-
Pattern.compile("^(?:TLS|SSL)_((?:(?!_WITH_).)+)_WITH_(.*)_(.*)$");
+-
+- /**
+- * A-B-C, where:
+- *
+- * A - handshake algorithm (key exchange and authentication algorithms to be
precise)
+- * B - bulk cipher
+- * C - HMAC algorithm
+- *
+- * This regular expression assumes that:
+- *
+- * 1) A has some deterministic pattern as shown below, and
+- * 2) C is always a single word
+- */
+- private static final Pattern OPENSSL_CIPHERSUITE_PATTERN =
+- // Be very careful not to break the indentation while editing.
+- Pattern.compile(
+- "^(?:(" + // BEGIN handshake algorithm
+- "(?:(?:EXP-)?" +
+- "(?:" +
+-
"(?:DHE|EDH|ECDH|ECDHE|SRP|RSA)-(?:DSS|RSA|ECDSA|PSK)|" +
+- "(?:ADH|AECDH|KRB5|PSK|SRP)" +
+- ')' +
+- ")|" +
+- "EXP" +
+- ")-)?" + // END handshake algorithm
+- "(.*)-(.*)$");
+-
+- private static final Pattern JAVA_AES_CBC_PATTERN =
Pattern.compile("^(AES)_([0-9]+)_CBC$");
+- private static final Pattern JAVA_AES_PATTERN =
Pattern.compile("^(AES)_([0-9]+)_(.*)$");
+- private static final Pattern OPENSSL_AES_CBC_PATTERN =
Pattern.compile("^(AES)([0-9]+)$");
+- private static final Pattern OPENSSL_AES_PATTERN =
Pattern.compile("^(AES)([0-9]+)-(.*)$");
-
-- // Protocols
-- static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello";
-- static final String PROTOCOL_SSL_V2 = "SSLv2";
-- static final String PROTOCOL_SSL_V3 = "SSLv3";
-- static final String PROTOCOL_TLS_V1 = "TLSv1";
-- static final String PROTOCOL_TLS_V1_1 = "TLSv1.1";
-- static final String PROTOCOL_TLS_V1_2 = "TLSv1.2";
+- /**
+- * Java-to-OpenSSL cipher suite conversion map
+- * Note that the Java cipher suite has the protocol prefix (TLS_, SSL_)
+- */
+- private static final ConcurrentMap<String, String> j2o =
PlatformDependent.newConcurrentHashMap();
-
-- static final Set<String> SUPPORTED_PROTOCOLS_SET;
+- /**
+- * OpenSSL-to-Java cipher suite conversion map.
+- * Note that one OpenSSL cipher suite can be converted to more than one Java cipher
suites because
+- * a Java cipher suite has the protocol name prefix (TLS_, SSL_)
+- */
+- private static final ConcurrentMap<String, Map<String, String>> o2j =
PlatformDependent.newConcurrentHashMap();
+-
+- private static final Map<String, String> j2oTls13;
+- private static final Map<String, Map<String, String>> o2jTls13;
-
- static {
-- Throwable cause = null;
+- Map<String, String> j2oTls13Map = new HashMap<String, String>();
+- j2oTls13Map.put("TLS_AES_128_GCM_SHA256",
"AEAD-AES128-GCM-SHA256");
+- j2oTls13Map.put("TLS_AES_256_GCM_SHA384",
"AEAD-AES256-GCM-SHA384");
+- j2oTls13Map.put("TLS_CHACHA20_POLY1305_SHA256",
"AEAD-CHACHA20-POLY1305-SHA256");
+- j2oTls13 = Collections.unmodifiableMap(j2oTls13Map);
+-
+- Map<String, Map<String, String>> o2jTls13Map = new
HashMap<String, Map<String, String>>();
+- o2jTls13Map.put("TLS_AES_128_GCM_SHA256",
singletonMap("TLS", "TLS_AES_128_GCM_SHA256"));
+- o2jTls13Map.put("TLS_AES_256_GCM_SHA384",
singletonMap("TLS", "TLS_AES_256_GCM_SHA384"));
+- o2jTls13Map.put("TLS_CHACHA20_POLY1305_SHA256",
singletonMap("TLS", "TLS_CHACHA20_POLY1305_SHA256"));
+- o2jTls13Map.put("AEAD-AES128-GCM-SHA256",
singletonMap("TLS", "TLS_AES_128_GCM_SHA256"));
+- o2jTls13Map.put("AEAD-AES256-GCM-SHA384",
singletonMap("TLS", "TLS_AES_256_GCM_SHA384"));
+- o2jTls13Map.put("AEAD-CHACHA20-POLY1305-SHA256",
singletonMap("TLS", "TLS_CHACHA20_POLY1305_SHA256"));
+- o2jTls13 = Collections.unmodifiableMap(o2jTls13Map);
+- }
-
-- // Test if netty-tcnative is in the classpath first.
-- try {
-- Class.forName("io.netty.internal.tcnative.SSL", false,
OpenSsl.class.getClassLoader());
-- } catch (ClassNotFoundException t) {
-- cause = t;
-- logger.debug(
-- "netty-tcnative not in the classpath; " +
-- OpenSslEngine.class.getSimpleName() + " will be
unavailable.");
+- /**
+- * Clears the cache for testing purpose.
+- */
+- static void clearCache() {
+- j2o.clear();
+- o2j.clear();
+- }
+-
+- /**
+- * Tests if the specified key-value pair has been cached in Java-to-OpenSSL cache.
+- */
+- static boolean isJ2OCached(String key, String value) {
+- return value.equals(j2o.get(key));
+- }
+-
+- /**
+- * Tests if the specified key-value pair has been cached in OpenSSL-to-Java cache.
+- */
+- static boolean isO2JCached(String key, String protocol, String value) {
+- Map<String, String> p2j = o2j.get(key);
+- if (p2j == null) {
+- return false;
+- } else {
+- return value.equals(p2j.get(protocol));
- }
+- }
-
-- // If in the classpath, try to load the native library and initialize
netty-tcnative.
-- if (cause == null) {
-- try {
-- // The JNI library was not already loaded. Load it now.
-- loadTcNative();
-- } catch (Throwable t) {
-- cause = t;
-- logger.debug(
-- "Failed to load netty-tcnative; " +
-- OpenSslEngine.class.getSimpleName() + " will be
unavailable, unless the " +
-- "application has already loaded the symbols by some other
means. " +
-- "See
http://netty.io/wiki/forked-tomcat-native.html for
more information.", t);
-- }
+- /**
+- * Converts the specified Java cipher suite to its corresponding OpenSSL cipher
suite name.
+- *
+- * @return {@code null} if the conversion has failed
+- */
+- static String toOpenSsl(String javaCipherSuite, boolean boringSSL) {
+- String converted = j2o.get(javaCipherSuite);
+- if (converted != null) {
+- return converted;
+- }
+- return cacheFromJava(javaCipherSuite, boringSSL);
+- }
-
-- try {
-- initializeTcNative();
--
-- // The library was initialized successfully. If loading the library
failed above,
-- // reset the cause now since it appears that the library was loaded by
some other
-- // means.
-- cause = null;
-- } catch (Throwable t) {
-- if (cause == null) {
-- cause = t;
-- }
-- logger.debug(
-- "Failed to initialize netty-tcnative; " +
-- OpenSslEngine.class.getSimpleName() + " will be
unavailable. " +
-- "See
http://netty.io/wiki/forked-tomcat-native.html for
more information.", t);
-- }
+- private static String cacheFromJava(String javaCipherSuite, boolean boringSSL) {
+- String converted = j2oTls13.get(javaCipherSuite);
+- if (converted != null) {
+- return boringSSL ? converted : javaCipherSuite;
- }
-
-- UNAVAILABILITY_CAUSE = cause;
+- String openSslCipherSuite = toOpenSslUncached(javaCipherSuite, boringSSL);
+- if (openSslCipherSuite == null) {
+- return null;
+- }
-
-- if (cause == null) {
-- logger.debug("netty-tcnative using native library: {}",
SSL.versionString());
+- // Cache the mapping.
+- j2o.putIfAbsent(javaCipherSuite, openSslCipherSuite);
-
-- final Set<String> availableOpenSslCipherSuites = new
LinkedHashSet<String>(128);
-- boolean supportsKeyManagerFactory = false;
-- boolean useKeyManagerFactory = false;
-- boolean supportsHostNameValidation = false;
-- try {
-- final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL,
SSL.SSL_MODE_SERVER);
-- long certBio = 0;
-- SelfSignedCertificate cert = null;
-- try {
-- SSLContext.setCipherSuite(sslCtx, "ALL");
-- final long ssl = SSL.newSSL(sslCtx, true);
-- try {
-- for (String c: SSL.getCiphers(ssl)) {
-- // Filter out bad input.
-- if (c == null || c.isEmpty() ||
availableOpenSslCipherSuites.contains(c)) {
-- continue;
-- }
-- availableOpenSslCipherSuites.add(c);
-- }
-- try {
-- SSL.setHostNameValidation(ssl, 0, "netty.io");
-- supportsHostNameValidation = true;
-- } catch (Throwable ignore) {
-- logger.debug("Hostname Verification not
supported.");
-- }
-- try {
-- cert = new SelfSignedCertificate();
-- certBio =
ReferenceCountedOpenSslContext.toBIO(cert.cert());
-- SSL.setCertificateChainBio(ssl, certBio, false);
-- supportsKeyManagerFactory = true;
-- try {
-- useKeyManagerFactory = AccessController.doPrivileged(new
PrivilegedAction<Boolean>() {
-- @Override
-- public Boolean run() {
-- return SystemPropertyUtil.getBoolean(
--
"io.netty.handler.ssl.openssl.useKeyManagerFactory", true);
-- }
-- });
-- } catch (Throwable ignore) {
-- logger.debug("Failed to get useKeyManagerFactory
system property.");
-- }
-- } catch (Throwable ignore) {
-- logger.debug("KeyManagerFactory not supported.");
-- }
-- } finally {
-- SSL.freeSSL(ssl);
-- if (certBio != 0) {
-- SSL.freeBIO(certBio);
-- }
-- if (cert != null) {
-- cert.delete();
-- }
-- }
-- } finally {
-- SSLContext.free(sslCtx);
-- }
-- } catch (Exception e) {
-- logger.warn("Failed to get the list of available OpenSSL cipher
suites.", e);
-- }
-- AVAILABLE_OPENSSL_CIPHER_SUITES =
Collections.unmodifiableSet(availableOpenSslCipherSuites);
+- // Cache the reverse mapping after stripping the protocol prefix (TLS_ or SSL_)
+- final String javaCipherSuiteSuffix = javaCipherSuite.substring(4);
+- Map<String, String> p2j = new HashMap<String, String>(4);
+- p2j.put("", javaCipherSuiteSuffix);
+- p2j.put("SSL", "SSL_" + javaCipherSuiteSuffix);
+- p2j.put("TLS", "TLS_" + javaCipherSuiteSuffix);
+- o2j.put(openSslCipherSuite, p2j);
-
-- final Set<String> availableJavaCipherSuites = new
LinkedHashSet<String>(
-- AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
-- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
-- // Included converted but also openssl cipher name
-- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher,
"TLS"));
-- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher,
"SSL"));
-- }
-- AVAILABLE_JAVA_CIPHER_SUITES =
Collections.unmodifiableSet(availableJavaCipherSuites);
+- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuite,
openSslCipherSuite);
-
-- final Set<String> availableCipherSuites = new
LinkedHashSet<String>(
-- AVAILABLE_OPENSSL_CIPHER_SUITES.size() +
AVAILABLE_JAVA_CIPHER_SUITES.size());
-- availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES);
-- availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES);
+- return openSslCipherSuite;
+- }
-
-- AVAILABLE_CIPHER_SUITES = availableCipherSuites;
-- SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory;
-- SUPPORTS_HOSTNAME_VALIDATION = supportsHostNameValidation;
-- USE_KEYMANAGER_FACTORY = useKeyManagerFactory;
+- static String toOpenSslUncached(String javaCipherSuite, boolean boringSSL) {
+- String converted = j2oTls13.get(javaCipherSuite);
+- if (converted != null) {
+- return boringSSL ? converted : javaCipherSuite;
+- }
-
-- Set<String> protocols = new LinkedHashSet<String>(6);
-- // Seems like there is no way to explicitly disable SSLv2Hello in openssl so
it is always enabled
-- protocols.add(PROTOCOL_SSL_V2_HELLO);
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2)) {
-- protocols.add(PROTOCOL_SSL_V2);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3)) {
-- protocols.add(PROTOCOL_SSL_V3);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1)) {
-- protocols.add(PROTOCOL_TLS_V1);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1)) {
-- protocols.add(PROTOCOL_TLS_V1_1);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2)) {
-- protocols.add(PROTOCOL_TLS_V1_2);
-- }
+- Matcher m = JAVA_CIPHERSUITE_PATTERN.matcher(javaCipherSuite);
+- if (!m.matches()) {
+- return null;
+- }
-
-- SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols);
-- SUPPORTS_OCSP = doesSupportOcsp();
+- String handshakeAlgo = toOpenSslHandshakeAlgo(m.group(1));
+- String bulkCipher = toOpenSslBulkCipher(m.group(2));
+- String hmacAlgo = toOpenSslHmacAlgo(m.group(3));
+- if (handshakeAlgo.isEmpty()) {
+- return bulkCipher + '-' + hmacAlgo;
+- } else if (bulkCipher.contains("CHACHA20")) {
+- return handshakeAlgo + '-' + bulkCipher;
- } else {
-- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
-- AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
-- AVAILABLE_CIPHER_SUITES = Collections.emptySet();
-- SUPPORTS_KEYMANAGER_FACTORY = false;
-- SUPPORTS_HOSTNAME_VALIDATION = false;
-- USE_KEYMANAGER_FACTORY = false;
-- SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
-- SUPPORTS_OCSP = false;
+- return handshakeAlgo + '-' + bulkCipher + '-' + hmacAlgo;
- }
- }
-
-- private static boolean doesSupportOcsp() {
-- boolean supportsOcsp = false;
-- if (version() >= 0x10002000L) {
-- long sslCtx = -1;
-- try {
-- sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2,
SSL.SSL_MODE_SERVER);
-- SSLContext.enableOcsp(sslCtx, false);
-- supportsOcsp = true;
-- } catch (Exception ignore) {
-- // ignore
-- } finally {
-- if (sslCtx != -1) {
-- SSLContext.free(sslCtx);
-- }
+- private static String toOpenSslHandshakeAlgo(String handshakeAlgo) {
+- final boolean export = handshakeAlgo.endsWith("_EXPORT");
+- if (export) {
+- handshakeAlgo = handshakeAlgo.substring(0, handshakeAlgo.length() - 7);
+- }
+-
+- if ("RSA".equals(handshakeAlgo)) {
+- handshakeAlgo = "";
+- } else if (handshakeAlgo.endsWith("_anon")) {
+- handshakeAlgo = 'A' + handshakeAlgo.substring(0,
handshakeAlgo.length() - 5);
+- }
+-
+- if (export) {
+- if (handshakeAlgo.isEmpty()) {
+- handshakeAlgo = "EXP";
+- } else {
+- handshakeAlgo = "EXP-" + handshakeAlgo;
- }
- }
-- return supportsOcsp;
+-
+- return handshakeAlgo.replace('_', '-');
- }
-- private static boolean doesSupportProtocol(int protocol) {
-- long sslCtx = -1;
-- try {
-- sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED);
-- return true;
-- } catch (Exception ignore) {
-- return false;
-- } finally {
-- if (sslCtx != -1) {
-- SSLContext.free(sslCtx);
+-
+- private static String toOpenSslBulkCipher(String bulkCipher) {
+- if (bulkCipher.startsWith("AES_")) {
+- Matcher m = JAVA_AES_CBC_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1$2");
+- }
+-
+- m = JAVA_AES_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1$2-$3");
- }
- }
-- }
-
-- /**
-- * Returns {@code true} if and only if
-- * <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code
netty-tcnative}</a> and its OpenSSL support
-- * are available.
-- */
-- public static boolean isAvailable() {
-- return UNAVAILABILITY_CAUSE == null;
-- }
+- if ("3DES_EDE_CBC".equals(bulkCipher)) {
+- return "DES-CBC3";
+- }
-
-- /**
-- * Returns {@code true} if the used version of openssl supports
-- * <a
href="https://tools.ietf.org/html/rfc7301">ALPN</a>.
-- */
-- public static boolean isAlpnSupported() {
-- return version() >= 0x10002000L;
-- }
+- if ("RC4_128".equals(bulkCipher) ||
"RC4_40".equals(bulkCipher)) {
+- return "RC4";
+- }
-
-- /**
-- * Returns {@code true} if the used version of OpenSSL supports OCSP stapling.
-- */
-- public static boolean isOcspSupported() {
-- return SUPPORTS_OCSP;
-- }
+- if ("DES40_CBC".equals(bulkCipher) ||
"DES_CBC_40".equals(bulkCipher)) {
+- return "DES-CBC";
+- }
-
-- /**
-- * Returns the version of the used available OpenSSL library or {@code -1} if {@link
#isAvailable()}
-- * returns {@code false}.
-- */
-- public static int version() {
-- return isAvailable() ? SSL.version() : -1;
+- if ("RC2_CBC_40".equals(bulkCipher)) {
+- return "RC2-CBC";
+- }
+-
+- return bulkCipher.replace('_', '-');
- }
-
-- /**
-- * Returns the version string of the used available OpenSSL library or {@code null}
if {@link #isAvailable()}
-- * returns {@code false}.
-- */
-- public static String versionString() {
-- return isAvailable() ? SSL.versionString() : null;
+- private static String toOpenSslHmacAlgo(String hmacAlgo) {
+- // Java and OpenSSL use the same algorithm names for:
+- //
+- // * SHA
+- // * SHA256
+- // * MD5
+- //
+- return hmacAlgo;
- }
-
- /**
-- * Ensure that <a
href="http://netty.io/wiki/forked-tomcat-native.html">{@code
netty-tcnative}</a> and
-- * its OpenSSL support are available.
-- *
-- * @throws UnsatisfiedLinkError if unavailable
+- * Convert from OpenSSL cipher suite name convention to java cipher suite name
convention.
+- * @param openSslCipherSuite An OpenSSL cipher suite name.
+- * @param protocol The cryptographic protocol (i.e. SSL, TLS, ...).
+- * @return The translated cipher suite name according to java conventions. This will
not be {@code null}.
- */
-- public static void ensureAvailability() {
-- if (UNAVAILABILITY_CAUSE != null) {
-- throw (Error) new UnsatisfiedLinkError(
-- "failed to load the required native
library").initCause(UNAVAILABILITY_CAUSE);
+- static String toJava(String openSslCipherSuite, String protocol) {
+- Map<String, String> p2j = o2j.get(openSslCipherSuite);
+- if (p2j == null) {
+- p2j = cacheFromOpenSsl(openSslCipherSuite);
+- // This may happen if this method is queried when OpenSSL doesn't yet
have a cipher setup. It will return
+- // "(NONE)" in this case.
+- if (p2j == null) {
+- return null;
+- }
+- }
+-
+- String javaCipherSuite = p2j.get(protocol);
+- if (javaCipherSuite == null) {
+- String cipher = p2j.get("");
+- if (cipher == null) {
+- return null;
+- }
+- javaCipherSuite = protocol + '_' + cipher;
- }
+-
+- return javaCipherSuite;
- }
-
-- /**
-- * Returns the cause of unavailability of
-- * <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code
netty-tcnative}</a> and its OpenSSL support.
-- *
-- * @return the cause if unavailable. {@code null} if available.
-- */
-- public static Throwable unavailabilityCause() {
-- return UNAVAILABILITY_CAUSE;
-- }
--
-- /**
-- * @deprecated use {@link #availableOpenSslCipherSuites()}
-- */
-- @Deprecated
-- public static Set<String> availableCipherSuites() {
-- return availableOpenSslCipherSuites();
-- }
+- private static Map<String, String> cacheFromOpenSsl(String openSslCipherSuite)
{
+- Map<String, String> converted = o2jTls13.get(openSslCipherSuite);
+- if (converted != null) {
+- return converted;
+- }
-
-- /**
-- * Returns all the available OpenSSL cipher suites.
-- * Please note that the returned array may include the cipher suites that are
insecure or non-functional.
-- */
-- public static Set<String> availableOpenSslCipherSuites() {
-- return AVAILABLE_OPENSSL_CIPHER_SUITES;
-- }
+- String javaCipherSuiteSuffix = toJavaUncached0(openSslCipherSuite, false);
+- if (javaCipherSuiteSuffix == null) {
+- return null;
+- }
-
-- /**
-- * Returns all the available cipher suites (Java-style).
-- * Please note that the returned array may include the cipher suites that are
insecure or non-functional.
-- */
-- public static Set<String> availableJavaCipherSuites() {
-- return AVAILABLE_JAVA_CIPHER_SUITES;
-- }
+- final String javaCipherSuiteSsl = "SSL_" + javaCipherSuiteSuffix;
+- final String javaCipherSuiteTls = "TLS_" + javaCipherSuiteSuffix;
-
-- /**
-- * Returns {@code true} if and only if the specified cipher suite is available in
OpenSSL.
-- * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted.
-- */
-- public static boolean isCipherSuiteAvailable(String cipherSuite) {
-- String converted = CipherSuiteConverter.toOpenSsl(cipherSuite);
-- if (converted != null) {
-- cipherSuite = converted;
-- }
-- return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite);
-- }
+- // Cache the mapping.
+- final Map<String, String> p2j = new HashMap<String, String>(4);
+- p2j.put("", javaCipherSuiteSuffix);
+- p2j.put("SSL", javaCipherSuiteSsl);
+- p2j.put("TLS", javaCipherSuiteTls);
+- o2j.putIfAbsent(openSslCipherSuite, p2j);
-
-- /**
-- * Returns {@code true} if {@link javax.net.ssl.KeyManagerFactory} is supported when
using OpenSSL.
-- */
-- public static boolean supportsKeyManagerFactory() {
-- return SUPPORTS_KEYMANAGER_FACTORY;
-- }
+- // Cache the reverse mapping after adding the protocol prefix (TLS_ or SSL_)
+- j2o.putIfAbsent(javaCipherSuiteTls, openSslCipherSuite);
+- j2o.putIfAbsent(javaCipherSuiteSsl, openSslCipherSuite);
-
-- /**
-- * Returns {@code true} if <a
href="https://wiki.openssl.org/index.php/Hostname_validation"&g...
Validation</a>
-- * is supported when using OpenSSL.
-- */
-- public static boolean supportsHostnameValidation() {
-- return SUPPORTS_HOSTNAME_VALIDATION;
-- }
+- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteTls,
openSslCipherSuite);
+- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteSsl,
openSslCipherSuite);
-
-- static boolean useKeyManagerFactory() {
-- return USE_KEYMANAGER_FACTORY;
+- return p2j;
- }
-
-- static long memoryAddress(ByteBuf buf) {
-- assert buf.isDirect();
-- return buf.hasMemoryAddress() ? buf.memoryAddress() :
Buffer.address(buf.nioBuffer());
+- static String toJavaUncached(String openSslCipherSuite) {
+- return toJavaUncached0(openSslCipherSuite, true);
- }
-
-- private OpenSsl() { }
+- private static String toJavaUncached0(String openSslCipherSuite, boolean checkTls13)
{
+- if (checkTls13) {
+- Map<String, String> converted = o2jTls13.get(openSslCipherSuite);
+- if (converted != null) {
+- return converted.get("TLS");
+- }
+- }
-
-- private static void loadTcNative() throws Exception {
-- String os = normalizeOs(SystemPropertyUtil.get("os.name",
""));
-- String arch = normalizeArch(SystemPropertyUtil.get("os.arch",
""));
+- Matcher m = OPENSSL_CIPHERSUITE_PATTERN.matcher(openSslCipherSuite);
+- if (!m.matches()) {
+- return null;
+- }
-
-- Set<String> libNames = new LinkedHashSet<String>(4);
-- // First, try loading the platform-specific library. Platform-specific
-- // libraries will be available if using a tcnative uber jar.
-- libNames.add("netty-tcnative-" + os + '-' + arch);
-- if (LINUX.equalsIgnoreCase(os)) {
-- // Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0)..
-- libNames.add("netty-tcnative-" + os + '-' + arch +
"-fedora");
+- String handshakeAlgo = m.group(1);
+- final boolean export;
+- if (handshakeAlgo == null) {
+- handshakeAlgo = "";
+- export = false;
+- } else if (handshakeAlgo.startsWith("EXP-")) {
+- handshakeAlgo = handshakeAlgo.substring(4);
+- export = true;
+- } else if ("EXP".equals(handshakeAlgo)) {
+- handshakeAlgo = "";
+- export = true;
+- } else {
+- export = false;
- }
-- // finally the default library.
-- libNames.add("netty-tcnative");
-- // in Java 8, statically compiled JNI code is namespaced
-- libNames.add("netty_tcnative");
-
-- NativeLibraryLoader.loadFirstAvailable(SSL.class.getClassLoader(),
-- libNames.toArray(new String[libNames.size()]));
-- }
+- handshakeAlgo = toJavaHandshakeAlgo(handshakeAlgo, export);
+- String bulkCipher = toJavaBulkCipher(m.group(2), export);
+- String hmacAlgo = toJavaHmacAlgo(m.group(3));
-
-- private static boolean initializeTcNative() throws Exception {
-- return Library.initialize();
+- String javaCipherSuite = handshakeAlgo + "_WITH_" + bulkCipher +
'_' + hmacAlgo;
+- // For historical reasons the CHACHA20 ciphers do not follow OpenSSL's
custom naming convention and omits the
+- // HMAC algorithm portion of the name. There is currently no way to derive this
information because it is
+- // omitted from the OpenSSL cipher name, but they currently all use SHA256 for
HMAC [1].
+- // [1]
https://www.openssl.org/docs/man1.1.0/apps/ciphers.html
+- return bulkCipher.contains("CHACHA20") ? javaCipherSuite +
"_SHA256" : javaCipherSuite;
- }
-
-- private static String normalizeOs(String value) {
-- value = normalize(value);
-- if (value.startsWith("aix")) {
-- return "aix";
+- private static String toJavaHandshakeAlgo(String handshakeAlgo, boolean export) {
+- if (handshakeAlgo.isEmpty()) {
+- handshakeAlgo = "RSA";
+- } else if ("ADH".equals(handshakeAlgo)) {
+- handshakeAlgo = "DH_anon";
+- } else if ("AECDH".equals(handshakeAlgo)) {
+- handshakeAlgo = "ECDH_anon";
- }
-- if (value.startsWith("hpux")) {
-- return "hpux";
+-
+- handshakeAlgo = handshakeAlgo.replace('-', '_');
+- if (export) {
+- return handshakeAlgo + "_EXPORT";
+- } else {
+- return handshakeAlgo;
- }
-- if (value.startsWith("os400")) {
-- // Avoid the names such as os4000
-- if (value.length() <= 5 || !Character.isDigit(value.charAt(5))) {
-- return "os400";
+- }
+-
+- private static String toJavaBulkCipher(String bulkCipher, boolean export) {
+- if (bulkCipher.startsWith("AES")) {
+- Matcher m = OPENSSL_AES_CBC_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1_$2_CBC");
+- }
+-
+- m = OPENSSL_AES_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1_$2_$3");
- }
- }
-- if (value.startsWith(LINUX)) {
-- return LINUX;
-- }
-- if (value.startsWith("macosx") || value.startsWith("osx"))
{
-- return "osx";
-- }
-- if (value.startsWith("freebsd")) {
-- return "freebsd";
-- }
-- if (value.startsWith("openbsd")) {
-- return "openbsd";
+-
+- if ("DES-CBC3".equals(bulkCipher)) {
+- return "3DES_EDE_CBC";
- }
-- if (value.startsWith("netbsd")) {
-- return "netbsd";
+-
+- if ("RC4".equals(bulkCipher)) {
+- if (export) {
+- return "RC4_40";
+- } else {
+- return "RC4_128";
+- }
- }
-- if (value.startsWith("solaris") ||
value.startsWith("sunos")) {
-- return "sunos";
+-
+- if ("DES-CBC".equals(bulkCipher)) {
+- if (export) {
+- return "DES_CBC_40";
+- } else {
+- return "DES_CBC";
+- }
- }
-- if (value.startsWith("windows")) {
-- return "windows";
+-
+- if ("RC2-CBC".equals(bulkCipher)) {
+- if (export) {
+- return "RC2_CBC_40";
+- } else {
+- return "RC2_CBC";
+- }
- }
-
-- return UNKNOWN;
+- return bulkCipher.replace('-', '_');
- }
-
-- private static String normalizeArch(String value) {
-- value = normalize(value);
-- if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
-- return "x86_64";
-- }
-- if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
-- return "x86_32";
-- }
-- if (value.matches("^(ia64|itanium64)$")) {
-- return "itanium_64";
-- }
-- if (value.matches("^(sparc|sparc32)$")) {
-- return "sparc_32";
-- }
-- if (value.matches("^(sparcv9|sparc64)$")) {
-- return "sparc_64";
-- }
-- if (value.matches("^(arm|arm32)$")) {
-- return "arm_32";
-- }
-- if ("aarch64".equals(value)) {
-- return "aarch_64";
-- }
-- if (value.matches("^(ppc|ppc32)$")) {
-- return "ppc_32";
-- }
-- if ("ppc64".equals(value)) {
-- return "ppc_64";
+- private static String toJavaHmacAlgo(String hmacAlgo) {
+- // Java and OpenSSL use the same algorithm names for:
+- //
+- // * SHA
+- // * SHA256
+- // * MD5
+- //
+- return hmacAlgo;
+- }
+-
+- /**
+- * Convert the given ciphers if needed to OpenSSL format and append them to the
correct {@link StringBuilder}
+- * depending on if its a TLSv1.3 cipher or not. If this methods returns without
throwing an exception its
+- * guaranteed that at least one of the {@link StringBuilder}s contain some ciphers
that can be used to configure
+- * OpenSSL.
+- */
+- static void convertToCipherStrings(Iterable<String> cipherSuites,
StringBuilder cipherBuilder,
+- StringBuilder cipherTLSv13Builder, boolean
boringSSL) {
+- for (String c: cipherSuites) {
+- if (c == null) {
+- break;
+- }
+-
+- String converted = toOpenSsl(c, boringSSL);
+- if (converted == null) {
+- converted = c;
+- }
+-
+- if (!OpenSsl.isCipherSuiteAvailable(converted)) {
+- throw new IllegalArgumentException("unsupported cipher suite:
" + c + '(' + converted + ')');
+- }
+-
+- if (SslUtils.isTLSv13Cipher(converted) || SslUtils.isTLSv13Cipher(c)) {
+- cipherTLSv13Builder.append(converted);
+- cipherTLSv13Builder.append(':');
+- } else {
+- cipherBuilder.append(converted);
+- cipherBuilder.append(':');
+- }
- }
-- if ("ppc64le".equals(value)) {
-- return "ppcle_64";
+-
+- if (cipherBuilder.length() == 0 && cipherTLSv13Builder.length() == 0) {
+- throw new IllegalArgumentException("empty cipher suites");
- }
-- if ("s390".equals(value)) {
-- return "s390_32";
+- if (cipherBuilder.length() > 0) {
+- cipherBuilder.setLength(cipherBuilder.length() - 1);
- }
-- if ("s390x".equals(value)) {
-- return "s390_64";
+- if (cipherTLSv13Builder.length() > 0) {
+- cipherTLSv13Builder.setLength(cipherTLSv13Builder.length() - 1);
- }
--
-- return UNKNOWN;
- }
-
-- private static String normalize(String value) {
-- return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+",
"");
-- }
--
-- static void releaseIfNeeded(ReferenceCounted counted) {
-- if (counted.refCnt() > 0) {
-- ReferenceCountUtil.safeRelease(counted);
-- }
-- }
+- private CipherSuiteConverter() { }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
b/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
deleted file mode 100644
-index 4672d00..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
+index fcea5266f2..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
+++ /dev/null
-@@ -1,79 +0,0 @@
+@@ -1,126 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in
compliance
@@ -629,74 +606,121 @@ index 4672d00..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.CertificateVerifier;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.IllegalReferenceCountException;
+-import io.netty.util.ResourceLeakDetector;
+-import io.netty.util.ResourceLeakDetectorFactory;
+-import io.netty.util.ResourceLeakTracker;
-
--import java.security.cert.CertificateException;
+-import java.security.cert.X509Certificate;
-
--/**
-- * A special {@link CertificateException} which allows to specify which error code is
included in the
-- * SSL Record. This only work when {@link SslProvider#OPENSSL} or {@link
SslProvider#OPENSSL_REFCNT} is used.
-- */
--public final class OpenSslCertificateException extends CertificateException {
-- private static final long serialVersionUID = 5542675253797129798L;
+-final class DefaultOpenSslKeyMaterial extends AbstractReferenceCounted implements
OpenSslKeyMaterial {
-
-- private final int errorCode;
+- private static final ResourceLeakDetector<DefaultOpenSslKeyMaterial>
leakDetector =
+-
ResourceLeakDetectorFactory.instance().newResourceLeakDetector(DefaultOpenSslKeyMaterial.class);
+- private final ResourceLeakTracker<DefaultOpenSslKeyMaterial> leak;
+- private final X509Certificate[] x509CertificateChain;
+- private long chain;
+- private long privateKey;
-
-- /**
-- * Construct a new exception with the
-- * <a
href="https://www.openssl.org/docs/manmaster/apps/verify.html"&...
code</a>.
-- */
-- public OpenSslCertificateException(int errorCode) {
-- this((String) null, errorCode);
+- DefaultOpenSslKeyMaterial(long chain, long privateKey, X509Certificate[]
x509CertificateChain) {
+- this.chain = chain;
+- this.privateKey = privateKey;
+- this.x509CertificateChain = x509CertificateChain;
+- leak = leakDetector.track(this);
- }
-
-- /**
-- * Construct a new exception with the msg and
-- * <a
href="https://www.openssl.org/docs/manmaster/apps/verify.html"&...
code</a> .
-- */
-- public OpenSslCertificateException(String msg, int errorCode) {
-- super(msg);
-- this.errorCode = checkErrorCode(errorCode);
+- @Override
+- public X509Certificate[] certificateChain() {
+- return x509CertificateChain.clone();
- }
-
-- /**
-- * Construct a new exception with the msg, cause and
-- * <a
href="https://www.openssl.org/docs/manmaster/apps/verify.html"&...
code</a> .
-- */
-- public OpenSslCertificateException(String message, Throwable cause, int errorCode)
{
-- super(message, cause);
-- this.errorCode = checkErrorCode(errorCode);
+- @Override
+- public long certificateChainAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return chain;
- }
-
-- /**
-- * Construct a new exception with the cause and
-- * <a
href="https://www.openssl.org/docs/manmaster/apps/verify.html"&...
code</a> .
-- */
-- public OpenSslCertificateException(Throwable cause, int errorCode) {
-- this(null, cause, errorCode);
+- @Override
+- public long privateKeyAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return privateKey;
- }
-
-- /**
-- * Return the <a
href="https://www.openssl.org/docs/man1.0.2/apps/verify.html"&g...
code</a> to use.
-- */
-- public int errorCode() {
-- return errorCode;
+- @Override
+- protected void deallocate() {
+- SSL.freeX509Chain(chain);
+- chain = 0;
+- SSL.freePrivateKey(privateKey);
+- privateKey = 0;
+- if (leak != null) {
+- boolean closed = leak.close(this);
+- assert closed;
+- }
- }
-
-- private static int checkErrorCode(int errorCode) {
-- if (!CertificateVerifier.isValid(errorCode)) {
-- throw new IllegalArgumentException("errorCode '" + errorCode
+
-- "' invalid, see
https://www.openssl.org/docs/man1.0.2/apps/verify.html.");
+- @Override
+- public DefaultOpenSslKeyMaterial retain() {
+- if (leak != null) {
+- leak.record();
- }
-- return errorCode;
+- super.retain();
+- return this;
+- }
+-
+- @Override
+- public DefaultOpenSslKeyMaterial retain(int increment) {
+- if (leak != null) {
+- leak.record();
+- }
+- super.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public DefaultOpenSslKeyMaterial touch() {
+- if (leak != null) {
+- leak.record();
+- }
+- super.touch();
+- return this;
+- }
+-
+- @Override
+- public DefaultOpenSslKeyMaterial touch(Object hint) {
+- if (leak != null) {
+- leak.record(hint);
+- }
+- return this;
+- }
+-
+- @Override
+- public boolean release() {
+- if (leak != null) {
+- leak.record();
+- }
+- return super.release();
+- }
+-
+- @Override
+- public boolean release(int decrement) {
+- if (leak != null) {
+- leak.record();
+- }
+- return super.release(decrement);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
deleted file mode 100644
-index 46412e9..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+index d7d44cf3e7..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+++ /dev/null
-@@ -1,211 +0,0 @@
+@@ -1,610 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -712,210 +736,609 @@ index 46412e9..0000000
- * License for the specific language governing permissions and limitations
- * under the License.
- */
+-
-package io.netty.handler.ssl;
-
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.buffer.UnpooledByteBufAllocator;
+-import io.netty.internal.tcnative.Buffer;
+-import io.netty.internal.tcnative.Library;
-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.util.CharsetUtil;
+-import io.netty.util.ReferenceCountUtil;
+-import io.netty.util.ReferenceCounted;
+-import io.netty.util.internal.EmptyArrays;
+-import io.netty.util.internal.NativeLibraryLoader;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
--import java.io.File;
--import java.security.PrivateKey;
+-import java.io.ByteArrayInputStream;
+-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+-import java.util.ArrayList;
+-import java.util.Collections;
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-import java.util.Set;
-
--import javax.net.ssl.KeyManagerFactory;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.TrustManager;
--import javax.net.ssl.TrustManagerFactory;
--
--import static
io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext;
+-import static io.netty.handler.ssl.SslUtils.*;
-
-/**
-- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
-- * <p>This class will use a finalizer to ensure native resources are automatically
cleaned up. To avoid finalizers
-- * and manually release the native memory see {@link
ReferenceCountedOpenSslClientContext}.
+- * Tells if <a
href="https://netty.io/wiki/forked-tomcat-native.html">{@code
netty-tcnative}</a> and its OpenSSL support
+- * are available.
- */
--public final class OpenSslClientContext extends OpenSslContext {
-- private final OpenSslSessionContext sessionContext;
+-public final class OpenSsl {
-
-- /**
-- * Creates a new instance.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslClientContext() throws SSLException {
-- this((File) null, null, null, null, null, null, null,
IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
+- private static final InternalLogger logger =
InternalLoggerFactory.getInstance(OpenSsl.class);
+- private static final Throwable UNAVAILABILITY_CAUSE;
+-
+- static final List<String> DEFAULT_CIPHERS;
+- static final Set<String> AVAILABLE_CIPHER_SUITES;
+- private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES;
+- private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES;
+- private static final boolean SUPPORTS_KEYMANAGER_FACTORY;
+- private static final boolean USE_KEYMANAGER_FACTORY;
+- private static final boolean SUPPORTS_OCSP;
+- private static final boolean TLSV13_SUPPORTED;
+- private static final boolean IS_BORINGSSL;
+- static final Set<String> SUPPORTED_PROTOCOLS_SET;
+- static final String[] EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
+-
+- // self-signed certificate for netty.io and the matching private-key
+- private static final String CERT = "-----BEGIN CERTIFICATE-----\n" +
+-
"MIICrjCCAZagAwIBAgIIdSvQPv1QAZQwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAxMLZXhhbXBs\n"
+
+-
"ZS5jb20wIBcNMTgwNDA2MjIwNjU5WhgPOTk5OTEyMzEyMzU5NTlaMBYxFDASBgNVBAMTC2V4YW1w\n"
+
+-
"bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAggbWsmDQ6zNzRZ5AW8E3eoGl\n"
+
+-
"qWvOBDb5Fs1oBRrVQHuYmVAoaqwDzXYJ0LOwa293AgWEQ1jpcbZ2hpoYQzqEZBTLnFhMrhRFlH6K\n"
+
+-
"bJND8Y33kZ/iSVBBDuGbdSbJShlM+4WwQ9IAso4MZ4vW3S1iv5fGGpLgbtXRmBf/RU8omN0Gijlv\n"
+
+-
"WlLWHWijLN8xQtySFuBQ7ssW8RcKAary3pUm6UUQB+Co6lnfti0Tzag8PgjhAJq2Z3wbsGRnP2YS\n"
+
+-
"vYoaK6qzmHXRYlp/PxrjBAZAmkLJs4YTm/XFF+fkeYx4i9zqHbyone5yerRibsHaXZWLnUL+rFoe\n"
+
+-
"MdKvr0VS3sGmhQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQADQi441pKmXf9FvUV5EHU4v8nJT9Iq\n"
+
+-
"yqwsKwXnr7AsUlDGHBD7jGrjAXnG5rGxuNKBQ35wRxJATKrUtyaquFUL6H8O6aGQehiFTk6zmPbe\n"
+
+-
"12Gu44vqqTgIUxnv3JQJiox8S2hMxsSddpeCmSdvmalvD6WG4NthH6B9ZaBEiep1+0s0RUaBYn73\n"
+
+-
"I7CCUaAtbjfR6pcJjrFk5ei7uwdQZFSJtkP2z8r7zfeANJddAKFlkaMWn7u+OIVuB4XPooWicObk\n"
+
+-
"NAHFtP65bocUYnDpTVdiyvn8DdqyZ/EO8n1bBKBzuSLplk2msW4pdgaFgY7Vw/0wzcFXfUXmL1uy\n"
+
+- "G8sQD/wx\n" +
+- "-----END CERTIFICATE-----";
+-
+- private static final String KEY = "-----BEGIN PRIVATE KEY-----\n" +
+-
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCCBtayYNDrM3NFnkBbwTd6gaWp\n"
+
+-
"a84ENvkWzWgFGtVAe5iZUChqrAPNdgnQs7Brb3cCBYRDWOlxtnaGmhhDOoRkFMucWEyuFEWUfops\n"
+
+-
"k0PxjfeRn+JJUEEO4Zt1JslKGUz7hbBD0gCyjgxni9bdLWK/l8YakuBu1dGYF/9FTyiY3QaKOW9a\n"
+
+-
"UtYdaKMs3zFC3JIW4FDuyxbxFwoBqvLelSbpRRAH4KjqWd+2LRPNqDw+COEAmrZnfBuwZGc/ZhK9\n"
+
+-
"ihorqrOYddFiWn8/GuMEBkCaQsmzhhOb9cUX5+R5jHiL3OodvKid7nJ6tGJuwdpdlYudQv6sWh4x\n"
+
+-
"0q+vRVLewaaFAgMBAAECggEAP8tPJvFtTxhNJAkCloHz0D0vpDHqQBMgntlkgayqmBqLwhyb18pR\n"
+
+-
"i0qwgh7HHc7wWqOOQuSqlEnrWRrdcI6TSe8R/sErzfTQNoznKWIPYcI/hskk4sdnQ//Yn9/Jvnsv\n"
+
+-
"U/BBjOTJxtD+sQbhAl80JcA3R+5sArURQkfzzHOL/YMqzAsn5hTzp7HZCxUqBk3KaHRxV7NefeOE\n"
+
+-
"xlZuWSmxYWfbFIs4kx19/1t7h8CHQWezw+G60G2VBtSBBxDnhBWvqG6R/wpzJ3nEhPLLY9T+XIHe\n"
+
+-
"ipzdMOOOUZorfIg7M+pyYPji+ZIZxIpY5OjrOzXHciAjRtr5Y7l99K1CG1LguQKBgQDrQfIMxxtZ\n"
+
+-
"vxU/1cRmUV9l7pt5bjV5R6byXq178LxPKVYNjdZ840Q0/OpZEVqaT1xKVi35ohP1QfNjxPLlHD+K\n"
+
+-
"iDAR9z6zkwjIrbwPCnb5kuXy4lpwPcmmmkva25fI7qlpHtbcuQdoBdCfr/KkKaUCMPyY89LCXgEw\n"
+
+-
"5KTDj64UywKBgQCNfbO+eZLGzhiHhtNJurresCsIGWlInv322gL8CSfBMYl6eNfUTZvUDdFhPISL\n"
+
+-
"UljKWzXDrjw0ujFSPR0XhUGtiq89H+HUTuPPYv25gVXO+HTgBFZEPl4PpA+BUsSVZy0NddneyqLk\n"
+
+-
"42Wey9omY9Q8WsdNQS5cbUvy0uG6WFoX7wKBgQDZ1jpW8pa0x2bZsQsm4vo+3G5CRnZlUp+XlWt2\n"
+
+-
"dDcp5dC0xD1zbs1dc0NcLeGDOTDv9FSl7hok42iHXXq8AygjEm/QcuwwQ1nC2HxmQP5holAiUs4D\n"
+
+-
"WHM8PWs3wFYPzE459EBoKTxeaeP/uWAn+he8q7d5uWvSZlEcANs/6e77eQKBgD21Ar0hfFfj7mK8\n"
+
+-
"9E0FeRZBsqK3omkfnhcYgZC11Xa2SgT1yvs2Va2n0RcdM5kncr3eBZav2GYOhhAdwyBM55XuE/sO\n"
+
+-
"eokDVutNeuZ6d5fqV96TRaRBpvgfTvvRwxZ9hvKF4Vz+9wfn/JvCwANaKmegF6ejs7pvmF3whq2k\n"
+
+-
"drZVAoGAX5YxQ5XMTD0QbMAl7/6qp6S58xNoVdfCkmkj1ZLKaHKIjS/benkKGlySVQVPexPfnkZx\n"
+
+-
"p/Vv9yyphBoudiTBS9Uog66ueLYZqpgxlM/6OhYg86Gm3U2ycvMxYjBM1NFiyze21AqAhI+HX+Ot\n"
+
+- "mraV2/guSgDgZAhukRZzeQ2RucI=\n" +
+- "-----END PRIVATE KEY-----";
+-
+- static {
+- Throwable cause = null;
+-
+- if (SystemPropertyUtil.getBoolean("io.netty.handler.ssl.noOpenSsl",
false)) {
+- cause = new UnsupportedOperationException(
+- "OpenSSL was explicit disabled with
-Dio.netty.handler.ssl.noOpenSsl=true");
+-
+- logger.debug(
+- "netty-tcnative explicit disabled; " +
+- OpenSslEngine.class.getSimpleName() + " will be
unavailable.", cause);
+- } else {
+- // Test if netty-tcnative is in the classpath first.
+- try {
+- Class.forName("io.netty.internal.tcnative.SSLContext", false,
OpenSsl.class.getClassLoader());
+- } catch (ClassNotFoundException t) {
+- cause = t;
+- logger.debug(
+- "netty-tcnative not in the classpath; " +
+- OpenSslEngine.class.getSimpleName() + " will be
unavailable.");
+- }
+-
+- // If in the classpath, try to load the native library and initialize
netty-tcnative.
+- if (cause == null) {
+- try {
+- // The JNI library was not already loaded. Load it now.
+- loadTcNative();
+- } catch (Throwable t) {
+- cause = t;
+- logger.debug(
+- "Failed to load netty-tcnative; " +
+- OpenSslEngine.class.getSimpleName() + " will be
unavailable, unless the " +
+- "application has already loaded the symbols by
some other means. " +
+- "See
https://netty.io/wiki/forked-tomcat-native.html for more information.", t);
+- }
+-
+- try {
+- String engine =
SystemPropertyUtil.get("io.netty.handler.ssl.openssl.engine", null);
+- if (engine == null) {
+- logger.debug("Initialize netty-tcnative using engine:
'default'");
+- } else {
+- logger.debug("Initialize netty-tcnative using engine:
'{}'", engine);
+- }
+- initializeTcNative(engine);
+-
+- // The library was initialized successfully. If loading the library
failed above,
+- // reset the cause now since it appears that the library was loaded
by some other
+- // means.
+- cause = null;
+- } catch (Throwable t) {
+- if (cause == null) {
+- cause = t;
+- }
+- logger.debug(
+- "Failed to initialize netty-tcnative; " +
+- OpenSslEngine.class.getSimpleName() + " will be
unavailable. " +
+- "See
https://netty.io/wiki/forked-tomcat-native.html for more information.", t);
+- }
+- }
+- }
+-
+- UNAVAILABILITY_CAUSE = cause;
+-
+- if (cause == null) {
+- logger.debug("netty-tcnative using native library: {}",
SSL.versionString());
+-
+- final List<String> defaultCiphers = new ArrayList<String>();
+- final Set<String> availableOpenSslCipherSuites = new
LinkedHashSet<String>(128);
+- boolean supportsKeyManagerFactory = false;
+- boolean useKeyManagerFactory = false;
+- boolean tlsv13Supported = false;
+-
+- IS_BORINGSSL = "BoringSSL".equals(versionString());
+- if (IS_BORINGSSL) {
+- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = new String [] {
"TLS_AES_128_GCM_SHA256",
+- "TLS_AES_256_GCM_SHA384" ,
+- "TLS_CHACHA20_POLY1305_SHA256" };
+- } else {
+- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
+- }
+-
+- try {
+- final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL,
SSL.SSL_MODE_SERVER);
+- long certBio = 0;
+- long keyBio = 0;
+- long cert = 0;
+- long key = 0;
+- try {
+- try {
+- StringBuilder tlsv13Ciphers = new StringBuilder();
+-
+- for (String cipher: TLSV13_CIPHERS) {
+- String converted = CipherSuiteConverter.toOpenSsl(cipher,
IS_BORINGSSL);
+- if (converted != null) {
+- tlsv13Ciphers.append(converted).append(':');
+- }
+- }
+- if (tlsv13Ciphers.length() == 0) {
+- tlsv13Supported = false;
+- } else {
+- tlsv13Ciphers.setLength(tlsv13Ciphers.length() - 1);
+- SSLContext.setCipherSuite(sslCtx, tlsv13Ciphers.toString() ,
true);
+- tlsv13Supported = true;
+- }
+-
+- } catch (Exception ignore) {
+- tlsv13Supported = false;
+- }
+-
+- SSLContext.setCipherSuite(sslCtx, "ALL", false);
+-
+- final long ssl = SSL.newSSL(sslCtx, true);
+- try {
+- for (String c: SSL.getCiphers(ssl)) {
+- // Filter out bad input.
+- if (c == null || c.isEmpty() ||
availableOpenSslCipherSuites.contains(c) ||
+- // Filter out TLSv1.3 ciphers if not supported.
+- !tlsv13Supported && isTLSv13Cipher(c)) {
+- continue;
+- }
+- availableOpenSslCipherSuites.add(c);
+- }
+- if (IS_BORINGSSL) {
+- // Currently BoringSSL does not include these when calling
SSL.getCiphers() even when these
+- // are supported.
+- Collections.addAll(availableOpenSslCipherSuites,
EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
+- Collections.addAll(availableOpenSslCipherSuites,
+- "AEAD-AES128-GCM-SHA256",
+- "AEAD-AES256-GCM-SHA384",
+-
"AEAD-CHACHA20-POLY1305-SHA256");
+- }
+-
+- PemEncoded privateKey =
PemPrivateKey.valueOf(KEY.getBytes(CharsetUtil.US_ASCII));
+- try {
+- // Let's check if we can set a callback, which may not
work if the used OpenSSL version
+- // is to old.
+- SSLContext.setCertificateCallback(sslCtx, null);
+-
+- X509Certificate certificate = selfSignedCertificate();
+- certBio =
ReferenceCountedOpenSslContext.toBIO(ByteBufAllocator.DEFAULT, certificate);
+- cert = SSL.parseX509Chain(certBio);
+-
+- keyBio = ReferenceCountedOpenSslContext.toBIO(
+- UnpooledByteBufAllocator.DEFAULT,
privateKey.retain());
+- key = SSL.parsePrivateKey(keyBio, null);
+-
+- SSL.setKeyMaterial(ssl, cert, key);
+- supportsKeyManagerFactory = true;
+- try {
+- boolean propertySet = SystemPropertyUtil.contains(
+-
"io.netty.handler.ssl.openssl.useKeyManagerFactory");
+- if (!IS_BORINGSSL) {
+- useKeyManagerFactory =
SystemPropertyUtil.getBoolean(
+-
"io.netty.handler.ssl.openssl.useKeyManagerFactory", true);
+-
+- if (propertySet) {
+- logger.info("System property " +
+-
"'io.netty.handler.ssl.openssl.useKeyManagerFactory'" +
+- " is deprecated and so will be
ignored in the future");
+- }
+- } else {
+- useKeyManagerFactory = true;
+- if (propertySet) {
+- logger.info("System property " +
+-
"'io.netty.handler.ssl.openssl.useKeyManagerFactory'" +
+- " is deprecated and will be ignored
when using BoringSSL");
+- }
+- }
+- } catch (Throwable ignore) {
+- logger.debug("Failed to get useKeyManagerFactory
system property.");
+- }
+- } catch (Error ignore) {
+- logger.debug("KeyManagerFactory not supported.");
+- } finally {
+- privateKey.release();
+- }
+- } finally {
+- SSL.freeSSL(ssl);
+- if (certBio != 0) {
+- SSL.freeBIO(certBio);
+- }
+- if (keyBio != 0) {
+- SSL.freeBIO(keyBio);
+- }
+- if (cert != 0) {
+- SSL.freeX509Chain(cert);
+- }
+- if (key != 0) {
+- SSL.freePrivateKey(key);
+- }
+- }
+- } finally {
+- SSLContext.free(sslCtx);
+- }
+- } catch (Exception e) {
+- logger.warn("Failed to get the list of available OpenSSL cipher
suites.", e);
+- }
+- AVAILABLE_OPENSSL_CIPHER_SUITES =
Collections.unmodifiableSet(availableOpenSslCipherSuites);
+- final Set<String> availableJavaCipherSuites = new
LinkedHashSet<String>(
+- AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
+- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
+- // Included converted but also openssl cipher name
+- if (!isTLSv13Cipher(cipher)) {
+- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher,
"TLS"));
+- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher,
"SSL"));
+- } else {
+- // TLSv1.3 ciphers have the correct format.
+- availableJavaCipherSuites.add(cipher);
+- }
+- }
+-
+- addIfSupported(availableJavaCipherSuites, defaultCiphers,
DEFAULT_CIPHER_SUITES);
+- addIfSupported(availableJavaCipherSuites, defaultCiphers,
TLSV13_CIPHER_SUITES);
+-
+- useFallbackCiphersIfDefaultIsEmpty(defaultCiphers,
availableJavaCipherSuites);
+- DEFAULT_CIPHERS = Collections.unmodifiableList(defaultCiphers);
+-
+- AVAILABLE_JAVA_CIPHER_SUITES =
Collections.unmodifiableSet(availableJavaCipherSuites);
+-
+- final Set<String> availableCipherSuites = new
LinkedHashSet<String>(
+- AVAILABLE_OPENSSL_CIPHER_SUITES.size() +
AVAILABLE_JAVA_CIPHER_SUITES.size());
+- availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES);
+- availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES);
+-
+- AVAILABLE_CIPHER_SUITES = availableCipherSuites;
+- SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory;
+- USE_KEYMANAGER_FACTORY = useKeyManagerFactory;
+-
+- Set<String> protocols = new LinkedHashSet<String>(6);
+- // Seems like there is no way to explicitly disable SSLv2Hello in openssl so
it is always enabled
+- protocols.add(PROTOCOL_SSL_V2_HELLO);
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2, SSL.SSL_OP_NO_SSLv2)) {
+- protocols.add(PROTOCOL_SSL_V2);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3, SSL.SSL_OP_NO_SSLv3)) {
+- protocols.add(PROTOCOL_SSL_V3);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1, SSL.SSL_OP_NO_TLSv1)) {
+- protocols.add(PROTOCOL_TLS_V1);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1, SSL.SSL_OP_NO_TLSv1_1)) {
+- protocols.add(PROTOCOL_TLS_V1_1);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_OP_NO_TLSv1_2)) {
+- protocols.add(PROTOCOL_TLS_V1_2);
+- }
+-
+- // This is only supported by java11 and later.
+- if (tlsv13Supported && doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_3,
SSL.SSL_OP_NO_TLSv1_3)) {
+- protocols.add(PROTOCOL_TLS_V1_3);
+- TLSV13_SUPPORTED = true;
+- } else {
+- TLSV13_SUPPORTED = false;
+- }
+-
+- SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols);
+- SUPPORTS_OCSP = doesSupportOcsp();
+-
+- if (logger.isDebugEnabled()) {
+- logger.debug("Supported protocols (OpenSSL): {} ",
SUPPORTED_PROTOCOLS_SET);
+- logger.debug("Default cipher suites (OpenSSL): {}",
DEFAULT_CIPHERS);
+- }
+- } else {
+- DEFAULT_CIPHERS = Collections.emptyList();
+- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
+- AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
+- AVAILABLE_CIPHER_SUITES = Collections.emptySet();
+- SUPPORTS_KEYMANAGER_FACTORY = false;
+- USE_KEYMANAGER_FACTORY = false;
+- SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
+- SUPPORTS_OCSP = false;
+- TLSV13_SUPPORTED = false;
+- IS_BORINGSSL = false;
+- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
+- }
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format.
-- * {@code null} to use the system default
-- * @deprecated use {@link SslContextBuilder}
+- * Returns a self-signed {@link X509Certificate} for {@code netty.io}.
- */
-- @Deprecated
-- public OpenSslClientContext(File certChainFile) throws SSLException {
-- this(certChainFile, null);
+- static X509Certificate selfSignedCertificate() throws CertificateException {
+- return (X509Certificate) SslContext.X509_CERT_FACTORY.generateCertificate(
+- new ByteArrayInputStream(CERT.getBytes(CharsetUtil.US_ASCII))
+- );
+- }
+-
+- private static boolean doesSupportOcsp() {
+- boolean supportsOcsp = false;
+- if (version() >= 0x10002000L) {
+- long sslCtx = -1;
+- try {
+- sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2,
SSL.SSL_MODE_SERVER);
+- SSLContext.enableOcsp(sslCtx, false);
+- supportsOcsp = true;
+- } catch (Exception ignore) {
+- // ignore
+- } finally {
+- if (sslCtx != -1) {
+- SSLContext.free(sslCtx);
+- }
+- }
+- }
+- return supportsOcsp;
+- }
+- private static boolean doesSupportProtocol(int protocol, int opt) {
+- if (opt == 0) {
+- // If the opt is 0 the protocol is not supported. This is for example the
case with BoringSSL and SSLv2.
+- return false;
+- }
+- long sslCtx = -1;
+- try {
+- sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED);
+- return true;
+- } catch (Exception ignore) {
+- return false;
+- } finally {
+- if (sslCtx != -1) {
+- SSLContext.free(sslCtx);
+- }
+- }
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns {@code true} if and only if
+- * <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code
netty-tcnative}</a> and its OpenSSL support
+- * are available.
- */
-- @Deprecated
-- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws
SSLException {
-- this(null, trustManagerFactory);
+- public static boolean isAvailable() {
+- return UNAVAILABILITY_CAUSE == null;
- }
-
- /**
-- * Creates a new instance.
+- * Returns {@code true} if the used version of openssl supports
+- * <a
href="https://tools.ietf.org/html/rfc7301">ALPN</a>.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format.
-- * {@code null} to use the system default
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default.
-- * @deprecated use {@link SslContextBuilder}
+- * @deprecated use {@link SslProvider#isAlpnSupported(SslProvider)} with {@link
SslProvider#OPENSSL}.
- */
- @Deprecated
-- public OpenSslClientContext(File certChainFile, TrustManagerFactory
trustManagerFactory) throws SSLException {
-- this(certChainFile, trustManagerFactory, null, null, null, null, null,
-- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
+- public static boolean isAlpnSupported() {
+- return version() >= 0x10002000L;
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default..
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param apn Provides a means to configure parameters related to application
protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns {@code true} if the used version of OpenSSL supports OCSP stapling.
- */
-- @Deprecated
-- public OpenSslClientContext(File certChainFile, TrustManagerFactory
trustManagerFactory, Iterable<String> ciphers,
-- ApplicationProtocolConfig apn, long sessionCacheSize,
long sessionTimeout)
-- throws SSLException {
-- this(certChainFile, trustManagerFactory, null, null, null, null, ciphers,
IdentityCipherSuiteFilter.INSTANCE,
-- apn, sessionCacheSize, sessionTimeout);
+- public static boolean isOcspSupported() {
+- return SUPPORTS_OCSP;
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default..
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param apn Provides a means to configure parameters related to application
protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns the version of the used available OpenSSL library or {@code -1} if {@link
#isAvailable()}
+- * returns {@code false}.
+- */
+- public static int version() {
+- return isAvailable() ? SSL.version() : -1;
+- }
+-
+- /**
+- * Returns the version string of the used available OpenSSL library or {@code null}
if {@link #isAvailable()}
+- * returns {@code false}.
+- */
+- public static String versionString() {
+- return isAvailable() ? SSL.versionString() : null;
+- }
+-
+- /**
+- * Ensure that <a
href="https://netty.io/wiki/forked-tomcat-native.html">{@code
netty-tcnative}</a> and
+- * its OpenSSL support are available.
+- *
+- * @throws UnsatisfiedLinkError if unavailable
+- */
+- public static void ensureAvailability() {
+- if (UNAVAILABILITY_CAUSE != null) {
+- throw (Error) new UnsatisfiedLinkError(
+- "failed to load the required native
library").initCause(UNAVAILABILITY_CAUSE);
+- }
+- }
+-
+- /**
+- * Returns the cause of unavailability of
+- * <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code
netty-tcnative}</a> and its OpenSSL support.
+- *
+- * @return the cause if unavailable. {@code null} if available.
+- */
+- public static Throwable unavailabilityCause() {
+- return UNAVAILABILITY_CAUSE;
+- }
+-
+- /**
+- * @deprecated use {@link #availableOpenSslCipherSuites()}
- */
- @Deprecated
-- public OpenSslClientContext(File certChainFile, TrustManagerFactory
trustManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout) throws
SSLException {
-- this(certChainFile, trustManagerFactory, null, null, null, null,
-- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
+- public static Set<String> availableCipherSuites() {
+- return availableOpenSslCipherSuites();
- }
-
- /**
-- * Creates a new instance.
-- * @param trustCertCollectionFile an X.509 certificate collection file in PEM
format.
-- * {@code null} to use the system default
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default or the results of
parsing
-- * {@code trustCertCollectionFile}
-- * @param keyCertChainFile an X.509 certificate chain file in PEM format.
-- * This provides the public key for mutual authentication.
-- * {@code null} to use the system default
-- * @param keyFile a PKCS#8 private key file in PEM format.
-- * This provides the private key for mutual authentication.
-- * {@code null} for no mutual authentication.
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * Ignored if {@code keyFile} is {@code null}.
-- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link
javax.net.ssl.KeyManager}s
-- * that is used to encrypt data being sent to servers.
-- * {@code null} to use the default or the results of
parsing
-- * {@code keyCertChainFile} and {@code keyFile}.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param apn Application Protocol Negotiator object.
-- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns all the available OpenSSL cipher suites.
+- * Please note that the returned array may include the cipher suites that are
insecure or non-functional.
+- */
+- public static Set<String> availableOpenSslCipherSuites() {
+- return AVAILABLE_OPENSSL_CIPHER_SUITES;
+- }
+-
+- /**
+- * Returns all the available cipher suites (Java-style).
+- * Please note that the returned array may include the cipher suites that are
insecure or non-functional.
+- */
+- public static Set<String> availableJavaCipherSuites() {
+- return AVAILABLE_JAVA_CIPHER_SUITES;
+- }
+-
+- /**
+- * Returns {@code true} if and only if the specified cipher suite is available in
OpenSSL.
+- * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted.
+- */
+- public static boolean isCipherSuiteAvailable(String cipherSuite) {
+- String converted = CipherSuiteConverter.toOpenSsl(cipherSuite, IS_BORINGSSL);
+- if (converted != null) {
+- cipherSuite = converted;
+- }
+- return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite);
+- }
+-
+- /**
+- * Returns {@code true} if {@link javax.net.ssl.KeyManagerFactory} is supported when
using OpenSSL.
+- */
+- public static boolean supportsKeyManagerFactory() {
+- return SUPPORTS_KEYMANAGER_FACTORY;
+- }
+-
+- /**
+- * Always returns {@code true} if {@link #isAvailable()} returns {@code true}.
+- *
+- * @deprecated Will be removed because hostname validation is always done by a
+- * {@link javax.net.ssl.TrustManager} implementation.
- */
- @Deprecated
-- public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory
trustManagerFactory,
-- File keyCertChainFile, File keyFile, String
keyPassword,
-- KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout)
-- throws SSLException {
-- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
-- toX509CertificatesInternal(keyCertChainFile),
toPrivateKeyInternal(keyFile, keyPassword),
-- keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, null,
sessionCacheSize,
-- sessionTimeout, false);
+- public static boolean supportsHostnameValidation() {
+- return isAvailable();
- }
-
-- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory
trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String
keyPassword,
-- KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn, String[] protocols,
-- long sessionCacheSize, long sessionTimeout, boolean
enableOcsp)
-- throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
SSL.SSL_MODE_CLIENT, keyCertChain,
-- ClientAuth.NONE, protocols, false, enableOcsp);
-- boolean success = false;
-- try {
-- sessionContext = newSessionContext(this, ctx, engineMap,
trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword,
keyManagerFactory);
-- success = true;
-- } finally {
-- if (!success) {
-- release();
-- }
+- static boolean useKeyManagerFactory() {
+- return USE_KEYMANAGER_FACTORY;
+- }
+-
+- static long memoryAddress(ByteBuf buf) {
+- assert buf.isDirect();
+- return buf.hasMemoryAddress() ? buf.memoryAddress() :
Buffer.address(buf.nioBuffer());
+- }
+-
+- private OpenSsl() { }
+-
+- private static void loadTcNative() throws Exception {
+- String os = PlatformDependent.normalizedOs();
+- String arch = PlatformDependent.normalizedArch();
+-
+- Set<String> libNames = new LinkedHashSet<String>(5);
+- String staticLibName = "netty_tcnative";
+-
+- // First, try loading the platform-specific library. Platform-specific
+- // libraries will be available if using a tcnative uber jar.
+- if ("linux".equalsIgnoreCase(os)) {
+- Set<String> classifiers =
PlatformDependent.normalizedLinuxClassifiers();
+- for (String classifier : classifiers) {
+- libNames.add(staticLibName + "_" + os + '_' + arch +
"_" + classifier);
+- }
+- // generic arch-dependent library
+- libNames.add(staticLibName + "_" + os + '_' + arch);
+-
+- // Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0).
+- // note: should already be included from the classifiers but if not, we use
this as an
+- // additional fallback option here
+- libNames.add(staticLibName + "_" + os + '_' + arch +
"_fedora");
+- } else {
+- libNames.add(staticLibName + "_" + os + '_' + arch);
- }
+- libNames.add(staticLibName + "_" + arch);
+- libNames.add(staticLibName);
+-
+- NativeLibraryLoader.loadFirstAvailable(SSLContext.class.getClassLoader(),
+- libNames.toArray(new String[0]));
- }
-
-- @Override
-- public OpenSslSessionContext sessionContext() {
-- return sessionContext;
+- private static boolean initializeTcNative(String engine) throws Exception {
+- return Library.initialize("provided", engine);
- }
-
-- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return null;
+- static void releaseIfNeeded(ReferenceCounted counted) {
+- if (counted.refCnt() > 0) {
+- ReferenceCountUtil.safeRelease(counted);
+- }
+- }
+-
+- static boolean isTlsv13Supported() {
+- return TLSV13_SUPPORTED;
+- }
+-
+- static boolean isBoringSSL() {
+- return IS_BORINGSSL;
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+diff --git
a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
deleted file mode 100644
-index c4ca6b5..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+index 07b67d9fa7..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
+++ /dev/null
-@@ -1,58 +0,0 @@
+@@ -1,79 +0,0 @@
-/*
-- * Copyright 2014 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in
compliance
@@ -933,53 +1356,74 @@ index c4ca6b5..0000000
-
-import io.netty.buffer.ByteBufAllocator;
-
--import java.security.cert.Certificate;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
+-import javax.net.ssl.X509KeyManager;
+-import java.util.Iterator;
+-import java.util.concurrent.ConcurrentHashMap;
+-import java.util.concurrent.ConcurrentMap;
-
-/**
-- * This class will use a finalizer to ensure native resources are automatically cleaned
up. To avoid finalizers
-- * and manually release the native memory see {@link ReferenceCountedOpenSslContext}.
+- * {@link OpenSslKeyMaterialProvider} that will cache the {@link OpenSslKeyMaterial} to
reduce the overhead
+- * of parsing the chain and the key for generation of the material.
- */
--public abstract class OpenSslContext extends ReferenceCountedOpenSslContext {
-- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apnCfg,
-- long sessionCacheSize, long sessionTimeout, int mode, Certificate[]
keyCertChain,
-- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean
enableOcsp)
-- throws SSLException {
-- super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode,
keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp, false);
-- }
+-final class OpenSslCachingKeyMaterialProvider extends OpenSslKeyMaterialProvider {
-
-- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
-- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
-- long sessionTimeout, int mode, Certificate[] keyCertChain,
-- ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode,
keyCertChain, clientAuth, protocols,
-- startTls, enableOcsp, false);
+- private final int maxCachedEntries;
+- private volatile boolean full;
+- private final ConcurrentMap<String, OpenSslKeyMaterial> cache = new
ConcurrentHashMap<String, OpenSslKeyMaterial>();
+-
+- OpenSslCachingKeyMaterialProvider(X509KeyManager keyManager, String password, int
maxCachedEntries) {
+- super(keyManager, password);
+- this.maxCachedEntries = maxCachedEntries;
- }
-
- @Override
-- final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) {
-- return new OpenSslEngine(this, alloc, peerHost, peerPort);
+- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias)
throws Exception {
+- OpenSslKeyMaterial material = cache.get(alias);
+- if (material == null) {
+- material = super.chooseKeyMaterial(allocator, alias);
+- if (material == null) {
+- // No keymaterial should be used.
+- return null;
+- }
+-
+- if (full) {
+- return material;
+- }
+- if (cache.size() > maxCachedEntries) {
+- full = true;
+- // Do not cache...
+- return material;
+- }
+- OpenSslKeyMaterial old = cache.putIfAbsent(alias, material);
+- if (old != null) {
+- material.release();
+- material = old;
+- }
+- }
+- // We need to call retain() as we want to always have at least a refCnt() of 1
before destroy() was called.
+- return material.retain();
- }
-
- @Override
-- @SuppressWarnings("FinalizeDeclaration")
-- protected final void finalize() throws Throwable {
-- super.finalize();
-- OpenSsl.releaseIfNeeded(this);
+- void destroy() {
+- // Remove and release all entries.
+- do {
+- Iterator<OpenSslKeyMaterial> iterator = cache.values().iterator();
+- while (iterator.hasNext()) {
+- iterator.next().release();
+- iterator.remove();
+- }
+- } while (!cache.isEmpty());
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+diff --git
a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
deleted file mode 100644
-index cbc7ee4..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+index 7f67bc8198..0000000000
+---
a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
+++ /dev/null
-@@ -1,40 +0,0 @@
+@@ -1,81 +0,0 @@
-/*
-- * Copyright 2014 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in
compliance
@@ -995,37 +1439,78 @@ index cbc7ee4..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBufAllocator;
+-import io.netty.util.internal.ObjectUtil;
-
--import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.KeyManager;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.KeyManagerFactorySpi;
+-import javax.net.ssl.ManagerFactoryParameters;
+-import javax.net.ssl.X509ExtendedKeyManager;
+-import javax.net.ssl.X509KeyManager;
+-import java.security.InvalidAlgorithmParameterException;
+-import java.security.KeyStore;
+-import java.security.KeyStoreException;
+-import java.security.NoSuchAlgorithmException;
+-import java.security.PrivateKey;
+-import java.security.UnrecoverableKeyException;
+-import java.security.cert.X509Certificate;
-
-/**
-- * Implements a {@link SSLEngine} using
-- * <a
href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE&quo... BIO
abstractions</a>.
-- * <p>
-- * This class will use a finalizer to ensure native resources are automatically cleaned
up. To avoid finalizers
-- * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}.
+- * Wraps another {@link KeyManagerFactory} and caches its chains / certs for an alias
for better performance when using
+- * {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT}.
+- *
+- * Because of the caching its important that the wrapped {@link KeyManagerFactory}s
{@link X509KeyManager}s always
+- * return the same {@link X509Certificate} chain and {@link PrivateKey} for the same
alias.
- */
--public final class OpenSslEngine extends ReferenceCountedOpenSslEngine {
-- OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int
peerPort) {
-- super(context, alloc, peerHost, peerPort, false);
+-public final class OpenSslCachingX509KeyManagerFactory extends KeyManagerFactory {
+-
+- private final int maxCachedEntries;
+-
+- public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory) {
+- this(factory, 1024);
- }
-
-- @Override
-- @SuppressWarnings("FinalizeDeclaration")
-- protected void finalize() throws Throwable {
-- super.finalize();
-- OpenSsl.releaseIfNeeded(this);
+- public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory, int
maxCachedEntries) {
+- super(new KeyManagerFactorySpi() {
+- @Override
+- protected void engineInit(KeyStore keyStore, char[] chars)
+- throws KeyStoreException, NoSuchAlgorithmException,
UnrecoverableKeyException {
+- factory.init(keyStore, chars);
+- }
+-
+- @Override
+- protected void engineInit(ManagerFactoryParameters
managerFactoryParameters)
+- throws InvalidAlgorithmParameterException {
+- factory.init(managerFactoryParameters);
+- }
+-
+- @Override
+- protected KeyManager[] engineGetKeyManagers() {
+- return factory.getKeyManagers();
+- }
+- }, factory.getProvider(), factory.getAlgorithm());
+- this.maxCachedEntries = ObjectUtil.checkPositive(maxCachedEntries,
"maxCachedEntries");
+- }
+-
+- OpenSslKeyMaterialProvider newProvider(String password) {
+- X509KeyManager keyManager =
ReferenceCountedOpenSslContext.chooseX509KeyManager(getKeyManagers());
+- if
("sun.security.ssl.X509KeyManagerImpl".equals(keyManager.getClass().getName()))
{
+- // Don't do caching if X509KeyManagerImpl is used as the returned
aliases are not stable and will change
+- // between invocations.
+- return new OpenSslKeyMaterialProvider(keyManager, password);
+- }
+- return new OpenSslCachingKeyMaterialProvider(
+- ReferenceCountedOpenSslContext.chooseX509KeyManager(getKeyManagers()),
password, maxCachedEntries);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
deleted file mode 100644
-index 02131b4..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+index f20b2d3ba0..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
+++ /dev/null
-@@ -1,35 +0,0 @@
+@@ -1,81 +0,0 @@
-/*
-- * Copyright 2014 The Netty Project
+- * Copyright 2016 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in
compliance
@@ -1041,261 +1526,76 @@ index 02131b4..0000000
- */
-package io.netty.handler.ssl;
-
--interface OpenSslEngineMap {
+-import io.netty.internal.tcnative.CertificateVerifier;
-
-- /**
-- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and
-- * return it.
-- */
-- ReferenceCountedOpenSslEngine remove(long ssl);
--
-- /**
-- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}.
-- */
-- void add(ReferenceCountedOpenSslEngine engine);
--
-- /**
-- * Get the {@link OpenSslEngine} for the given {@code ssl} address.
-- */
-- ReferenceCountedOpenSslEngine get(long ssl);
--}
-diff --git
a/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java
-deleted file mode 100644
-index 38f6a7f..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java
-+++ /dev/null
-@@ -1,40 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.security.auth.x500.X500Principal;
--
--final class OpenSslExtendedKeyMaterialManager extends OpenSslKeyMaterialManager {
--
-- private final X509ExtendedKeyManager keyManager;
--
-- OpenSslExtendedKeyMaterialManager(X509ExtendedKeyManager keyManager, String
password) {
-- super(keyManager, password);
-- this.keyManager = keyManager;
-- }
--
-- @Override
-- protected String chooseClientAlias(ReferenceCountedOpenSslEngine engine, String[]
keyTypes,
-- X500Principal[] issuer) {
-- return keyManager.chooseEngineClientAlias(keyTypes, issuer, engine);
-- }
--
-- @Override
-- protected String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String
type) {
-- return keyManager.chooseEngineServerAlias(type, null, engine);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
-deleted file mode 100644
-index 2e48e8b..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
-+++ /dev/null
-@@ -1,179 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.internal.tcnative.CertificateRequestedCallback;
--import io.netty.internal.tcnative.SSL;
--
--import javax.net.ssl.SSLException;
--import javax.net.ssl.X509KeyManager;
--import javax.security.auth.x500.X500Principal;
--import java.security.PrivateKey;
--import java.security.cert.X509Certificate;
--import java.util.HashMap;
--import java.util.HashSet;
--import java.util.Map;
--import java.util.Set;
--
--import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.freeBio;
--import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO;
+-import java.security.cert.CertificateException;
-
-/**
-- * Manages key material for {@link OpenSslEngine}s and so set the right {@link
PrivateKey}s and
-- * {@link X509Certificate}s.
+- * A special {@link CertificateException} which allows to specify which error code is
included in the
+- * SSL Record. This only work when {@link SslProvider#OPENSSL} or {@link
SslProvider#OPENSSL_REFCNT} is used.
- */
--class OpenSslKeyMaterialManager {
--
-- // Code in this class is inspired by code of conscrypts:
-- // -
https://android.googlesource.com/platform/external/
-- // conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java
-- // -
https://android.googlesource.com/platform/external/
-- // conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java
-- //
-- static final String KEY_TYPE_RSA = "RSA";
-- static final String KEY_TYPE_DH_RSA = "DH_RSA";
-- static final String KEY_TYPE_EC = "EC";
-- static final String KEY_TYPE_EC_EC = "EC_EC";
-- static final String KEY_TYPE_EC_RSA = "EC_RSA";
--
-- // key type mappings for types.
-- private static final Map<String, String> KEY_TYPES = new HashMap<String,
String>();
-- static {
-- KEY_TYPES.put("RSA", KEY_TYPE_RSA);
-- KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA);
-- KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA);
-- KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC);
-- KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA);
-- KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC);
-- KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA);
-- }
+-public final class OpenSslCertificateException extends CertificateException {
+- private static final long serialVersionUID = 5542675253797129798L;
-
-- private final X509KeyManager keyManager;
-- private final String password;
+- private final int errorCode;
-
-- OpenSslKeyMaterialManager(X509KeyManager keyManager, String password) {
-- this.keyManager = keyManager;
-- this.password = password;
+- /**
+- * Construct a new exception with the
+- * <a
href="https://www.openssl.org/docs/manmaster/apps/verify.html"&...
code</a>.
+- */
+- public OpenSslCertificateException(int errorCode) {
+- this((String) null, errorCode);
- }
-
-- void setKeyMaterial(ReferenceCountedOpenSslEngine engine) throws SSLException {
-- long ssl = engine.sslPointer();
-- String[] authMethods = SSL.authenticationMethods(ssl);
-- Set<String> aliases = new HashSet<String>(authMethods.length);
-- for (String authMethod : authMethods) {
-- String type = KEY_TYPES.get(authMethod);
-- if (type != null) {
-- String alias = chooseServerAlias(engine, type);
-- if (alias != null && aliases.add(alias)) {
-- setKeyMaterial(ssl, alias);
-- }
-- }
-- }
+- /**
+- * Construct a new exception with the msg and
+- * <a
href="https://www.openssl.org/docs/manmaster/apps/verify.html"&...
code</a> .
+- */
+- public OpenSslCertificateException(String msg, int errorCode) {
+- super(msg);
+- this.errorCode = checkErrorCode(errorCode);
- }
-
-- CertificateRequestedCallback.KeyMaterial keyMaterial(ReferenceCountedOpenSslEngine
engine, String[] keyTypes,
-- X500Principal[] issuer) throws
SSLException {
-- String alias = chooseClientAlias(engine, keyTypes, issuer);
-- long keyBio = 0;
-- long keyCertChainBio = 0;
-- long pkey = 0;
-- long certChain = 0;
--
-- try {
-- // TODO: Should we cache these and so not need to do a memory copy all the
time ?
-- X509Certificate[] certificates = keyManager.getCertificateChain(alias);
-- if (certificates == null || certificates.length == 0) {
-- return null;
-- }
--
-- PrivateKey key = keyManager.getPrivateKey(alias);
-- keyCertChainBio = toBIO(certificates);
-- certChain = SSL.parseX509Chain(keyCertChainBio);
-- if (key != null) {
-- keyBio = toBIO(key);
-- pkey = SSL.parsePrivateKey(keyBio, password);
-- }
-- CertificateRequestedCallback.KeyMaterial material = new
CertificateRequestedCallback.KeyMaterial(
-- certChain, pkey);
--
-- // Reset to 0 so we do not free these. This is needed as the client
certificate callback takes ownership
-- // of both the key and the certificate if they are returned from this
method, and thus must not
-- // be freed here.
-- certChain = pkey = 0;
-- return material;
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException(e);
-- } finally {
-- freeBio(keyBio);
-- freeBio(keyCertChainBio);
-- SSL.freePrivateKey(pkey);
-- SSL.freeX509Chain(certChain);
-- }
+- /**
+- * Construct a new exception with the msg, cause and
+- * <a
href="https://www.openssl.org/docs/manmaster/apps/verify.html"&...
code</a> .
+- */
+- public OpenSslCertificateException(String message, Throwable cause, int errorCode)
{
+- super(message, cause);
+- this.errorCode = checkErrorCode(errorCode);
- }
-
-- private void setKeyMaterial(long ssl, String alias) throws SSLException {
-- long keyBio = 0;
-- long keyCertChainBio = 0;
-- long keyCertChainBio2 = 0;
--
-- try {
-- // TODO: Should we cache these and so not need to do a memory copy all the
time ?
-- X509Certificate[] certificates = keyManager.getCertificateChain(alias);
-- if (certificates == null || certificates.length == 0) {
-- return;
-- }
--
-- PrivateKey key = keyManager.getPrivateKey(alias);
--
-- // Only encode one time
-- PemEncoded encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT,
true, certificates);
-- try {
-- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
--
-- if (key != null) {
-- keyBio = toBIO(key);
-- }
-- SSL.setCertificateBio(ssl, keyCertChainBio, keyBio, password);
--
-- // We may have more then one cert in the chain so add all of them now.
-- SSL.setCertificateChainBio(ssl, keyCertChainBio2, true);
-- } finally {
-- encoded.release();
-- }
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException(e);
-- } finally {
-- freeBio(keyBio);
-- freeBio(keyCertChainBio);
-- freeBio(keyCertChainBio2);
-- }
+- /**
+- * Construct a new exception with the cause and
+- * <a
href="https://www.openssl.org/docs/manmaster/apps/verify.html"&...
code</a> .
+- */
+- public OpenSslCertificateException(Throwable cause, int errorCode) {
+- this(null, cause, errorCode);
- }
-
-- protected String chooseClientAlias(@SuppressWarnings("unused")
ReferenceCountedOpenSslEngine engine,
-- String[] keyTypes, X500Principal[] issuer) {
-- return keyManager.chooseClientAlias(keyTypes, issuer, null);
+- /**
+- * Return the <a
href="https://www.openssl.org/docs/man1.0.2/apps/verify.html"&g...
code</a> to use.
+- */
+- public int errorCode() {
+- return errorCode;
- }
-
-- protected String chooseServerAlias(@SuppressWarnings("unused")
ReferenceCountedOpenSslEngine engine, String type) {
-- return keyManager.chooseServerAlias(type, null, null);
+- private static int checkErrorCode(int errorCode) {
+- // Call OpenSsl.isAvailable() to ensure we try to load the native lib as
CertificateVerifier.isValid(...)
+- // will depend on it. If loading fails we will just skip the validation.
+- if (OpenSsl.isAvailable() && !CertificateVerifier.isValid(errorCode)) {
+- throw new IllegalArgumentException("errorCode '" + errorCode
+
+- "' invalid, see
https://www.openssl.org/docs/man1.0.2/apps/verify.html.");
+- }
+- return errorCode;
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
deleted file mode 100644
-index f57434b..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+index 7f9b39a8dd..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+++ /dev/null
-@@ -1,373 +0,0 @@
+@@ -1,208 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1313,143 +1613,88 @@ index f57434b..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.ServerContext;
-import io.netty.internal.tcnative.SSL;
-
-import java.io.File;
+-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-
--import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-
--import static
io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.newSessionContext;
+-import static
io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext;
-
-/**
-- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
- * <p>This class will use a finalizer to ensure native resources are automatically
cleaned up. To avoid finalizers
-- * and manually release the native memory see {@link
ReferenceCountedOpenSslServerContext}.
+- * and manually release the native memory see {@link
ReferenceCountedOpenSslClientContext}.
- */
--public final class OpenSslServerContext extends OpenSslContext {
-- private final OpenSslServerSessionContext sessionContext;
-- private final OpenSslKeyMaterialManager keyMaterialManager;
+-public final class OpenSslClientContext extends OpenSslContext {
+- private final OpenSslSessionContext sessionContext;
-
- /**
- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException {
-- this(certChainFile, keyFile, null);
+- public OpenSslClientContext() throws SSLException {
+- this(null, null, null, null, null, null, null,
IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
- }
-
- /**
- * Creates a new instance.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
+- * @param certChainFile an X.509 certificate chain file in PEM format.
+- * {@code null} to use the system default
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword)
throws SSLException {
-- this(certChainFile, keyFile, keyPassword, null,
IdentityCipherSuiteFilter.INSTANCE,
-- ApplicationProtocolConfig.DISABLED, 0, 0);
+- public OpenSslClientContext(File certChainFile) throws SSLException {
+- this(certChainFile, null);
- }
-
- /**
- * Creates a new instance.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param apn Provides a means to configure parameters related to application
protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword,
-- Iterable<String> ciphers, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, ciphers,
IdentityCipherSuiteFilter.INSTANCE,
-- apn, sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param nextProtocols the application layer protocols to accept, in the order of
preference.
-- * {@code null} to disable TLS NPN/ALPN extension.
-- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
-- * {@code 0} to use the default value.
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default.
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword,
-- Iterable<String> ciphers, Iterable<String> nextProtocols,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, ciphers,
-- toApplicationProtocolConfig(nextProtocols), sessionCacheSize,
sessionTimeout);
+- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws
SSLException {
+- this(null, trustManagerFactory);
- }
-
- /**
- * Creates a new instance.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param config Application protocol config.
-- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
-- * {@code 0} to use the default value.
+- * @param certChainFile an X.509 certificate chain file in PEM format.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default.
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory
trustManagerFactory,
-- Iterable<String> ciphers, ApplicationProtocolConfig config,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers,
-- toNegotiator(config), sessionCacheSize, sessionTimeout);
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory
trustManagerFactory) throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null, null,
+- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
- }
-
- /**
- * Creates a new instance.
- *
- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default..
- * @param ciphers the cipher suites to enable, in the order of preference.
- * {@code null} to use the default cipher suites.
-- * @param apn Application protocol negotiator.
+- * @param apn Provides a means to configure parameters related to application
protocol negotiation.
- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
- * {@code 0} to use the default value.
- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
@@ -1457,21 +1702,20 @@ index f57434b..0000000
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory
trustManagerFactory,
-- Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
-- ciphers, null, apn, sessionCacheSize, sessionTimeout);
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory
trustManagerFactory, Iterable<String> ciphers,
+- ApplicationProtocolConfig apn, long sessionCacheSize,
long sessionTimeout)
+- throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null, ciphers,
IdentityCipherSuiteFilter.INSTANCE,
+- apn, sessionCacheSize, sessionTimeout);
- }
-
- /**
- * Creates a new instance.
- *
- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default..
- * @param ciphers the cipher suites to enable, in the order of preference.
- * {@code null} to use the default cipher suites.
- * @param cipherFilter a filter to apply over the supplied list of ciphers
@@ -1483,129 +1727,38 @@ index f57434b..0000000
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, null, certChainFile, keyFile, keyPassword, null,
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory
trustManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws
SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null,
- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
- }
-
- /**
- * Creates a new instance.
-- *
- * @param trustCertCollectionFile an X.509 certificate collection file in PEM
format.
-- * This provides the certificate collection used for mutual
authentication.
- * {@code null} to use the system default
- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
-- * that verifies the certificates sent from clients.
+- * that verifies the certificates sent from servers.
- * {@code null} to use the default or the results of
parsing
-- * {@code trustCertCollectionFile}.
-- * @param keyCertChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link
KeyManager}s
-- * that is used to encrypt data being sent to clients.
-- * {@code null} to use the default or the results of
parsing
-- * {@code keyCertChainFile} and {@code keyFile}.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * Only required if {@code provider} is {@link SslProvider#JDK}
-- * @param config Provides a means to configure parameters related to application
protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslServerContext(
-- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
-- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory
keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig config,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile,
keyPassword, keyManagerFactory,
-- ciphers, cipherFilter, toNegotiator(config), sessionCacheSize,
sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param config Application protocol config.
-- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword,
-- TrustManagerFactory trustManagerFactory,
Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig config,
-- long sessionCacheSize, long sessionTimeout) throws
SSLException {
-- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
ciphers, cipherFilter,
-- toNegotiator(config), sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param apn Application protocol negotiator.
-- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}}
-- */
-- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory
trustManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
ciphers, cipherFilter,
-- apn, sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- *
-- * @param trustCertCollectionFile an X.509 certificate collection file in PEM
format.
-- * This provides the certificate collection used for mutual
authentication.
+- * {@code trustCertCollectionFile}
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format.
+- * This provides the public key for mutual authentication.
- * {@code null} to use the system default
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
-- * that verifies the certificates sent from clients.
-- * {@code null} to use the default or the results of
parsing
-- * {@code trustCertCollectionFile}.
-- * @param keyCertChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format.
+- * This provides the private key for mutual authentication.
+- * {@code null} for no mutual authentication.
- * @param keyPassword the password of the {@code keyFile}.
- * {@code null} if it's not password-protected.
-- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link
KeyManager}s
-- * that is used to encrypt data being sent to clients.
+- * Ignored if {@code keyFile} is {@code null}.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link
javax.net.ssl.KeyManager}s
+- * that is used to encrypt data being sent to servers.
- * {@code null} to use the default or the results of
parsing
- * {@code keyCertChainFile} and {@code keyFile}.
- * @param ciphers the cipher suites to enable, in the order of preference.
- * {@code null} to use the default cipher suites.
- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * Only required if {@code provider} is {@link SslProvider#JDK}
-- * @param apn Application Protocol Negotiator object
+- * @param apn Application Protocol Negotiator object.
- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
- * {@code 0} to use the default value.
- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
@@ -1613,44 +1766,31 @@ index f57434b..0000000
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
-- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory
keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory
trustManagerFactory,
+- File keyCertChainFile, File keyFile, String
keyPassword,
+- KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout)
+- throws SSLException {
- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
- toX509CertificatesInternal(keyCertChainFile),
toPrivateKeyInternal(keyFile, keyPassword),
-- keyPassword, keyManagerFactory, ciphers, cipherFilter,
-- apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false,
false);
-- }
--
-- OpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory
trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[]
protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers,
-- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout,
clientAuth, protocols, startTls,
-- enableOcsp);
+- keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, null,
sessionCacheSize,
+- sessionTimeout, false, KeyStore.getDefaultType());
- }
-
-- @SuppressWarnings("deprecation")
-- private OpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory
trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[]
protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
SSL.SSL_MODE_SERVER, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp);
-- // Create a new SSL_CTX and configure it.
+- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory
trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String
keyPassword,
+- KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn, String[] protocols,
+- long sessionCacheSize, long sessionTimeout, boolean
enableOcsp, String keyStore)
+- throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
SSL.SSL_MODE_CLIENT, keyCertChain,
+- ClientAuth.NONE, protocols, false, enableOcsp);
- boolean success = false;
- try {
-- ServerContext context = newSessionContext(this, ctx, engineMap,
trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword,
keyManagerFactory);
-- sessionContext = context.sessionContext;
-- keyMaterialManager = context.keyMaterialManager;
+- OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key,
keyPassword);
+- sessionContext = newSessionContext(this, ctx, engineMap,
trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword,
keyManagerFactory, keyStore);
- success = true;
- } finally {
- if (!success) {
@@ -1660,21 +1800,16 @@ index f57434b..0000000
- }
-
- @Override
-- public OpenSslServerSessionContext sessionContext() {
+- public OpenSslSessionContext sessionContext() {
- return sessionContext;
- }
--
-- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return keyMaterialManager;
-- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
deleted file mode 100644
-index 8c92deb..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+index f18c0643fc..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+++ /dev/null
-@@ -1,124 +0,0 @@
+@@ -1,58 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1692,119 +1827,53 @@ index 8c92deb..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
+-import io.netty.buffer.ByteBufAllocator;
-
--import java.util.concurrent.locks.Lock;
+-import java.security.cert.Certificate;
-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
-
-/**
-- * {@link OpenSslSessionContext} implementation which offers extra methods which are
only useful for the server-side.
+- * This class will use a finalizer to ensure native resources are automatically cleaned
up. To avoid finalizers
+- * and manually release the native memory see {@link ReferenceCountedOpenSslContext}.
- */
--public final class OpenSslServerSessionContext extends OpenSslSessionContext {
-- OpenSslServerSessionContext(ReferenceCountedOpenSslContext context) {
-- super(context);
-- }
--
-- @Override
-- public void setSessionTimeout(int seconds) {
-- if (seconds < 0) {
-- throw new IllegalArgumentException();
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.setSessionCacheTimeout(context.ctx, seconds);
-- } finally {
-- writerLock.unlock();
-- }
-- }
--
-- @Override
-- public int getSessionTimeout() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return (int) SSLContext.getSessionCacheTimeout(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
-- }
--
-- @Override
-- public void setSessionCacheSize(int size) {
-- if (size < 0) {
-- throw new IllegalArgumentException();
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.setSessionCacheSize(context.ctx, size);
-- } finally {
-- writerLock.unlock();
-- }
+-public abstract class OpenSslContext extends ReferenceCountedOpenSslContext {
+- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apnCfg,
+- long sessionCacheSize, long sessionTimeout, int mode, Certificate[]
keyCertChain,
+- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean
enableOcsp)
+- throws SSLException {
+- super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode,
keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp, false);
- }
-
-- @Override
-- public int getSessionCacheSize() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return (int) SSLContext.getSessionCacheSize(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
+- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
+- long sessionTimeout, int mode, Certificate[] keyCertChain,
+- ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode,
keyCertChain, clientAuth, protocols,
+- startTls, enableOcsp, false);
- }
-
- @Override
-- public void setSessionCacheEnabled(boolean enabled) {
-- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
--
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.setSessionCacheMode(context.ctx, mode);
-- } finally {
-- writerLock.unlock();
-- }
+- final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort,
boolean jdkCompatibilityMode) {
+- return new OpenSslEngine(this, alloc, peerHost, peerPort,
jdkCompatibilityMode);
- }
-
- @Override
-- public boolean isSessionCacheEnabled() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.getSessionCacheMode(context.ctx) ==
SSL.SSL_SESS_CACHE_SERVER;
-- } finally {
-- readerLock.unlock();
-- }
-- }
--
-- /**
-- * Set the context within which session be reused (server side only)
-- * See <a
href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context...
-- * man SSL_CTX_set_session_id_context</a>
-- *
-- * @param sidCtx can be any kind of binary data, it is therefore possible to use
e.g. the name
-- * of the application and/or the hostname and/or service name
-- * @return {@code true} if success, {@code false} otherwise.
-- */
-- public boolean setSessionIdContext(byte[] sidCtx) {
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- return SSLContext.setSessionIdContext(context.ctx, sidCtx);
-- } finally {
-- writerLock.unlock();
-- }
+- @SuppressWarnings("FinalizeDeclaration")
+- protected final void finalize() throws Throwable {
+- super.finalize();
+- OpenSsl.releaseIfNeeded(this);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
deleted file mode 100644
-index 846a968..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+index a700dabf39..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+++ /dev/null
-@@ -1,137 +0,0 @@
+@@ -1,41 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1822,132 +1891,36 @@ index 846a968..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.util.internal.ObjectUtil;
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
--import io.netty.internal.tcnative.SessionTicketKey;
+-import io.netty.buffer.ByteBufAllocator;
-
--import javax.net.ssl.SSLSession;
--import javax.net.ssl.SSLSessionContext;
--import java.util.Arrays;
--import java.util.Enumeration;
--import java.util.NoSuchElementException;
--import java.util.concurrent.locks.Lock;
+-import javax.net.ssl.SSLEngine;
-
-/**
-- * OpenSSL specific {@link SSLSessionContext} implementation.
+- * Implements a {@link SSLEngine} using
+- * <a
href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE&quo... BIO
abstractions</a>.
+- * <p>
+- * This class will use a finalizer to ensure native resources are automatically cleaned
up. To avoid finalizers
+- * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}.
- */
--public abstract class OpenSslSessionContext implements SSLSessionContext {
-- private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration();
--
-- private final OpenSslSessionStats stats;
-- final ReferenceCountedOpenSslContext context;
--
-- // IMPORTANT: We take the OpenSslContext and not just the long (which points the
native instance) to prevent
-- // the GC to collect OpenSslContext as this would also free the pointer
and so could result in a
-- // segfault when the user calls any of the methods here that try to pass
the pointer down to the native
-- // level.
-- OpenSslSessionContext(ReferenceCountedOpenSslContext context) {
-- this.context = context;
-- stats = new OpenSslSessionStats(context);
-- }
--
-- @Override
-- public SSLSession getSession(byte[] bytes) {
-- if (bytes == null) {
-- throw new NullPointerException("bytes");
-- }
-- return null;
+-public final class OpenSslEngine extends ReferenceCountedOpenSslEngine {
+- OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int
peerPort,
+- boolean jdkCompatibilityMode) {
+- super(context, alloc, peerHost, peerPort, jdkCompatibilityMode, false);
- }
-
- @Override
-- public Enumeration<byte[]> getIds() {
-- return EMPTY;
-- }
--
-- /**
-- * Sets the SSL session ticket keys of this context.
-- * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}.
-- */
-- @Deprecated
-- public void setTicketKeys(byte[] keys) {
-- if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) {
-- throw new IllegalArgumentException("keys.length % " +
SessionTicketKey.TICKET_KEY_SIZE + " != 0");
-- }
-- SessionTicketKey[] tickets = new SessionTicketKey[keys.length /
SessionTicketKey.TICKET_KEY_SIZE];
-- for (int i = 0, a = 0; i < tickets.length; i++) {
-- byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE);
-- a += SessionTicketKey.NAME_SIZE;
-- byte[] hmacKey = Arrays.copyOfRange(keys, a,
SessionTicketKey.HMAC_KEY_SIZE);
-- i += SessionTicketKey.HMAC_KEY_SIZE;
-- byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE);
-- a += SessionTicketKey.AES_KEY_SIZE;
-- tickets[i] = new SessionTicketKey(name, hmacKey, aesKey);
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
-- SSLContext.setSessionTicketKeys(context.ctx, tickets);
-- } finally {
-- writerLock.unlock();
-- }
-- }
--
-- /**
-- * Sets the SSL session ticket keys of this context.
-- */
-- public void setTicketKeys(OpenSslSessionTicketKey... keys) {
-- ObjectUtil.checkNotNull(keys, "keys");
-- SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length];
-- for (int i = 0; i < ticketKeys.length; i++) {
-- ticketKeys[i] = keys[i].key;
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
-- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys);
-- } finally {
-- writerLock.unlock();
-- }
-- }
--
-- /**
-- * Enable or disable caching of SSL sessions.
-- */
-- public abstract void setSessionCacheEnabled(boolean enabled);
--
-- /**
-- * Return {@code true} if caching of SSL sessions is enabled, {@code false}
otherwise.
-- */
-- public abstract boolean isSessionCacheEnabled();
--
-- /**
-- * Returns the stats of this context.
-- */
-- public OpenSslSessionStats stats() {
-- return stats;
-- }
--
-- private static final class EmptyEnumeration implements Enumeration<byte[]> {
-- @Override
-- public boolean hasMoreElements() {
-- return false;
-- }
--
-- @Override
-- public byte[] nextElement() {
-- throw new NoSuchElementException();
-- }
+- @SuppressWarnings("FinalizeDeclaration")
+- protected void finalize() throws Throwable {
+- super.finalize();
+- OpenSsl.releaseIfNeeded(this);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
deleted file mode 100644
-index f49b95f..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
+index 02131b4b26..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+++ /dev/null
-@@ -1,253 +0,0 @@
+@@ -1,35 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1963,252 +1936,524 @@ index f49b95f..0000000
- * License for the specific language governing permissions and limitations
- * under the License.
- */
--
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SSLContext;
+-interface OpenSslEngineMap {
-
--import java.util.concurrent.locks.Lock;
+- /**
+- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and
+- * return it.
+- */
+- ReferenceCountedOpenSslEngine remove(long ssl);
-
--/**
-- * Stats exposed by an OpenSSL session context.
+- /**
+- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}.
+- */
+- void add(ReferenceCountedOpenSslEngine engine);
+-
+- /**
+- * Get the {@link OpenSslEngine} for the given {@code ssl} address.
+- */
+- ReferenceCountedOpenSslEngine get(long ssl);
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
+deleted file mode 100644
+index 7acbf70cfe..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
++++ /dev/null
+@@ -1,127 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
- *
-- * @see <a
href="https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_numbe...
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
- */
--public final class OpenSslSessionStats {
+-package io.netty.handler.ssl;
-
-- private final ReferenceCountedOpenSslContext context;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.X509ExtendedKeyManager;
+-import javax.net.ssl.X509KeyManager;
+-import javax.security.auth.x500.X500Principal;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-import java.util.HashMap;
+-import java.util.HashSet;
+-import java.util.Map;
+-import java.util.Set;
-
-- // IMPORTANT: We take the OpenSslContext and not just the long (which points the
native instance) to prevent
-- // the GC to collect OpenSslContext as this would also free the pointer
and so could result in a
-- // segfault when the user calls any of the methods here that try to pass
the pointer down to the native
-- // level.
-- OpenSslSessionStats(ReferenceCountedOpenSslContext context) {
-- this.context = context;
+-
+-/**
+- * Manages key material for {@link OpenSslEngine}s and so set the right {@link
PrivateKey}s and
+- * {@link X509Certificate}s.
+- */
+-final class OpenSslKeyMaterialManager {
+-
+- // Code in this class is inspired by code of conscrypts:
+- // -
https://android.googlesource.com/platform/external/
+- // conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java
+- // -
https://android.googlesource.com/platform/external/
+- // conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java
+- //
+- static final String KEY_TYPE_RSA = "RSA";
+- static final String KEY_TYPE_DH_RSA = "DH_RSA";
+- static final String KEY_TYPE_EC = "EC";
+- static final String KEY_TYPE_EC_EC = "EC_EC";
+- static final String KEY_TYPE_EC_RSA = "EC_RSA";
+-
+- // key type mappings for types.
+- private static final Map<String, String> KEY_TYPES = new HashMap<String,
String>();
+- static {
+- KEY_TYPES.put("RSA", KEY_TYPE_RSA);
+- KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA);
+- KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA);
+- KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC);
+- KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA);
+- KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC);
+- KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA);
- }
-
-- /**
-- * Returns the current number of sessions in the internal session cache.
-- */
-- public long number() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionNumber(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- private final OpenSslKeyMaterialProvider provider;
+-
+- OpenSslKeyMaterialManager(OpenSslKeyMaterialProvider provider) {
+- this.provider = provider;
- }
-
-- /**
-- * Returns the number of started SSL/TLS handshakes in client mode.
-- */
-- public long connect() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionConnect(context.ctx);
-- } finally {
-- readerLock.unlock();
+- void setKeyMaterialServerSide(ReferenceCountedOpenSslEngine engine) throws
SSLException {
+- String[] authMethods = engine.authMethods();
+- if (authMethods.length == 0) {
+- return;
+- }
+- Set<String> aliases = new HashSet<String>(authMethods.length);
+- for (String authMethod : authMethods) {
+- String type = KEY_TYPES.get(authMethod);
+- if (type != null) {
+- String alias = chooseServerAlias(engine, type);
+- if (alias != null && aliases.add(alias)) {
+- if (!setKeyMaterial(engine, alias)) {
+- return;
+- }
+- }
+- }
- }
- }
-
-- /**
-- * Returns the number of successfully established SSL/TLS sessions in client mode.
-- */
-- public long connectGood() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionConnectGood(context.ctx);
-- } finally {
-- readerLock.unlock();
+- void setKeyMaterialClientSide(ReferenceCountedOpenSslEngine engine, String[]
keyTypes,
+- X500Principal[] issuer) throws SSLException {
+- String alias = chooseClientAlias(engine, keyTypes, issuer);
+- // Only try to set the keymaterial if we have a match. This is also consistent
with what OpenJDK does:
+- //
http://hg.openjdk.java.net/jdk/jdk11/file/76072a077ee1/
+- // src/java.base/share/classes/sun/security/ssl/CertificateRequest.java#l362
+- if (alias != null) {
+- setKeyMaterial(engine, alias);
- }
- }
-
-- /**
-- * Returns the number of start renegotiations in client mode.
-- */
-- public long connectRenegotiate() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
+- private boolean setKeyMaterial(ReferenceCountedOpenSslEngine engine, String alias)
throws SSLException {
+- OpenSslKeyMaterial keyMaterial = null;
- try {
-- return SSLContext.sessionConnectRenegotiate(context.ctx);
+- keyMaterial = provider.chooseKeyMaterial(engine.alloc, alias);
+- return keyMaterial == null || engine.setKeyMaterial(keyMaterial);
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException(e);
- } finally {
-- readerLock.unlock();
+- if (keyMaterial != null) {
+- keyMaterial.release();
+- }
+- }
+- }
+- private String chooseClientAlias(ReferenceCountedOpenSslEngine engine,
+- String[] keyTypes, X500Principal[] issuer) {
+- X509KeyManager manager = provider.keyManager();
+- if (manager instanceof X509ExtendedKeyManager) {
+- return ((X509ExtendedKeyManager) manager).chooseEngineClientAlias(keyTypes,
issuer, engine);
- }
+- return manager.chooseClientAlias(keyTypes, issuer, null);
- }
-
-- /**
-- * Returns the number of started SSL/TLS handshakes in server mode.
-- */
-- public long accept() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionAccept(context.ctx);
-- } finally {
-- readerLock.unlock();
+- private String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type)
{
+- X509KeyManager manager = provider.keyManager();
+- if (manager instanceof X509ExtendedKeyManager) {
+- return ((X509ExtendedKeyManager) manager).chooseEngineServerAlias(type,
null, engine);
- }
+- return manager.chooseServerAlias(type, null, null);
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
+deleted file mode 100644
+index f931fcfdbb..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
++++ /dev/null
+@@ -1,154 +0,0 @@
+-/*
+- * Copyright 2018 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.buffer.UnpooledByteBufAllocator;
+-import io.netty.internal.tcnative.SSL;
+-
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.X509KeyManager;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-
+-import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO;
+-
+-/**
+- * Provides {@link OpenSslKeyMaterial} for a given alias.
+- */
+-class OpenSslKeyMaterialProvider {
+-
+- private final X509KeyManager keyManager;
+- private final String password;
+-
+- OpenSslKeyMaterialProvider(X509KeyManager keyManager, String password) {
+- this.keyManager = keyManager;
+- this.password = password;
+- }
+-
+- static void validateKeyMaterialSupported(X509Certificate[] keyCertChain, PrivateKey
key, String keyPassword)
+- throws SSLException {
+- validateSupported(keyCertChain);
+- validateSupported(key, keyPassword);
+- }
+-
+- private static void validateSupported(PrivateKey key, String password) throws
SSLException {
+- if (key == null) {
+- return;
+- }
+-
+- long pkeyBio = 0;
+- long pkey = 0;
-
-- /**
-- * Returns the number of successfully established SSL/TLS sessions in server mode.
-- */
-- public long acceptGood() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
- try {
-- return SSLContext.sessionAcceptGood(context.ctx);
+- pkeyBio = toBIO(UnpooledByteBufAllocator.DEFAULT, key);
+- pkey = SSL.parsePrivateKey(pkeyBio, password);
+- } catch (Exception e) {
+- throw new SSLException("PrivateKey type not supported " +
key.getFormat(), e);
- } finally {
-- readerLock.unlock();
+- SSL.freeBIO(pkeyBio);
+- if (pkey != 0) {
+- SSL.freePrivateKey(pkey);
+- }
- }
- }
-
-- /**
-- * Returns the number of start renegotiations in server mode.
-- */
-- public long acceptRenegotiate() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
+- private static void validateSupported(X509Certificate[] certificates) throws
SSLException {
+- if (certificates == null || certificates.length == 0) {
+- return;
+- }
+-
+- long chainBio = 0;
+- long chain = 0;
+- PemEncoded encoded = null;
- try {
-- return SSLContext.sessionAcceptRenegotiate(context.ctx);
+- encoded = PemX509Certificate.toPEM(UnpooledByteBufAllocator.DEFAULT, true,
certificates);
+- chainBio = toBIO(UnpooledByteBufAllocator.DEFAULT, encoded.retain());
+- chain = SSL.parseX509Chain(chainBio);
+- } catch (Exception e) {
+- throw new SSLException("Certificate type not supported", e);
- } finally {
-- readerLock.unlock();
+- SSL.freeBIO(chainBio);
+- if (chain != 0) {
+- SSL.freeX509Chain(chain);
+- }
+- if (encoded != null) {
+- encoded.release();
+- }
- }
- }
-
- /**
-- * Returns the number of successfully reused sessions. In client mode, a session set
with {@code SSL_set_session}
-- * successfully reused is counted as a hit. In server mode, a session successfully
retrieved from internal or
-- * external cache is counted as a hit.
+- * Returns the underlying {@link X509KeyManager} that is used.
- */
-- public long hits() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionHits(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- X509KeyManager keyManager() {
+- return keyManager;
- }
-
- /**
-- * Returns the number of successfully retrieved sessions from the external session
cache in server mode.
+- * Returns the {@link OpenSslKeyMaterial} or {@code null} (if none) that should be
used during the handshake by
+- * OpenSSL.
- */
-- public long cbHits() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
+- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias)
throws Exception {
+- X509Certificate[] certificates = keyManager.getCertificateChain(alias);
+- if (certificates == null || certificates.length == 0) {
+- return null;
+- }
+-
+- PrivateKey key = keyManager.getPrivateKey(alias);
+- PemEncoded encoded = PemX509Certificate.toPEM(allocator, true, certificates);
+- long chainBio = 0;
+- long pkeyBio = 0;
+- long chain = 0;
+- long pkey = 0;
- try {
-- return SSLContext.sessionCbHits(context.ctx);
+- chainBio = toBIO(allocator, encoded.retain());
+- chain = SSL.parseX509Chain(chainBio);
+-
+- OpenSslKeyMaterial keyMaterial;
+- if (key instanceof OpenSslPrivateKey) {
+- keyMaterial = ((OpenSslPrivateKey) key).newKeyMaterial(chain,
certificates);
+- } else {
+- pkeyBio = toBIO(allocator, key);
+- pkey = key == null ? 0 : SSL.parsePrivateKey(pkeyBio, password);
+- keyMaterial = new DefaultOpenSslKeyMaterial(chain, pkey, certificates);
+- }
+-
+- // See the chain and pkey to 0 so we will not release it as the ownership
was
+- // transferred to OpenSslKeyMaterial.
+- chain = 0;
+- pkey = 0;
+- return keyMaterial;
- } finally {
-- readerLock.unlock();
+- SSL.freeBIO(chainBio);
+- SSL.freeBIO(pkeyBio);
+- if (chain != 0) {
+- SSL.freeX509Chain(chain);
+- }
+- if (pkey != 0) {
+- SSL.freePrivateKey(pkey);
+- }
+- encoded.release();
- }
- }
-
- /**
-- * Returns the number of sessions proposed by clients that were not found in the
internal session cache
-- * in server mode.
+- * Will be invoked once the provider should be destroyed.
- */
-- public long misses() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionMisses(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- void destroy() {
+- // NOOP.
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
+deleted file mode 100644
+index c2e4f108b7..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
++++ /dev/null
+@@ -1,191 +0,0 @@
+-/*
+- * Copyright 2018 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- /**
-- * Returns the number of sessions proposed by clients and either found in the
internal or external session cache
-- * in server mode, but that were invalid due to timeout. These sessions are not
included in the {@link #hits()}
-- * count.
-- */
-- public long timeouts() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTimeouts(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.IllegalReferenceCountException;
+-import io.netty.util.internal.EmptyArrays;
+-
+-import javax.security.auth.Destroyable;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-
+-final class OpenSslPrivateKey extends AbstractReferenceCounted implements PrivateKey {
+-
+- private long privateKeyAddress;
+-
+- OpenSslPrivateKey(long privateKeyAddress) {
+- this.privateKeyAddress = privateKeyAddress;
- }
-
-- /**
-- * Returns the number of sessions that were removed because the maximum session
cache size was exceeded.
-- */
-- public long cacheFull() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionCacheFull(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- @Override
+- public String getAlgorithm() {
+- return "unknown";
- }
-
-- /**
-- * Returns the number of times a client presented a ticket that did not match any
key in the list.
-- */
-- public long ticketKeyFail() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyFail(context.ctx);
-- } finally {
-- readerLock.unlock();
+- @Override
+- public String getFormat() {
+- // As we do not support encoding we should return null as stated in the javadocs
of PrivateKey.
+- return null;
+- }
+-
+- @Override
+- public byte[] getEncoded() {
+- return null;
+- }
+-
+- private long privateKeyAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
- }
+- return privateKeyAddress;
+- }
+-
+- @Override
+- protected void deallocate() {
+- SSL.freePrivateKey(privateKeyAddress);
+- privateKeyAddress = 0;
+- }
+-
+- @Override
+- public OpenSslPrivateKey retain() {
+- super.retain();
+- return this;
+- }
+-
+- @Override
+- public OpenSslPrivateKey retain(int increment) {
+- super.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public OpenSslPrivateKey touch() {
+- super.touch();
+- return this;
+- }
+-
+- @Override
+- public OpenSslPrivateKey touch(Object hint) {
+- return this;
- }
-
- /**
-- * Returns the number of times a client did not present a ticket and we issued a new
one
+- * NOTE: This is a JDK8 interface/method. Due to backwards compatibility
+- * reasons it's not possible to slap the {@code @Override} annotation onto
+- * this method.
+- *
+- * @see Destroyable#destroy()
- */
-- public long ticketKeyNew() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyNew(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- @Override
+- public void destroy() {
+- release(refCnt());
- }
-
- /**
-- * Returns the number of times a client presented a ticket derived from an older
key,
-- * and we upgraded to the primary key.
+- * NOTE: This is a JDK8 interface/method. Due to backwards compatibility
+- * reasons it's not possible to slap the {@code @Override} annotation onto
+- * this method.
+- *
+- * @see Destroyable#isDestroyed()
- */
-- public long ticketKeyRenew() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyRenew(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- @Override
+- public boolean isDestroyed() {
+- return refCnt() == 0;
- }
-
- /**
-- * Returns the number of times a client presented a ticket derived from the primary
key.
+- * Create a new {@link OpenSslKeyMaterial} which uses the private key that is held
by {@link OpenSslPrivateKey}.
+- *
+- * When the material is created we increment the reference count of the enclosing
{@link OpenSslPrivateKey} and
+- * decrement it again when the reference count of the {@link OpenSslKeyMaterial}
reaches {@code 0}.
- */
-- public long ticketKeyResume() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyResume(context.ctx);
-- } finally {
-- readerLock.unlock();
+- OpenSslKeyMaterial newKeyMaterial(long certificateChain, X509Certificate[] chain) {
+- return new OpenSslPrivateKeyMaterial(certificateChain, chain);
+- }
+-
+- // Package-private for unit-test only
+- final class OpenSslPrivateKeyMaterial extends AbstractReferenceCounted implements
OpenSslKeyMaterial {
+-
+- // Package-private for unit-test only
+- long certificateChain;
+- private final X509Certificate[] x509CertificateChain;
+-
+- OpenSslPrivateKeyMaterial(long certificateChain, X509Certificate[]
x509CertificateChain) {
+- this.certificateChain = certificateChain;
+- this.x509CertificateChain = x509CertificateChain == null ?
+- EmptyArrays.EMPTY_X509_CERTIFICATES : x509CertificateChain;
+- OpenSslPrivateKey.this.retain();
+- }
+-
+- @Override
+- public X509Certificate[] certificateChain() {
+- return x509CertificateChain.clone();
+- }
+-
+- @Override
+- public long certificateChainAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return certificateChain;
+- }
+-
+- @Override
+- public long privateKeyAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return OpenSslPrivateKey.this.privateKeyAddress();
+- }
+-
+- @Override
+- public OpenSslKeyMaterial touch(Object hint) {
+- OpenSslPrivateKey.this.touch(hint);
+- return this;
+- }
+-
+- @Override
+- public OpenSslKeyMaterial retain() {
+- super.retain();
+- return this;
+- }
+-
+- @Override
+- public OpenSslKeyMaterial retain(int increment) {
+- super.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public OpenSslKeyMaterial touch() {
+- OpenSslPrivateKey.this.touch();
+- return this;
+- }
+-
+- @Override
+- protected void deallocate() {
+- releaseChain();
+- OpenSslPrivateKey.this.release();
+- }
+-
+- private void releaseChain() {
+- SSL.freeX509Chain(certificateChain);
+- certificateChain = 0;
- }
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
deleted file mode 100644
-index 79f71a6..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+index d9fc877269..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
+++ /dev/null
-@@ -1,78 +0,0 @@
+@@ -1,62 +0,0 @@
-/*
-- * Copyright 2015 The Netty Project
+- * Copyright 2019 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in
compliance
@@ -2224,75 +2469,59 @@ index 79f71a6..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SessionTicketKey;
+-import io.netty.internal.tcnative.SSLPrivateKeyMethod;
+-import io.netty.util.internal.UnstableApi;
+-
+-import javax.net.ssl.SSLEngine;
-
-/**
-- * Session Ticket Key
+- * Allow to customize private key signing / decrypting (when using RSA). Only supported
when using BoringSSL atm.
- */
--public final class OpenSslSessionTicketKey {
--
-- /**
-- * Size of session ticket key name
-- */
-- public static final int NAME_SIZE = SessionTicketKey.NAME_SIZE;
-- /**
-- * Size of session ticket key HMAC key
-- */
-- public static final int HMAC_KEY_SIZE = SessionTicketKey.HMAC_KEY_SIZE;
-- /**
-- * Size of session ticket key AES key
-- */
-- public static final int AES_KEY_SIZE = SessionTicketKey.AES_KEY_SIZE;
-- /**
-- * Size of session ticker key
-- */
-- public static final int TICKET_KEY_SIZE = SessionTicketKey.TICKET_KEY_SIZE;
--
-- final SessionTicketKey key;
+-@UnstableApi
+-public interface OpenSslPrivateKeyMethod {
+- int SSL_SIGN_RSA_PKCS1_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA1;
+- int SSL_SIGN_RSA_PKCS1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA256;
+- int SSL_SIGN_RSA_PKCS1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA384;
+- int SSL_SIGN_RSA_PKCS1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA512;
+- int SSL_SIGN_ECDSA_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SHA1;
+- int SSL_SIGN_ECDSA_SECP256R1_SHA256 =
SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP256R1_SHA256;
+- int SSL_SIGN_ECDSA_SECP384R1_SHA384 =
SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP384R1_SHA384;
+- int SSL_SIGN_ECDSA_SECP521R1_SHA512 =
SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP521R1_SHA512;
+- int SSL_SIGN_RSA_PSS_RSAE_SHA256 =
SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA256;
+- int SSL_SIGN_RSA_PSS_RSAE_SHA384 =
SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA384;
+- int SSL_SIGN_RSA_PSS_RSAE_SHA512 =
SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA512;
+- int SSL_SIGN_ED25519 = SSLPrivateKeyMethod.SSL_SIGN_ED25519;
+- int SSL_SIGN_RSA_PKCS1_MD5_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_MD5_SHA1;
-
- /**
-- * Construct a OpenSslSessionTicketKey.
+- * Signs the input with the given key and returns the signed bytes.
- *
-- * @param name the name of the session ticket key
-- * @param hmacKey the HMAC key of the session ticket key
-- * @param aesKey the AES key of the session ticket key
+- * @param engine the {@link SSLEngine}
+- * @param signatureAlgorithm the algorithm to use for signing
+- * @param input the digest itself
+- * @return the signed data (must not be {@code null})
+- * @throws Exception thrown if an error is encountered during the
signing
- */
-- public OpenSslSessionTicketKey(byte[] name, byte[] hmacKey, byte[] aesKey) {
-- key = new SessionTicketKey(name.clone(), hmacKey.clone(), aesKey.clone());
-- }
--
-- /**
-- * Get name.
-- * @return the name of the session ticket key
-- */
-- public byte[] name() {
-- return key.getName().clone();
-- }
--
-- /**
-- * Get HMAC key.
-- * @return the HMAC key of the session ticket key
-- */
-- public byte[] hmacKey() {
-- return key.getHmacKey().clone();
-- }
+- byte[] sign(SSLEngine engine, int signatureAlgorithm, byte[] input) throws
Exception;
-
- /**
-- * Get AES Key.
-- * @return the AES key of the session ticket key
+- * Decrypts the input with the given key and returns the decrypted bytes.
+- *
+- * @param engine the {@link SSLEngine}
+- * @param input the input which should be decrypted
+- * @return the decrypted data (must not be {@code null})
+- * @throws Exception thrown if an error is encountered during the
decrypting
- */
-- public byte[] aesKey() {
-- return key.getAesKey().clone();
-- }
+- byte[] decrypt(SSLEngine engine, byte[] input) throws Exception;
-}
-diff --git
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
deleted file mode 100644
-index b213573..0000000
----
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
+index da342de0f2..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+++ /dev/null
-@@ -1,298 +0,0 @@
+@@ -1,367 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2014 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in
compliance
@@ -2308,295 +2537,364 @@ index b213573..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
--import io.netty.internal.tcnative.CertificateRequestedCallback;
-import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
-
+-import java.io.File;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
--import java.util.HashSet;
--import java.util.Set;
-
+-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.net.ssl.X509ExtendedTrustManager;
--import javax.net.ssl.X509KeyManager;
--import javax.net.ssl.X509TrustManager;
--import javax.security.auth.x500.X500Principal;
+-
+-import static
io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.newSessionContext;
-
-/**
-- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
-- * <p>Instances of this class must be {@link #release() released} or else native
memory will leak!
-- *
-- * <p>Instances of this class <strong>must not</strong> be released
before any {@link ReferenceCountedOpenSslEngine}
-- * which depends upon the instance of this class is released. Otherwise if any method
of
-- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI
resources the JVM may crash.
+- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * <p>This class will use a finalizer to ensure native resources are automatically
cleaned up. To avoid finalizers
+- * and manually release the native memory see {@link
ReferenceCountedOpenSslServerContext}.
- */
--public final class ReferenceCountedOpenSslClientContext extends
ReferenceCountedOpenSslContext {
-- private static final InternalLogger logger =
--
InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class);
-- private final OpenSslSessionContext sessionContext;
+-public final class OpenSslServerContext extends OpenSslContext {
+- private final OpenSslServerSessionContext sessionContext;
-
-- ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection,
TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key,
String keyPassword,
-- KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
-- String[] protocols, long sessionCacheSize, long
sessionTimeout,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
SSL.SSL_MODE_CLIENT, keyCertChain,
-- ClientAuth.NONE, protocols, false, enableOcsp, true);
-- boolean success = false;
-- try {
-- sessionContext = newSessionContext(this, ctx, engineMap,
trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword,
keyManagerFactory);
-- success = true;
-- } finally {
-- if (!success) {
-- release();
-- }
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException {
+- this(certChainFile, keyFile, null);
- }
-
-- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return null;
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword)
throws SSLException {
+- this(certChainFile, keyFile, keyPassword, null,
IdentityCipherSuiteFilter.INSTANCE,
+- ApplicationProtocolConfig.DISABLED, 0, 0);
- }
-
-- @Override
-- public OpenSslSessionContext sessionContext() {
-- return sessionContext;
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param apn Provides a means to configure parameters related to application
protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable<String> ciphers, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, ciphers,
IdentityCipherSuiteFilter.INSTANCE,
+- apn, sessionCacheSize, sessionTimeout);
- }
-
-- static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz,
long ctx,
-- OpenSslEngineMap engineMap,
-- X509Certificate[]
trustCertCollection,
-- TrustManagerFactory
trustManagerFactory,
-- X509Certificate[] keyCertChain,
PrivateKey key, String keyPassword,
-- KeyManagerFactory keyManagerFactory)
throws SSLException {
-- if (key == null && keyCertChain != null || key != null &&
keyCertChain == null) {
-- throw new IllegalArgumentException(
-- "Either both keyCertChain and key needs to be null or none of
them");
-- }
-- try {
-- if (!OpenSsl.useKeyManagerFactory()) {
-- if (keyManagerFactory != null) {
-- throw new IllegalArgumentException(
-- "KeyManagerFactory not supported");
-- }
-- if (keyCertChain != null/* && key != null*/) {
-- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
-- }
-- } else {
-- // javadocs state that keyManagerFactory has precedent over
keyCertChain
-- if (keyManagerFactory == null && keyCertChain != null) {
-- keyManagerFactory = buildKeyManagerFactory(
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- }
--
-- if (keyManagerFactory != null) {
-- X509KeyManager keyManager =
chooseX509KeyManager(keyManagerFactory.getKeyManagers());
-- OpenSslKeyMaterialManager materialManager =
useExtendedKeyManager(keyManager) ?
-- new OpenSslExtendedKeyMaterialManager(
-- (X509ExtendedKeyManager) keyManager, keyPassword) :
-- new OpenSslKeyMaterialManager(keyManager, keyPassword);
-- SSLContext.setCertRequestedCallback(ctx, new
OpenSslCertificateRequestedCallback(
-- engineMap, materialManager));
-- }
-- }
-- } catch (Exception e) {
-- throw new SSLException("failed to set certificate and key", e);
-- }
--
-- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
--
-- try {
-- if (trustCertCollection != null) {
-- trustManagerFactory = buildTrustManagerFactory(trustCertCollection,
trustManagerFactory);
-- } else if (trustManagerFactory == null) {
-- trustManagerFactory = TrustManagerFactory.getInstance(
-- TrustManagerFactory.getDefaultAlgorithm());
-- trustManagerFactory.init((KeyStore) null);
-- }
-- final X509TrustManager manager =
chooseTrustManager(trustManagerFactory.getTrustManagers());
--
-- // IMPORTANT: The callbacks set for verification must be static to prevent
memory leak as
-- // otherwise the context can never be collected. This is because
the JNI code holds
-- // a global reference to the callbacks.
-- //
-- // See
https://github.com/netty/netty/issues/5372
--
-- // Use this to prevent an error when running on java < 7
-- if (useExtendedTrustManager(manager)) {
-- SSLContext.setCertVerifyCallback(ctx,
-- new ExtendedTrustManagerVerifyCallback(engineMap,
(X509ExtendedTrustManager) manager));
-- } else {
-- SSLContext.setCertVerifyCallback(ctx, new
TrustManagerVerifyCallback(engineMap, manager));
-- }
-- } catch (Exception e) {
-- throw new SSLException("unable to setup trustmanager", e);
-- }
-- return new OpenSslClientSessionContext(thiz);
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param nextProtocols the application layer protocols to accept, in the order of
preference.
+- * {@code null} to disable TLS NPN/ALPN extension.
+- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable<String> ciphers, Iterable<String> nextProtocols,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, ciphers,
+- toApplicationProtocolConfig(nextProtocols), sessionCacheSize,
sessionTimeout);
- }
-
-- // No cache is currently supported for client side mode.
-- static final class OpenSslClientSessionContext extends OpenSslSessionContext {
-- OpenSslClientSessionContext(ReferenceCountedOpenSslContext context) {
-- super(context);
-- }
--
-- @Override
-- public void setSessionTimeout(int seconds) {
-- if (seconds < 0) {
-- throw new IllegalArgumentException();
-- }
-- }
--
-- @Override
-- public int getSessionTimeout() {
-- return 0;
-- }
--
-- @Override
-- public void setSessionCacheSize(int size) {
-- if (size < 0) {
-- throw new IllegalArgumentException();
-- }
-- }
--
-- @Override
-- public int getSessionCacheSize() {
-- return 0;
-- }
--
-- @Override
-- public void setSessionCacheEnabled(boolean enabled) {
-- // ignored
-- }
--
-- @Override
-- public boolean isSessionCacheEnabled() {
-- return false;
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param config Application protocol config.
+- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory
trustManagerFactory,
+- Iterable<String> ciphers, ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers,
+- toNegotiator(config), sessionCacheSize, sessionTimeout);
- }
-
-- private static final class TrustManagerVerifyCallback extends
AbstractCertificateVerifier {
-- private final X509TrustManager manager;
--
-- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager)
{
-- super(engineMap);
-- this.manager = manager;
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param apn Application protocol negotiator.
+- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory
trustManagerFactory,
+- Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
+- ciphers, null, apn, sessionCacheSize, sessionTimeout);
+- }
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
String auth)
-- throws Exception {
-- manager.checkServerTrusted(peerCerts, auth);
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param apn Provides a means to configure parameters related to application
protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, null, certChainFile, keyFile, keyPassword, null,
+- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
- }
-
-- private static final class ExtendedTrustManagerVerifyCallback extends
AbstractCertificateVerifier {
-- private final X509ExtendedTrustManager manager;
+- /**
+- * Creates a new instance.
+- *
+- * @param trustCertCollectionFile an X.509 certificate collection file in PEM
format.
+- * This provides the certificate collection used for mutual
authentication.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
+- * that verifies the certificates sent from clients.
+- * {@code null} to use the default or the results of
parsing
+- * {@code trustCertCollectionFile}.
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link
KeyManager}s
+- * that is used to encrypt data being sent to clients.
+- * {@code null} to use the default or the results of
parsing
+- * {@code keyCertChainFile} and {@code keyFile}.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * Only required if {@code provider} is {@link SslProvider#JDK}
+- * @param config Provides a means to configure parameters related to application
protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory
keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile,
keyPassword, keyManagerFactory,
+- ciphers, cipherFilter, toNegotiator(config), sessionCacheSize,
sessionTimeout);
+- }
-
-- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap,
X509ExtendedTrustManager manager) {
-- super(engineMap);
-- this.manager = manager;
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param config Application protocol config.
+- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword,
+- TrustManagerFactory trustManagerFactory,
Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws
SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
ciphers, cipherFilter,
+- toNegotiator(config), sessionCacheSize, sessionTimeout);
+- }
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
String auth)
-- throws Exception {
-- manager.checkServerTrusted(peerCerts, auth, engine);
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param apn Application protocol negotiator.
+- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory
trustManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
ciphers, cipherFilter,
+- apn, sessionCacheSize, sessionTimeout);
- }
-
-- private static final class OpenSslCertificateRequestedCallback implements
CertificateRequestedCallback {
-- private final OpenSslEngineMap engineMap;
-- private final OpenSslKeyMaterialManager keyManagerHolder;
+- /**
+- * Creates a new instance.
+- *
+- *
+- * @param trustCertCollectionFile an X.509 certificate collection file in PEM
format.
+- * This provides the certificate collection used for mutual
authentication.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the
{@link TrustManager}s
+- * that verifies the certificates sent from clients.
+- * {@code null} to use the default or the results of
parsing
+- * {@code trustCertCollectionFile}.
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link
KeyManager}s
+- * that is used to encrypt data being sent to clients.
+- * {@code null} to use the default or the results of
parsing
+- * {@code keyCertChainFile} and {@code keyFile}.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * Only required if {@code provider} is {@link SslProvider#JDK}
+- * @param apn Application Protocol Negotiator object
+- * @param sessionCacheSize the size of the cache used for storing SSL session
objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in
seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory
keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
+- toX509CertificatesInternal(keyCertChainFile),
toPrivateKeyInternal(keyFile, keyPassword),
+- keyPassword, keyManagerFactory, ciphers, cipherFilter,
+- apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false,
false, KeyStore.getDefaultType());
+- }
-
-- OpenSslCertificateRequestedCallback(OpenSslEngineMap engineMap,
OpenSslKeyMaterialManager keyManagerHolder) {
-- this.engineMap = engineMap;
-- this.keyManagerHolder = keyManagerHolder;
-- }
+- OpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory
trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[]
protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers,
+- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout,
clientAuth, protocols, startTls,
+- enableOcsp, keyStore);
+- }
-
-- @Override
-- public KeyMaterial requested(long ssl, byte[] keyTypeBytes, byte[][]
asn1DerEncodedPrincipals) {
-- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-- try {
-- final Set<String> keyTypesSet =
supportedClientKeyTypes(keyTypeBytes);
-- final String[] keyTypes = keyTypesSet.toArray(new
String[keyTypesSet.size()]);
-- final X500Principal[] issuers;
-- if (asn1DerEncodedPrincipals == null) {
-- issuers = null;
-- } else {
-- issuers = new X500Principal[asn1DerEncodedPrincipals.length];
-- for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
-- issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
-- }
-- }
-- return keyManagerHolder.keyMaterial(engine, keyTypes, issuers);
-- } catch (Throwable cause) {
-- logger.debug("request of key failed", cause);
-- SSLHandshakeException e = new SSLHandshakeException("General
OpenSslEngine problem");
-- e.initCause(cause);
-- engine.handshakeException = e;
-- return null;
-- }
-- }
+- @SuppressWarnings("deprecation")
+- private OpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory
trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[]
protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
SSL.SSL_MODE_SERVER, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp);
-
-- /**
-- * Gets the supported key types for client certificates.
-- *
-- * @param clientCertificateTypes {@code ClientCertificateType} values provided
by the server.
-- * See
https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml.
-- * @return supported key types that can be used in {@code
X509KeyManager.chooseClientAlias} and
-- * {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
-- */
-- private static Set<String> supportedClientKeyTypes(byte[]
clientCertificateTypes) {
-- Set<String> result = new
HashSet<String>(clientCertificateTypes.length);
-- for (byte keyTypeCode : clientCertificateTypes) {
-- String keyType = clientKeyType(keyTypeCode);
-- if (keyType == null) {
-- // Unsupported client key type -- ignore
-- continue;
-- }
-- result.add(keyType);
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key,
keyPassword);
+- sessionContext = newSessionContext(this, ctx, engineMap,
trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword,
keyManagerFactory, keyStore);
+- success = true;
+- } finally {
+- if (!success) {
+- release();
- }
-- return result;
- }
+- }
-
-- private static String clientKeyType(byte clientCertificateType) {
-- // See also
http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
-- switch (clientCertificateType) {
-- case CertificateRequestedCallback.TLS_CT_RSA_SIGN:
-- return OpenSslKeyMaterialManager.KEY_TYPE_RSA; // RFC rsa_sign
-- case CertificateRequestedCallback.TLS_CT_RSA_FIXED_DH:
-- return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA; // RFC
rsa_fixed_dh
-- case CertificateRequestedCallback.TLS_CT_ECDSA_SIGN:
-- return OpenSslKeyMaterialManager.KEY_TYPE_EC; // RFC ecdsa_sign
-- case CertificateRequestedCallback.TLS_CT_RSA_FIXED_ECDH:
-- return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA; // RFC
rsa_fixed_ecdh
-- case CertificateRequestedCallback.TLS_CT_ECDSA_FIXED_ECDH:
-- return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC; // RFC
ecdsa_fixed_ecdh
-- default:
-- return null;
-- }
-- }
+- @Override
+- public OpenSslServerSessionContext sessionContext() {
+- return sessionContext;
- }
-}
-diff --git
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
deleted file mode 100644
-index ee049ab..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
+index 691ee0b661..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+++ /dev/null
-@@ -1,867 +0,0 @@
+@@ -1,124 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2014 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in
compliance
@@ -2612,864 +2910,874 @@ index ee049ab..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBuf;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.internal.tcnative.CertificateVerifier;
-import io.netty.internal.tcnative.SSL;
-import io.netty.internal.tcnative.SSLContext;
--import io.netty.util.AbstractReferenceCounted;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.ResourceLeakDetector;
--import io.netty.util.ResourceLeakDetectorFactory;
--import io.netty.util.ResourceLeakTracker;
--import io.netty.util.internal.PlatformDependent;
--import io.netty.util.internal.StringUtil;
--import io.netty.util.internal.SystemPropertyUtil;
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
--
--import java.security.AccessController;
--import java.security.PrivateKey;
--import java.security.PrivilegedAction;
--import java.security.cert.CertPathValidatorException;
--import java.security.cert.Certificate;
--import java.security.cert.CertificateExpiredException;
--import java.security.cert.CertificateNotYetValidException;
--import java.security.cert.CertificateRevokedException;
--import java.security.cert.X509Certificate;
--import java.util.ArrayList;
--import java.util.Arrays;
--import java.util.Collections;
--import java.util.List;
--import java.util.Map;
-
-import java.util.concurrent.locks.Lock;
--import java.util.concurrent.locks.ReadWriteLock;
--import java.util.concurrent.locks.ReentrantReadWriteLock;
--import javax.net.ssl.KeyManager;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
--import javax.net.ssl.TrustManager;
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.net.ssl.X509ExtendedTrustManager;
--import javax.net.ssl.X509KeyManager;
--import javax.net.ssl.X509TrustManager;
-
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
-
-/**
-- * An implementation of {@link SslContext} which works with libraries that support the
-- * <a
href="https://www.openssl.org/">OpenSsl</a> C library API.
-- * <p>Instances of this class must be {@link #release() released} or else native
memory will leak!
-- *
-- * <p>Instances of this class <strong>must not</strong> be released
before any {@link ReferenceCountedOpenSslEngine}
-- * which depends upon the instance of this class is released. Otherwise if any method
of
-- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI
resources the JVM may crash.
+- * {@link OpenSslSessionContext} implementation which offers extra methods which are
only useful for the server-side.
- */
--public abstract class ReferenceCountedOpenSslContext extends SslContext implements
ReferenceCounted {
-- private static final InternalLogger logger =
-- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class);
-- /**
-- * To make it easier for users to replace JDK implementation with OpenSsl version we
also use
-- * {@code jdk.tls.rejectClientInitiatedRenegotiation} to allow disabling client
initiated renegotiation.
-- * Java8+ uses this system property as well.
-- * <p>
-- * See also <a
href="http://blog.ivanristic.com/2014/03/ssl-tls-improvements-in-jav...
-- * Significant SSL/TLS improvements in Java 8</a>
-- */
-- private static final boolean JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION =
-- AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
-- @Override
-- public Boolean run() {
-- return
SystemPropertyUtil.getBoolean("jdk.tls.rejectClientInitiatedRenegotiation",
false);
-- }
-- });
+-public final class OpenSslServerSessionContext extends OpenSslSessionContext {
+- OpenSslServerSessionContext(ReferenceCountedOpenSslContext context,
OpenSslKeyMaterialProvider provider) {
+- super(context, provider);
+- }
-
-- private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE =
-- AccessController.doPrivileged(new PrivilegedAction<Integer>() {
-- @Override
-- public Integer run() {
-- return Math.max(1,
--
SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize",
-- 2048));
-- }
-- });
+- @Override
+- public void setSessionTimeout(int seconds) {
+- if (seconds < 0) {
+- throw new IllegalArgumentException();
+- }
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.setSessionCacheTimeout(context.ctx, seconds);
+- } finally {
+- writerLock.unlock();
+- }
+- }
-
-- private static final List<String> DEFAULT_CIPHERS;
-- private static final Integer DH_KEY_LENGTH;
-- private static final ResourceLeakDetector<ReferenceCountedOpenSslContext>
leakDetector =
--
ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class);
+- @Override
+- public int getSessionTimeout() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return (int) SSLContext.getSessionCacheTimeout(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- // TODO: Maybe make configurable ?
-- protected static final int VERIFY_DEPTH = 10;
+- @Override
+- public void setSessionCacheSize(int size) {
+- if (size < 0) {
+- throw new IllegalArgumentException();
+- }
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.setSessionCacheSize(context.ctx, size);
+- } finally {
+- writerLock.unlock();
+- }
+- }
-
-- /**
-- * The OpenSSL SSL_CTX object.
-- *
-- * <strong>{@link #ctxLock} must be hold while using ctx!</strong>
-- */
-- protected long ctx;
-- private final List<String> unmodifiableCiphers;
-- private final long sessionCacheSize;
-- private final long sessionTimeout;
-- private final OpenSslApplicationProtocolNegotiator apn;
-- private final int mode;
+- @Override
+- public int getSessionCacheSize() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return (int) SSLContext.getSessionCacheSize(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- // Reference Counting
-- private final ResourceLeakTracker<ReferenceCountedOpenSslContext> leak;
-- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
-- @Override
-- public ReferenceCounted touch(Object hint) {
-- if (leak != null) {
-- leak.record(hint);
-- }
+- @Override
+- public void setSessionCacheEnabled(boolean enabled) {
+- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
-
-- return ReferenceCountedOpenSslContext.this;
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.setSessionCacheMode(context.ctx, mode);
+- } finally {
+- writerLock.unlock();
- }
+- }
-
-- @Override
-- protected void deallocate() {
-- destroy();
-- if (leak != null) {
-- boolean closed = leak.close(ReferenceCountedOpenSslContext.this);
-- assert closed;
-- }
+- @Override
+- public boolean isSessionCacheEnabled() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.getSessionCacheMode(context.ctx) ==
SSL.SSL_SESS_CACHE_SERVER;
+- } finally {
+- readerLock.unlock();
- }
-- };
--
-- final Certificate[] keyCertChain;
-- final ClientAuth clientAuth;
-- final String[] protocols;
-- final boolean enableOcsp;
-- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
-- final ReadWriteLock ctxLock = new ReentrantReadWriteLock();
--
-- private volatile boolean rejectRemoteInitiatedRenegotiation;
-- private volatile int bioNonApplicationBufferSize =
DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE;
+- }
-
-- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR =
-- new OpenSslApplicationProtocolNegotiator() {
-- @Override
-- public ApplicationProtocolConfig.Protocol protocol() {
-- return ApplicationProtocolConfig.Protocol.NONE;
-- }
+- /**
+- * Set the context within which session be reused (server side only)
+- * See <a
href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context...
+- * man SSL_CTX_set_session_id_context</a>
+- *
+- * @param sidCtx can be any kind of binary data, it is therefore possible to use
e.g. the name
+- * of the application and/or the hostname and/or service name
+- * @return {@code true} if success, {@code false} otherwise.
+- */
+- public boolean setSessionIdContext(byte[] sidCtx) {
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- return SSLContext.setSessionIdContext(context.ctx, sidCtx);
+- } finally {
+- writerLock.unlock();
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+deleted file mode 100644
+index 5d471d34fb..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
++++ /dev/null
+@@ -1,158 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- @Override
-- public List<String> protocols() {
-- return Collections.emptyList();
-- }
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.internal.tcnative.SessionTicketKey;
+-import io.netty.util.internal.ObjectUtil;
-
-- @Override
-- public ApplicationProtocolConfig.SelectorFailureBehavior
selectorFailureBehavior() {
-- return
ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL;
-- }
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionContext;
+-import java.util.Arrays;
+-import java.util.Enumeration;
+-import java.util.NoSuchElementException;
+-import java.util.concurrent.locks.Lock;
-
-- @Override
-- public ApplicationProtocolConfig.SelectedListenerFailureBehavior
selectedListenerFailureBehavior() {
-- return
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT;
-- }
-- };
+-/**
+- * OpenSSL specific {@link SSLSessionContext} implementation.
+- */
+-public abstract class OpenSslSessionContext implements SSLSessionContext {
+- private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration();
-
-- static {
-- List<String> ciphers = new ArrayList<String>();
-- // XXX: Make sure to sync this list with JdkSslEngineFactory.
-- Collections.addAll(
-- ciphers,
-- "ECDHE-ECDSA-AES256-GCM-SHA384",
-- "ECDHE-ECDSA-AES128-GCM-SHA256",
-- "ECDHE-RSA-AES128-GCM-SHA256",
-- "ECDHE-RSA-AES128-SHA",
-- "ECDHE-RSA-AES256-SHA",
-- "AES128-GCM-SHA256",
-- "AES128-SHA",
-- "AES256-SHA");
-- DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers);
+- private final OpenSslSessionStats stats;
-
-- if (logger.isDebugEnabled()) {
-- logger.debug("Default cipher suite (OpenSSL): " + ciphers);
-- }
+- // The OpenSslKeyMaterialProvider is not really used by the OpenSslSessionContext
but only be stored here
+- // to make it easier to destroy it later because the ReferenceCountedOpenSslContext
will hold a reference
+- // to OpenSslSessionContext.
+- private final OpenSslKeyMaterialProvider provider;
-
-- Integer dhLen = null;
+- final ReferenceCountedOpenSslContext context;
-
-- try {
-- String dhKeySize = AccessController.doPrivileged(new
PrivilegedAction<String>() {
-- @Override
-- public String run() {
-- return
SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize");
-- }
-- });
-- if (dhKeySize != null) {
-- try {
-- dhLen = Integer.valueOf(dhKeySize);
-- } catch (NumberFormatException e) {
-- logger.debug("ReferenceCountedOpenSslContext supports
-Djdk.tls.ephemeralDHKeySize={int}, but got: "
-- + dhKeySize);
-- }
-- }
-- } catch (Throwable ignore) {
-- // ignore
-- }
-- DH_KEY_LENGTH = dhLen;
+- // IMPORTANT: We take the OpenSslContext and not just the long (which points the
native instance) to prevent
+- // the GC to collect OpenSslContext as this would also free the pointer
and so could result in a
+- // segfault when the user calls any of the methods here that try to pass
the pointer down to the native
+- // level.
+- OpenSslSessionContext(ReferenceCountedOpenSslContext context,
OpenSslKeyMaterialProvider provider) {
+- this.context = context;
+- this.provider = provider;
+- stats = new OpenSslSessionStats(context);
- }
-
-- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter
cipherFilter,
-- ApplicationProtocolConfig apnCfg, long
sessionCacheSize, long sessionTimeout,
-- int mode, Certificate[] keyCertChain, ClientAuth
clientAuth, String[] protocols,
-- boolean startTls, boolean enableOcsp, boolean
leakDetection) throws SSLException {
-- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize,
sessionTimeout, mode, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp, leakDetection);
+- final boolean useKeyManager() {
+- return provider != null;
- }
-
-- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter
cipherFilter,
-- OpenSslApplicationProtocolNegotiator apn, long
sessionCacheSize,
-- long sessionTimeout, int mode, Certificate[]
keyCertChain,
-- ClientAuth clientAuth, String[] protocols, boolean
startTls, boolean enableOcsp,
-- boolean leakDetection) throws SSLException {
-- super(startTls);
+- @Override
+- public SSLSession getSession(byte[] bytes) {
+- ObjectUtil.checkNotNull(bytes, "bytes");
+- return null;
+- }
-
-- OpenSsl.ensureAvailability();
+- @Override
+- public Enumeration<byte[]> getIds() {
+- return EMPTY;
+- }
-
-- if (enableOcsp && !OpenSsl.isOcspSupported()) {
-- throw new IllegalStateException("OCSP is not supported.");
+- /**
+- * Sets the SSL session ticket keys of this context.
+- * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}.
+- */
+- @Deprecated
+- public void setTicketKeys(byte[] keys) {
+- if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) {
+- throw new IllegalArgumentException("keys.length % " +
SessionTicketKey.TICKET_KEY_SIZE + " != 0");
- }
--
-- if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) {
-- throw new IllegalArgumentException("mode most be either
SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT");
+- SessionTicketKey[] tickets = new SessionTicketKey[keys.length /
SessionTicketKey.TICKET_KEY_SIZE];
+- for (int i = 0, a = 0; i < tickets.length; i++) {
+- byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE);
+- a += SessionTicketKey.NAME_SIZE;
+- byte[] hmacKey = Arrays.copyOfRange(keys, a,
SessionTicketKey.HMAC_KEY_SIZE);
+- i += SessionTicketKey.HMAC_KEY_SIZE;
+- byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE);
+- a += SessionTicketKey.AES_KEY_SIZE;
+- tickets[i] = new SessionTicketKey(name, hmacKey, aesKey);
- }
-- leak = leakDetection ? leakDetector.track(this) : null;
-- this.mode = mode;
-- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth")
: ClientAuth.NONE;
-- this.protocols = protocols;
-- this.enableOcsp = enableOcsp;
--
-- if (mode == SSL.SSL_MODE_SERVER) {
-- rejectRemoteInitiatedRenegotiation =
-- JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION;
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
+- SSLContext.setSessionTicketKeys(context.ctx, tickets);
+- } finally {
+- writerLock.unlock();
- }
-- this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone();
-- final List<String> convertedCiphers;
-- if (ciphers == null) {
-- convertedCiphers = null;
-- } else {
-- convertedCiphers = new ArrayList<String>();
-- for (String c : ciphers) {
-- if (c == null) {
-- break;
-- }
+- }
-
-- String converted = CipherSuiteConverter.toOpenSsl(c);
-- if (converted != null) {
-- c = converted;
-- }
-- convertedCiphers.add(c);
+- /**
+- * Sets the SSL session ticket keys of this context. Depending on the underlying
native library you may omit the
+- * argument or pass an empty array and so let the native library handle the key
generation and rotating for you.
+- * If this is supported by the underlying native library should be checked in this
case. For example
+- * <a
href="https://commondatastorage.googleapis.com/chromium-boringssl-do...
+- * BoringSSL</a> is known to support this.
+- */
+- public void setTicketKeys(OpenSslSessionTicketKey... keys) {
+- ObjectUtil.checkNotNull(keys, "keys");
+- SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length];
+- for (int i = 0; i < ticketKeys.length; i++) {
+- ticketKeys[i] = keys[i].key;
+- }
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
+- if (ticketKeys.length > 0) {
+- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys);
- }
+- } finally {
+- writerLock.unlock();
- }
+- }
-
-- unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter,
"cipherFilter").filterCipherSuites(
-- convertedCiphers, DEFAULT_CIPHERS,
OpenSsl.availableOpenSslCipherSuites()));
+- /**
+- * Enable or disable caching of SSL sessions.
+- */
+- public abstract void setSessionCacheEnabled(boolean enabled);
-
-- this.apn = checkNotNull(apn, "apn");
+- /**
+- * Return {@code true} if caching of SSL sessions is enabled, {@code false}
otherwise.
+- */
+- public abstract boolean isSessionCacheEnabled();
-
-- // Create a new SSL_CTX and configure it.
-- boolean success = false;
-- try {
-- try {
-- ctx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, mode);
-- } catch (Exception e) {
-- throw new SSLException("failed to create an SSL_CTX", e);
-- }
+- /**
+- * Returns the stats of this context.
+- */
+- public OpenSslSessionStats stats() {
+- return stats;
+- }
+-
+- final void destroy() {
+- if (provider != null) {
+- provider.destroy();
+- }
+- }
+-
+- private static final class EmptyEnumeration implements Enumeration<byte[]> {
+- @Override
+- public boolean hasMoreElements() {
+- return false;
+- }
-
-- SSLContext.setOptions(ctx, SSLContext.getOptions(ctx) |
-- SSL.SSL_OP_NO_SSLv2 |
-- SSL.SSL_OP_NO_SSLv3 |
-- SSL.SSL_OP_CIPHER_SERVER_PREFERENCE |
+- @Override
+- public byte[] nextElement() {
+- throw new NoSuchElementException();
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
+deleted file mode 100644
+index f49b95f3ba..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
++++ /dev/null
+@@ -1,253 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
-
-- // We do not support compression at the moment so we should
explicitly disable it.
-- SSL.SSL_OP_NO_COMPRESSION |
+-package io.netty.handler.ssl;
-
-- // Disable ticket support by default to be more inline with
SSLEngineImpl of the JDK.
-- // This also let SSLSession.getId() work the same way for the JDK
implementation and the
-- // OpenSSLEngine. If tickets are supported SSLSession.getId() will
only return an ID on the
-- // server-side if it could make use of tickets.
-- SSL.SSL_OP_NO_TICKET);
+-import io.netty.internal.tcnative.SSLContext;
-
-- // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory
address may change between
-- // calling OpenSSLEngine.wrap(...).
-- // See
https://github.com/netty/netty-tcnative/issues/100
-- SSLContext.setMode(ctx, SSLContext.getMode(ctx) |
SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+-import java.util.concurrent.locks.Lock;
-
-- if (DH_KEY_LENGTH != null) {
-- SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH);
-- }
+-/**
+- * Stats exposed by an OpenSSL session context.
+- *
+- * @see <a
href="https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_numbe...
+- */
+-public final class OpenSslSessionStats {
-
-- /* List the ciphers that are permitted to negotiate. */
-- try {
-- SSLContext.setCipherSuite(ctx,
CipherSuiteConverter.toOpenSsl(unmodifiableCiphers));
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException("failed to set cipher suite: " +
unmodifiableCiphers, e);
-- }
+- private final ReferenceCountedOpenSslContext context;
-
-- List<String> nextProtoList = apn.protocols();
-- /* Set next protocols for next protocol negotiation extension, if
specified */
-- if (!nextProtoList.isEmpty()) {
-- String[] appProtocols = nextProtoList.toArray(new
String[nextProtoList.size()]);
-- int selectorBehavior =
opensslSelectorFailureBehavior(apn.selectorFailureBehavior());
+- // IMPORTANT: We take the OpenSslContext and not just the long (which points the
native instance) to prevent
+- // the GC to collect OpenSslContext as this would also free the pointer
and so could result in a
+- // segfault when the user calls any of the methods here that try to pass
the pointer down to the native
+- // level.
+- OpenSslSessionStats(ReferenceCountedOpenSslContext context) {
+- this.context = context;
+- }
-
-- switch (apn.protocol()) {
-- case NPN:
-- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
-- break;
-- case ALPN:
-- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
-- break;
-- case NPN_AND_ALPN:
-- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
-- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
-- break;
-- default:
-- throw new Error();
-- }
-- }
+- /**
+- * Returns the current number of sessions in the internal session cache.
+- */
+- public long number() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionNumber(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- /* Set session cache size, if specified */
-- if (sessionCacheSize > 0) {
-- this.sessionCacheSize = sessionCacheSize;
-- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
-- } else {
-- // Get the default session cache size using
SSLContext.setSessionCacheSize()
-- this.sessionCacheSize = sessionCacheSize =
SSLContext.setSessionCacheSize(ctx, 20480);
-- // Revert the session cache size to the default value.
-- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
-- }
+- /**
+- * Returns the number of started SSL/TLS handshakes in client mode.
+- */
+- public long connect() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionConnect(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- /* Set session timeout, if specified */
-- if (sessionTimeout > 0) {
-- this.sessionTimeout = sessionTimeout;
-- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
-- } else {
-- // Get the default session timeout using
SSLContext.setSessionCacheTimeout()
-- this.sessionTimeout = sessionTimeout =
SSLContext.setSessionCacheTimeout(ctx, 300);
-- // Revert the session timeout to the default value.
-- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
-- }
+- /**
+- * Returns the number of successfully established SSL/TLS sessions in client mode.
+- */
+- public long connectGood() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionConnectGood(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- if (enableOcsp) {
-- SSLContext.enableOcsp(ctx, isClient());
-- }
-- success = true;
+- /**
+- * Returns the number of start renegotiations in client mode.
+- */
+- public long connectRenegotiate() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionConnectRenegotiate(context.ctx);
- } finally {
-- if (!success) {
-- release();
-- }
+- readerLock.unlock();
- }
- }
-
-- private static int
opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior)
{
-- switch (behavior) {
-- case NO_ADVERTISE:
-- return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE;
-- case CHOOSE_MY_LAST_PROTOCOL:
-- return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL;
-- default:
-- throw new Error();
+- /**
+- * Returns the number of started SSL/TLS handshakes in server mode.
+- */
+- public long accept() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionAccept(context.ctx);
+- } finally {
+- readerLock.unlock();
- }
- }
-
-- @Override
-- public final List<String> cipherSuites() {
-- return unmodifiableCiphers;
+- /**
+- * Returns the number of successfully established SSL/TLS sessions in server mode.
+- */
+- public long acceptGood() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionAcceptGood(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final long sessionCacheSize() {
-- return sessionCacheSize;
+- /**
+- * Returns the number of start renegotiations in server mode.
+- */
+- public long acceptRenegotiate() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionAcceptRenegotiate(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final long sessionTimeout() {
-- return sessionTimeout;
+- /**
+- * Returns the number of successfully reused sessions. In client mode, a session set
with {@code SSL_set_session}
+- * successfully reused is counted as a hit. In server mode, a session successfully
retrieved from internal or
+- * external cache is counted as a hit.
+- */
+- public long hits() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionHits(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public ApplicationProtocolNegotiator applicationProtocolNegotiator() {
-- return apn;
+- /**
+- * Returns the number of successfully retrieved sessions from the external session
cache in server mode.
+- */
+- public long cbHits() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionCbHits(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final boolean isClient() {
-- return mode == SSL.SSL_MODE_CLIENT;
+- /**
+- * Returns the number of sessions proposed by clients that were not found in the
internal session cache
+- * in server mode.
+- */
+- public long misses() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionMisses(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int
peerPort) {
-- return newEngine0(alloc, peerHost, peerPort);
+- /**
+- * Returns the number of sessions proposed by clients and either found in the
internal or external session cache
+- * in server mode, but that were invalid due to timeout. These sessions are not
included in the {@link #hits()}
+- * count.
+- */
+- public long timeouts() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTimeouts(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) {
-- return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort,
true);
+- /**
+- * Returns the number of sessions that were removed because the maximum session
cache size was exceeded.
+- */
+- public long cacheFull() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionCacheFull(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- abstract OpenSslKeyMaterialManager keyMaterialManager();
+- /**
+- * Returns the number of times a client presented a ticket that did not match any
key in the list.
+- */
+- public long ticketKeyFail() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTicketKeyFail(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
- /**
-- * Returns a new server-side {@link SSLEngine} with the current configuration.
+- * Returns the number of times a client did not present a ticket and we issued a new
one
- */
-- @Override
-- public final SSLEngine newEngine(ByteBufAllocator alloc) {
-- return newEngine(alloc, null, -1);
+- public long ticketKeyNew() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTicketKeyNew(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
- /**
-- * Returns the pointer to the {@code SSL_CTX} object for this {@link
ReferenceCountedOpenSslContext}.
-- * Be aware that it is freed as soon as the {@link #finalize()} method is called.
-- * At this point {@code 0} will be returned.
-- *
-- * @deprecated this method is considered unsafe as the returned pointer may be
released later. Dont use it!
+- * Returns the number of times a client presented a ticket derived from an older
key,
+- * and we upgraded to the primary key.
- */
-- @Deprecated
-- public final long context() {
-- Lock readerLock = ctxLock.readLock();
+- public long ticketKeyRenew() {
+- Lock readerLock = context.ctxLock.readLock();
- readerLock.lock();
- try {
-- return ctx;
+- return SSLContext.sessionTicketKeyRenew(context.ctx);
- } finally {
- readerLock.unlock();
- }
- }
-
- /**
-- * Returns the stats of this context.
-- *
-- * @deprecated use {@link #sessionContext#stats()}
+- * Returns the number of times a client presented a ticket derived from the primary
key.
- */
-- @Deprecated
-- public final OpenSslSessionStats stats() {
-- return sessionContext().stats();
+- public long ticketKeyResume() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTicketKeyResume(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+deleted file mode 100644
+index 79f71a65a3..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
++++ /dev/null
+@@ -1,78 +0,0 @@
+-/*
+- * Copyright 2015 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.internal.tcnative.SessionTicketKey;
+-
+-/**
+- * Session Ticket Key
+- */
+-public final class OpenSslSessionTicketKey {
-
- /**
-- * Specify if remote initiated renegotiation is supported or not. If not supported
and the remote side tries
-- * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during
decoding.
+- * Size of session ticket key name
+- */
+- public static final int NAME_SIZE = SessionTicketKey.NAME_SIZE;
+- /**
+- * Size of session ticket key HMAC key
+- */
+- public static final int HMAC_KEY_SIZE = SessionTicketKey.HMAC_KEY_SIZE;
+- /**
+- * Size of session ticket key AES key
- */
-- public void setRejectRemoteInitiatedRenegotiation(boolean
rejectRemoteInitiatedRenegotiation) {
-- this.rejectRemoteInitiatedRenegotiation = rejectRemoteInitiatedRenegotiation;
-- }
--
+- public static final int AES_KEY_SIZE = SessionTicketKey.AES_KEY_SIZE;
- /**
-- * Returns if remote initiated renegotiation is supported or not.
+- * Size of session ticker key
- */
-- public boolean getRejectRemoteInitiatedRenegotiation() {
-- return rejectRemoteInitiatedRenegotiation;
-- }
+- public static final int TICKET_KEY_SIZE = SessionTicketKey.TICKET_KEY_SIZE;
+-
+- final SessionTicketKey key;
-
- /**
-- * Set the size of the buffer used by the BIO for non-application based writes
-- * (e.g. handshake, renegotiation, etc...).
+- * Construct a OpenSslSessionTicketKey.
+- *
+- * @param name the name of the session ticket key
+- * @param hmacKey the HMAC key of the session ticket key
+- * @param aesKey the AES key of the session ticket key
- */
-- public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) {
-- this.bioNonApplicationBufferSize =
-- checkPositiveOrZero(bioNonApplicationBufferSize,
"bioNonApplicationBufferSize");
+- public OpenSslSessionTicketKey(byte[] name, byte[] hmacKey, byte[] aesKey) {
+- key = new SessionTicketKey(name.clone(), hmacKey.clone(), aesKey.clone());
- }
-
- /**
-- * Returns the size of the buffer used by the BIO for non-application based writes
+- * Get name.
+- * @return the name of the session ticket key
- */
-- public int getBioNonApplicationBufferSize() {
-- return bioNonApplicationBufferSize;
+- public byte[] name() {
+- return key.getName().clone();
- }
-
- /**
-- * Sets the SSL session ticket keys of this context.
-- *
-- * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])}
+- * Get HMAC key.
+- * @return the HMAC key of the session ticket key
- */
-- @Deprecated
-- public final void setTicketKeys(byte[] keys) {
-- sessionContext().setTicketKeys(keys);
+- public byte[] hmacKey() {
+- return key.getHmacKey().clone();
- }
-
-- @Override
-- public abstract OpenSslSessionContext sessionContext();
--
- /**
-- * Returns the pointer to the {@code SSL_CTX} object for this {@link
ReferenceCountedOpenSslContext}.
-- * Be aware that it is freed as soon as the {@link #release()} method is called.
-- * At this point {@code 0} will be returned.
-- *
-- * @deprecated this method is considered unsafe as the returned pointer may be
released later. Dont use it!
+- * Get AES Key.
+- * @return the AES key of the session ticket key
- */
-- @Deprecated
-- public final long sslCtxPointer() {
-- Lock readerLock = ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return ctx;
-- } finally {
-- readerLock.unlock();
-- }
+- public byte[] aesKey() {
+- return key.getAesKey().clone();
- }
+-}
+diff --git
a/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java
+deleted file mode 100644
+index a5a84f2793..0000000000
+---
a/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java
++++ /dev/null
+@@ -1,240 +0,0 @@
+-/*
+- * Copyright 2018 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- // IMPORTANT: This method must only be called from either the constructor or the
finalizer as a user MUST never
-- // get access to an OpenSslSessionContext after this method was called to
prevent the user from
-- // producing a segfault.
-- private void destroy() {
-- Lock writerLock = ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- if (ctx != 0) {
-- if (enableOcsp) {
-- SSLContext.disableOcsp(ctx);
-- }
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.SuppressJava6Requirement;
-
-- SSLContext.free(ctx);
-- ctx = 0;
-- }
-- } finally {
-- writerLock.unlock();
-- }
-- }
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLPeerUnverifiedException;
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionContext;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import java.net.Socket;
+-import java.security.Principal;
+-import java.security.cert.Certificate;
+-import java.security.cert.CertificateException;
+-import java.security.cert.X509Certificate;
+-import java.util.List;
-
-- protected static X509Certificate[] certificates(byte[][] chain) {
-- X509Certificate[] peerCerts = new X509Certificate[chain.length];
-- for (int i = 0; i < peerCerts.length; i++) {
-- peerCerts[i] = new OpenSslX509Certificate(chain[i]);
-- }
-- return peerCerts;
-- }
+-/**
+- * Provide a way to use {@code TLSv1.3} with Java versions prior to 11 by adding a
+- * <a
href="http://mail.openjdk.java.net/pipermail/security-dev/2018-Septe...
for the
+- * default {@link X509ExtendedTrustManager} implementations provided by the JDK that can
not handle a protocol version
+- * of {@code TLSv1.3}.
+- */
+-@SuppressJava6Requirement(reason = "Usage guarded by java version check")
+-final class OpenSslTlsv13X509ExtendedTrustManager extends X509ExtendedTrustManager {
-
-- protected static X509TrustManager chooseTrustManager(TrustManager[] managers) {
-- for (TrustManager m : managers) {
-- if (m instanceof X509TrustManager) {
-- return (X509TrustManager) m;
-- }
-- }
-- throw new IllegalStateException("no X509TrustManager found");
-- }
+- private final X509ExtendedTrustManager tm;
-
-- protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) {
-- for (KeyManager km : kms) {
-- if (km instanceof X509KeyManager) {
-- return (X509KeyManager) km;
-- }
-- }
-- throw new IllegalStateException("no X509KeyManager found");
+- private OpenSslTlsv13X509ExtendedTrustManager(X509ExtendedTrustManager tm) {
+- this.tm = tm;
- }
-
-- /**
-- * Translate a {@link ApplicationProtocolConfig} object to a
-- * {@link OpenSslApplicationProtocolNegotiator} object.
-- *
-- * @param config The configuration which defines the translation
-- * @return The results of the translation
-- */
-- static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig
config) {
-- if (config == null) {
-- return NONE_PROTOCOL_NEGOTIATOR;
-- }
--
-- switch (config.protocol()) {
-- case NONE:
-- return NONE_PROTOCOL_NEGOTIATOR;
-- case ALPN:
-- case NPN:
-- case NPN_AND_ALPN:
-- switch (config.selectedListenerFailureBehavior()) {
-- case CHOOSE_MY_LAST_PROTOCOL:
-- case ACCEPT:
-- switch (config.selectorFailureBehavior()) {
-- case CHOOSE_MY_LAST_PROTOCOL:
-- case NO_ADVERTISE:
-- return new OpenSslDefaultApplicationProtocolNegotiator(
-- config);
-- default:
-- throw new UnsupportedOperationException(
-- new StringBuilder("OpenSSL provider does
not support ")
--
.append(config.selectorFailureBehavior())
-- .append("
behavior").toString());
-- }
-- default:
-- throw new UnsupportedOperationException(
-- new StringBuilder("OpenSSL provider does not
support ")
--
.append(config.selectedListenerFailureBehavior())
-- .append(" behavior").toString());
-- }
-- default:
-- throw new Error();
+- static X509ExtendedTrustManager wrap(X509ExtendedTrustManager tm) {
+- if (PlatformDependent.javaVersion() < 11 &&
OpenSsl.isTlsv13Supported()) {
+- return new OpenSslTlsv13X509ExtendedTrustManager(tm);
- }
-- }
--
-- static boolean useExtendedTrustManager(X509TrustManager trustManager) {
-- return PlatformDependent.javaVersion() >= 7 && trustManager
instanceof X509ExtendedTrustManager;
-- }
--
-- static boolean useExtendedKeyManager(X509KeyManager keyManager) {
-- return PlatformDependent.javaVersion() >= 7 && keyManager instanceof
X509ExtendedKeyManager;
-- }
--
-- @Override
-- public final int refCnt() {
-- return refCnt.refCnt();
+- return tm;
- }
-
- @Override
-- public final ReferenceCounted retain() {
-- refCnt.retain();
-- return this;
-- }
--
-- @Override
-- public final ReferenceCounted retain(int increment) {
-- refCnt.retain(increment);
-- return this;
+- public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket
socket)
+- throws CertificateException {
+- tm.checkClientTrusted(x509Certificates, s, socket);
- }
-
- @Override
-- public final ReferenceCounted touch() {
-- refCnt.touch();
-- return this;
+- public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket
socket)
+- throws CertificateException {
+- tm.checkServerTrusted(x509Certificates, s, socket);
- }
-
-- @Override
-- public final ReferenceCounted touch(Object hint) {
-- refCnt.touch(hint);
-- return this;
-- }
+- private static SSLEngine wrapEngine(final SSLEngine engine) {
+- final SSLSession session = engine.getHandshakeSession();
+- if (session != null &&
SslUtils.PROTOCOL_TLS_V1_3.equals(session.getProtocol())) {
+- return new JdkSslEngine(engine) {
+- @Override
+- public String getNegotiatedApplicationProtocol() {
+- if (engine instanceof ApplicationProtocolAccessor) {
+- return ((ApplicationProtocolAccessor)
engine).getNegotiatedApplicationProtocol();
+- }
+- return super.getNegotiatedApplicationProtocol();
+- }
-
-- @Override
-- public final boolean release() {
-- return refCnt.release();
-- }
+- @Override
+- public SSLSession getHandshakeSession() {
+- if (PlatformDependent.javaVersion() >= 7 && session
instanceof ExtendedOpenSslSession) {
+- final ExtendedOpenSslSession extendedOpenSslSession =
(ExtendedOpenSslSession) session;
+- return new ExtendedOpenSslSession(extendedOpenSslSession) {
+- @Override
+- public List getRequestedServerNames() {
+- return
extendedOpenSslSession.getRequestedServerNames();
+- }
-
-- @Override
-- public final boolean release(int decrement) {
-- return refCnt.release(decrement);
-- }
+- @Override
+- public String[] getPeerSupportedSignatureAlgorithms() {
+- return
extendedOpenSslSession.getPeerSupportedSignatureAlgorithms();
+- }
-
-- abstract static class AbstractCertificateVerifier extends CertificateVerifier {
-- private final OpenSslEngineMap engineMap;
+- @Override
+- public String getProtocol() {
+- return SslUtils.PROTOCOL_TLS_V1_2;
+- }
+- };
+- } else {
+- return new SSLSession() {
+- @Override
+- public byte[] getId() {
+- return session.getId();
+- }
-
-- AbstractCertificateVerifier(OpenSslEngineMap engineMap) {
-- this.engineMap = engineMap;
-- }
+- @Override
+- public SSLSessionContext getSessionContext() {
+- return session.getSessionContext();
+- }
-
-- @Override
-- public final int verify(long ssl, byte[][] chain, String auth) {
-- X509Certificate[] peerCerts = certificates(chain);
-- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-- try {
-- verify(engine, peerCerts, auth);
-- return CertificateVerifier.X509_V_OK;
-- } catch (Throwable cause) {
-- logger.debug("verification of certificate failed", cause);
-- SSLHandshakeException e = new SSLHandshakeException("General
OpenSslEngine problem");
-- e.initCause(cause);
-- engine.handshakeException = e;
+- @Override
+- public long getCreationTime() {
+- return session.getCreationTime();
+- }
-
-- // Try to extract the correct error code that should be used.
-- if (cause instanceof OpenSslCertificateException) {
-- // This will never return a negative error code as its validated
when constructing the
-- // OpenSslCertificateException.
-- return ((OpenSslCertificateException) cause).errorCode();
-- }
-- if (cause instanceof CertificateExpiredException) {
-- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
-- }
-- if (cause instanceof CertificateNotYetValidException) {
-- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
-- }
-- if (PlatformDependent.javaVersion() >= 7) {
-- if (cause instanceof CertificateRevokedException) {
-- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
-- }
+- @Override
+- public long getLastAccessedTime() {
+- return session.getLastAccessedTime();
+- }
-
-- // The X509TrustManagerImpl uses a Validator which wraps a
CertPathValidatorException into
-- // an CertificateException. So we need to handle the wrapped
CertPathValidatorException to be
-- // able to send the correct alert.
-- Throwable wrapped = cause.getCause();
-- while (wrapped != null) {
-- if (wrapped instanceof CertPathValidatorException) {
-- CertPathValidatorException ex = (CertPathValidatorException)
wrapped;
-- CertPathValidatorException.Reason reason = ex.getReason();
-- if (reason ==
CertPathValidatorException.BasicReason.EXPIRED) {
-- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
+- @Override
+- public void invalidate() {
+- session.invalidate();
- }
-- if (reason ==
CertPathValidatorException.BasicReason.NOT_YET_VALID) {
-- return
CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
+-
+- @Override
+- public boolean isValid() {
+- return session.isValid();
- }
-- if (reason ==
CertPathValidatorException.BasicReason.REVOKED) {
-- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
+-
+- @Override
+- public void putValue(String s, Object o) {
+- session.putValue(s, o);
- }
-- }
-- wrapped = wrapped.getCause();
-- }
-- }
-
-- // Could not detect a specific error code to use, so fallback to a
default code.
-- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
-- }
-- }
+- @Override
+- public Object getValue(String s) {
+- return session.getValue(s);
+- }
-
-- abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[]
peerCerts,
-- String auth) throws Exception;
-- }
+- @Override
+- public void removeValue(String s) {
+- session.removeValue(s);
+- }
-
-- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
-- private final Map<Long, ReferenceCountedOpenSslEngine> engines =
PlatformDependent.newConcurrentHashMap();
+- @Override
+- public String[] getValueNames() {
+- return session.getValueNames();
+- }
-
-- @Override
-- public ReferenceCountedOpenSslEngine remove(long ssl) {
-- return engines.remove(ssl);
-- }
+- @Override
+- public Certificate[] getPeerCertificates() throws
SSLPeerUnverifiedException {
+- return session.getPeerCertificates();
+- }
-
-- @Override
-- public void add(ReferenceCountedOpenSslEngine engine) {
-- engines.put(engine.sslPointer(), engine);
-- }
+- @Override
+- public Certificate[] getLocalCertificates() {
+- return session.getLocalCertificates();
+- }
-
-- @Override
-- public ReferenceCountedOpenSslEngine get(long ssl) {
-- return engines.get(ssl);
-- }
-- }
+- @Override
+- public javax.security.cert.X509Certificate[]
getPeerCertificateChain()
+- throws SSLPeerUnverifiedException {
+- return session.getPeerCertificateChain();
+- }
-
-- static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key,
String keyPassword)
-- throws SSLException {
-- /* Load the certificate file and private key. */
-- long keyBio = 0;
-- long keyCertChainBio = 0;
-- long keyCertChainBio2 = 0;
-- PemEncoded encoded = null;
-- try {
-- // Only encode one time
-- encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true,
keyCertChain);
-- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
+- @Override
+- public Principal getPeerPrincipal() throws
SSLPeerUnverifiedException {
+- return session.getPeerPrincipal();
+- }
-
-- if (key != null) {
-- keyBio = toBIO(key);
-- }
+- @Override
+- public Principal getLocalPrincipal() {
+- return session.getLocalPrincipal();
+- }
-
-- SSLContext.setCertificateBio(
-- ctx, keyCertChainBio, keyBio,
-- keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword);
-- // We may have more then one cert in the chain so add all of them now.
-- SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true);
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException("failed to set certificate and key", e);
-- } finally {
-- freeBio(keyBio);
-- freeBio(keyCertChainBio);
-- freeBio(keyCertChainBio2);
-- if (encoded != null) {
-- encoded.release();
-- }
-- }
-- }
+- @Override
+- public String getCipherSuite() {
+- return session.getCipherSuite();
+- }
-
-- static void freeBio(long bio) {
-- if (bio != 0) {
-- SSL.freeBIO(bio);
-- }
-- }
+- @Override
+- public String getProtocol() {
+- return SslUtils.PROTOCOL_TLS_V1_2;
+- }
-
-- /**
-- * Return the pointer to a <a
href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html"...
BIO</a>
-- * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of
the {@code key}.
-- */
-- static long toBIO(PrivateKey key) throws Exception {
-- if (key == null) {
-- return 0;
-- }
+- @Override
+- public String getPeerHost() {
+- return session.getPeerHost();
+- }
-
-- ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
-- PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key);
-- try {
-- return toBIO(allocator, pem.retain());
-- } finally {
-- pem.release();
-- }
-- }
+- @Override
+- public int getPeerPort() {
+- return session.getPeerPort();
+- }
-
-- /**
-- * Return the pointer to a <a
href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html"...
BIO</a>
-- * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the
content of the {@code certChain}.
-- */
-- static long toBIO(X509Certificate... certChain) throws Exception {
-- if (certChain == null) {
-- return 0;
-- }
+- @Override
+- public int getPacketBufferSize() {
+- return session.getPacketBufferSize();
+- }
-
-- if (certChain.length == 0) {
-- throw new IllegalArgumentException("certChain can't be
empty");
+- @Override
+- public int getApplicationBufferSize() {
+- return session.getApplicationBufferSize();
+- }
+- };
+- }
+- }
+- };
- }
+- return engine;
+- }
-
-- ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
-- PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain);
-- try {
-- return toBIO(allocator, pem.retain());
-- } finally {
-- pem.release();
-- }
+- @Override
+- public void checkClientTrusted(X509Certificate[] x509Certificates, final String s,
SSLEngine sslEngine)
+- throws CertificateException {
+- tm.checkClientTrusted(x509Certificates, s, wrapEngine(sslEngine));
- }
-
-- static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception {
-- try {
-- // We can turn direct buffers straight into BIOs. No need to
-- // make a yet another copy.
-- ByteBuf content = pem.content();
+- @Override
+- public void checkServerTrusted(X509Certificate[] x509Certificates, String s,
SSLEngine sslEngine)
+- throws CertificateException {
+- tm.checkServerTrusted(x509Certificates, s, wrapEngine(sslEngine));
+- }
-
-- if (content.isDirect()) {
-- return newBIO(content.retainedSlice());
-- }
+- @Override
+- public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws
CertificateException {
+- tm.checkClientTrusted(x509Certificates, s);
+- }
-
-- ByteBuf buffer = allocator.directBuffer(content.readableBytes());
-- try {
-- buffer.writeBytes(content, content.readerIndex(),
content.readableBytes());
-- return newBIO(buffer.retainedSlice());
-- } finally {
-- try {
-- // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey)
we
-- // need to zero out the bytes of the copy before we're releasing
it.
-- if (pem.isSensitive()) {
-- SslUtils.zeroout(buffer);
-- }
-- } finally {
-- buffer.release();
-- }
-- }
-- } finally {
-- pem.release();
-- }
+- @Override
+- public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws
CertificateException {
+- tm.checkServerTrusted(x509Certificates, s);
- }
-
-- private static long newBIO(ByteBuf buffer) throws Exception {
-- try {
-- long bio = SSL.newMemBIO();
-- int readable = buffer.readableBytes();
-- if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(),
readable) != readable) {
-- SSL.freeBIO(bio);
-- throw new IllegalStateException("Could not write data to memory
BIO");
-- }
-- return bio;
-- } finally {
-- buffer.release();
-- }
+- @Override
+- public X509Certificate[] getAcceptedIssuers() {
+- return tm.getAcceptedIssuers();
- }
-}
-diff --git
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
b/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
deleted file mode 100644
-index 27460c7..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
+index 2a86332fe1..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
+++ /dev/null
-@@ -1,2037 +0,0 @@
+@@ -1,413 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in
compliance
@@ -3485,4638 +3793,4204 @@ index 27460c7..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufAllocator;
--import io.netty.internal.tcnative.Buffer;
+-import io.netty.buffer.UnpooledByteBufAllocator;
-import io.netty.internal.tcnative.SSL;
--import io.netty.util.AbstractReferenceCounted;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.ResourceLeakDetector;
--import io.netty.util.ResourceLeakDetectorFactory;
--import io.netty.util.ResourceLeakTracker;
--import io.netty.util.internal.EmptyArrays;
--import io.netty.util.internal.PlatformDependent;
--import io.netty.util.internal.StringUtil;
--import io.netty.util.internal.ThrowableUtil;
--import io.netty.util.internal.UnstableApi;
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
+-import io.netty.util.ReferenceCountUtil;
+-import io.netty.util.internal.ObjectUtil;
-
--import java.nio.ByteBuffer;
--import java.nio.ReadOnlyBufferException;
--import java.security.Principal;
+-import javax.net.ssl.KeyManager;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.KeyManagerFactorySpi;
+-import javax.net.ssl.ManagerFactoryParameters;
+-import javax.net.ssl.X509KeyManager;
+-import java.io.File;
+-import java.io.IOException;
+-import java.io.InputStream;
+-import java.io.OutputStream;
+-import java.security.InvalidAlgorithmParameterException;
+-import java.security.Key;
+-import java.security.KeyStore;
+-import java.security.KeyStoreException;
+-import java.security.KeyStoreSpi;
+-import java.security.NoSuchAlgorithmException;
+-import java.security.PrivateKey;
+-import java.security.Provider;
+-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
--import java.util.ArrayList;
--import java.util.Arrays;
--import java.util.Collection;
+-import java.security.cert.CertificateException;
+-import java.security.cert.X509Certificate;
+-import java.util.Collections;
+-import java.util.Date;
+-import java.util.Enumeration;
-import java.util.HashMap;
--import java.util.List;
-import java.util.Map;
--import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
--
--import java.util.concurrent.locks.Lock;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLEngineResult;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
--import javax.net.ssl.SSLParameters;
--import javax.net.ssl.SSLPeerUnverifiedException;
--import javax.net.ssl.SSLSession;
--import javax.net.ssl.SSLSessionBindingEvent;
--import javax.net.ssl.SSLSessionBindingListener;
--import javax.net.ssl.SSLSessionContext;
--import javax.security.cert.X509Certificate;
--
--import static io.netty.handler.ssl.OpenSsl.memoryAddress;
--import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH;
--import static io.netty.util.internal.EmptyArrays.EMPTY_CERTIFICATES;
--import static io.netty.util.internal.EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import static java.lang.Math.min;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
--import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
--import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
--import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
--import static javax.net.ssl.SSLEngineResult.Status.OK;
-
-/**
-- * Implements a {@link SSLEngine} using
-- * <a
href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE&quo... BIO
abstractions</a>.
-- * <p>Instances of this class must be {@link #release() released} or else native
memory will leak!
+- * Special {@link KeyManagerFactory} that pre-compute the keymaterial used when {@link
SslProvider#OPENSSL} or
+- * {@link SslProvider#OPENSSL_REFCNT} is used and so will improve handshake times and
its performance.
- *
-- * <p>Instances of this class <strong>must</strong> be released before
the {@link ReferenceCountedOpenSslContext}
-- * the instance depends upon are released. Otherwise if any method of this class is
called which uses the
-- * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash.
-- */
--public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted
{
--
-- private static final InternalLogger logger =
InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class);
--
-- private static final SSLException BEGIN_HANDSHAKE_ENGINE_CLOSED =
ThrowableUtil.unknownStackTrace(
-- new SSLException("engine closed"),
ReferenceCountedOpenSslEngine.class, "beginHandshake()");
-- private static final SSLException HANDSHAKE_ENGINE_CLOSED =
ThrowableUtil.unknownStackTrace(
-- new SSLException("engine closed"),
ReferenceCountedOpenSslEngine.class, "handshake()");
-- private static final SSLException RENEGOTIATION_UNSUPPORTED =
ThrowableUtil.unknownStackTrace(
-- new SSLException("renegotiation unsupported"),
ReferenceCountedOpenSslEngine.class, "beginHandshake()");
-- private static final ResourceLeakDetector<ReferenceCountedOpenSslEngine>
leakDetector =
--
ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class);
-- /**
-- * <a
href="https://www.openssl.org/docs/man1.0.2/crypto/X509_check_host.h...
flags argument is usually 0</a>.
-- */
-- private static final int DEFAULT_HOSTNAME_VALIDATION_FLAGS = 0;
+- *
+- *
+- * Because the keymaterial is pre-computed any modification to the {@link KeyStore} is
ignored after
+- * {@link #init(KeyStore, char[])} is called.
+- *
+- * {@link #init(ManagerFactoryParameters)} is not supported by this implementation and
so a call to it will always
+- * result in an {@link InvalidAlgorithmParameterException}.
+- */
+-public final class OpenSslX509KeyManagerFactory extends KeyManagerFactory {
-
-- static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
+- private final OpenSslKeyManagerFactorySpi spi;
-
-- /**
-- * This is the maximum overhead when encrypting plaintext as defined by
-- * <a
href="https://www.ietf.org/rfc/rfc5246.txt">rfc5264</a>,
-- * <a
href="https://www.ietf.org/rfc/rfc5289.txt">rfc5289</a>
and openssl implementation itself.
-- *
-- * Please note that we use a padding of 16 here as openssl uses PKC#5 which uses 16
bytes while the spec itself
-- * allow up to 255 bytes. 16 bytes is the max for PKC#5 (which handles it the same
way as PKC#7) as we use a block
-- * size of 16. See <a
href="https://tools.ietf.org/html/rfc5652#section-6.3">rfc56...;.
-- *
-- * TLS Header (5) + 16 (IV) + 48 (MAC) + 1 (Padding_length field) + 15 (Padding) + 1
(ContentType) +
-- * 2 (ProtocolVersion) + 2 (Length)
-- *
-- * TODO: We may need to review this calculation once TLS 1.3 becomes available.
-- */
-- static final int MAX_TLS_RECORD_OVERHEAD_LENGTH = SSL_RECORD_HEADER_LENGTH + 16 + 48
+ 1 + 15 + 1 + 2 + 2;
+- public OpenSslX509KeyManagerFactory() {
+- this(newOpenSslKeyManagerFactorySpi(null));
+- }
-
-- static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_PLAINTEXT_LENGTH +
MAX_TLS_RECORD_OVERHEAD_LENGTH;
+- public OpenSslX509KeyManagerFactory(Provider provider) {
+- this(newOpenSslKeyManagerFactorySpi(provider));
+- }
-
-- private static final AtomicIntegerFieldUpdater<ReferenceCountedOpenSslEngine>
DESTROYED_UPDATER =
-- AtomicIntegerFieldUpdater.newUpdater(ReferenceCountedOpenSslEngine.class,
"destroyed");
+- public OpenSslX509KeyManagerFactory(String algorithm, Provider provider) throws
NoSuchAlgorithmException {
+- this(newOpenSslKeyManagerFactorySpi(algorithm, provider));
+- }
-
-- private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
-- private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK,
NEED_UNWRAP, 0, 0);
-- private static final SSLEngineResult NEED_UNWRAP_CLOSED = new
SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
-- private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK,
NEED_WRAP, 0, 0);
-- private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED,
NEED_WRAP, 0, 0);
-- private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new
SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
+- private OpenSslX509KeyManagerFactory(OpenSslKeyManagerFactorySpi spi) {
+- super(spi, spi.kmf.getProvider(), spi.kmf.getAlgorithm());
+- this.spi = spi;
+- }
-
-- // OpenSSL state
-- private long ssl;
-- private long networkBIO;
-- private boolean certificateSet;
+- private static OpenSslKeyManagerFactorySpi newOpenSslKeyManagerFactorySpi(Provider
provider) {
+- try {
+- return newOpenSslKeyManagerFactorySpi(null, provider);
+- } catch (NoSuchAlgorithmException e) {
+- // This should never happen as we use the default algorithm.
+- throw new IllegalStateException(e);
+- }
+- }
-
-- private enum HandshakeState {
-- /**
-- * Not started yet.
-- */
-- NOT_STARTED,
-- /**
-- * Started via unwrap/wrap.
-- */
-- STARTED_IMPLICITLY,
-- /**
-- * Started via {@link #beginHandshake()}.
-- */
-- STARTED_EXPLICITLY,
+- private static OpenSslKeyManagerFactorySpi newOpenSslKeyManagerFactorySpi(String
algorithm, Provider provider)
+- throws NoSuchAlgorithmException {
+- if (algorithm == null) {
+- algorithm = KeyManagerFactory.getDefaultAlgorithm();
+- }
+- return new OpenSslKeyManagerFactorySpi(
+- provider == null ? KeyManagerFactory.getInstance(algorithm) :
+- KeyManagerFactory.getInstance(algorithm, provider));
+- }
-
-- /**
-- * Handshake is finished.
-- */
-- FINISHED
+- OpenSslKeyMaterialProvider newProvider() {
+- return spi.newProvider();
- }
-
-- private HandshakeState handshakeState = HandshakeState.NOT_STARTED;
-- private boolean renegotiationPending;
-- private boolean receivedShutdown;
-- private volatile int destroyed;
+- private static final class OpenSslKeyManagerFactorySpi extends KeyManagerFactorySpi
{
+- final KeyManagerFactory kmf;
+- private volatile ProviderFactory providerFactory;
+-
+- OpenSslKeyManagerFactorySpi(KeyManagerFactory kmf) {
+- this.kmf = ObjectUtil.checkNotNull(kmf, "kmf");
+- }
-
-- // Reference Counting
-- private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak;
-- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
- @Override
-- public ReferenceCounted touch(Object hint) {
-- if (leak != null) {
-- leak.record(hint);
+- protected synchronized void engineInit(KeyStore keyStore, char[] chars)
+- throws KeyStoreException, NoSuchAlgorithmException,
UnrecoverableKeyException {
+- if (providerFactory != null) {
+- throw new KeyStoreException("Already initialized");
+- }
+- if (!keyStore.aliases().hasMoreElements()) {
+- throw new KeyStoreException("No aliases found");
- }
-
-- return ReferenceCountedOpenSslEngine.this;
+- kmf.init(keyStore, chars);
+- providerFactory = new
ProviderFactory(ReferenceCountedOpenSslContext.chooseX509KeyManager(
+- kmf.getKeyManagers()), password(chars),
Collections.list(keyStore.aliases()));
- }
-
-- @Override
-- protected void deallocate() {
-- shutdown();
-- if (leak != null) {
-- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this);
-- assert closed;
+- private static String password(char[] password) {
+- if (password == null || password.length == 0) {
+- return null;
- }
+- return new String(password);
- }
-- };
-
-- private volatile ClientAuth clientAuth = ClientAuth.NONE;
+- @Override
+- protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
+- throws InvalidAlgorithmParameterException {
+- throw new InvalidAlgorithmParameterException("Not supported");
+- }
-
-- // Updated once a new handshake is started and so the SSLSession reused.
-- private volatile long lastAccessed = -1;
+- @Override
+- protected KeyManager[] engineGetKeyManagers() {
+- ProviderFactory providerFactory = this.providerFactory;
+- if (providerFactory == null) {
+- throw new IllegalStateException("engineInit(...) not called
yet");
+- }
+- return new KeyManager[] { providerFactory.keyManager };
+- }
-
-- private String endPointIdentificationAlgorithm;
-- // Store as object as AlgorithmConstraints only exists since java 7.
-- private Object algorithmConstraints;
-- private List<String> sniHostNames;
+- OpenSslKeyMaterialProvider newProvider() {
+- ProviderFactory providerFactory = this.providerFactory;
+- if (providerFactory == null) {
+- throw new IllegalStateException("engineInit(...) not called
yet");
+- }
+- return providerFactory.newProvider();
+- }
-
-- // Mark as volatile as accessed by checkSniHostnameMatch(...) and also not specify
the SNIMatcher type to allow us
-- // using it with java7.
-- private volatile Collection<?> matchers;
+- private static final class ProviderFactory {
+- private final X509KeyManager keyManager;
+- private final String password;
+- private final Iterable<String> aliases;
-
-- // SSL Engine status variables
-- private boolean isInboundDone;
-- private boolean outboundClosed;
+- ProviderFactory(X509KeyManager keyManager, String password,
Iterable<String> aliases) {
+- this.keyManager = keyManager;
+- this.password = password;
+- this.aliases = aliases;
+- }
-
-- private final boolean clientMode;
-- private final ByteBufAllocator alloc;
-- private final OpenSslEngineMap engineMap;
-- private final OpenSslApplicationProtocolNegotiator apn;
-- private final boolean rejectRemoteInitiatedRenegotiation;
-- private final OpenSslSession session;
-- private final Certificate[] localCerts;
-- private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1];
-- private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1];
-- private final OpenSslKeyMaterialManager keyMaterialManager;
-- private final boolean enableOcsp;
+- OpenSslKeyMaterialProvider newProvider() {
+- return new OpenSslPopulatedKeyMaterialProvider(keyManager,
+- password, aliases);
+- }
-
-- // This is package-private as we set it from OpenSslContext if an exception is
thrown during
-- // the verification step.
-- SSLHandshakeException handshakeException;
+- /**
+- * {@link OpenSslKeyMaterialProvider} implementation that pre-compute the
{@link OpenSslKeyMaterial} for
+- * all aliases.
+- */
+- private static final class OpenSslPopulatedKeyMaterialProvider extends
OpenSslKeyMaterialProvider {
+- private final Map<String, Object> materialMap;
-
-- /**
-- * Create a new instance.
-- * @param context Reference count release responsibility is not transferred! The
callee still owns this object.
-- * @param alloc The allocator to use.
-- * @param peerHost The peer host name.
-- * @param peerPort The peer port.
-- * @param leakDetection {@code true} to enable leak detection of this object.
-- */
-- ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context,
ByteBufAllocator alloc, String peerHost,
-- int peerPort, boolean leakDetection) {
-- super(peerHost, peerPort);
-- OpenSsl.ensureAvailability();
-- leak = leakDetection ? leakDetector.track(this) : null;
-- this.alloc = checkNotNull(alloc, "alloc");
-- apn = (OpenSslApplicationProtocolNegotiator)
context.applicationProtocolNegotiator();
-- session = new OpenSslSession(context.sessionContext());
-- clientMode = context.isClient();
-- engineMap = context.engineMap;
-- rejectRemoteInitiatedRenegotiation =
context.getRejectRemoteInitiatedRenegotiation();
-- localCerts = context.keyCertChain;
-- keyMaterialManager = context.keyMaterialManager();
-- enableOcsp = context.enableOcsp;
+- OpenSslPopulatedKeyMaterialProvider(
+- X509KeyManager keyManager, String password,
Iterable<String> aliases) {
+- super(keyManager, password);
+- materialMap = new HashMap<String, Object>();
+- boolean initComplete = false;
+- try {
+- for (String alias: aliases) {
+- if (alias != null &&
!materialMap.containsKey(alias)) {
+- try {
+- materialMap.put(alias, super.chooseKeyMaterial(
+- UnpooledByteBufAllocator.DEFAULT, alias));
+- } catch (Exception e) {
+- // Just store the exception and rethrow it when we
try to choose the keymaterial
+- // for this alias later on.
+- materialMap.put(alias, e);
+- }
+- }
+- }
+- initComplete = true;
+- } finally {
+- if (!initComplete) {
+- destroy();
+- }
+- }
+- if (materialMap.isEmpty()) {
+- throw new IllegalArgumentException("aliases must be
non-empty");
+- }
+- }
-
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- ssl = SSL.newSSL(context.ctx, !context.isClient());
-- } finally {
-- readerLock.unlock();
+- @Override
+- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String
alias) throws Exception {
+- Object value = materialMap.get(alias);
+- if (value == null) {
+- // There is no keymaterial for the requested alias, return null
+- return null;
+- }
+- if (value instanceof OpenSslKeyMaterial) {
+- return ((OpenSslKeyMaterial) value).retain();
+- }
+- throw (Exception) value;
+- }
+-
+- @Override
+- void destroy() {
+- for (Object material: materialMap.values()) {
+- ReferenceCountUtil.release(material);
+- }
+- materialMap.clear();
+- }
+- }
- }
-- try {
-- networkBIO = SSL.bioNewByteBuffer(ssl,
context.getBioNonApplicationBufferSize());
+- }
-
-- // Set the client auth mode, this needs to be done via setClientAuth(...)
method so we actually call the
-- // needed JNI methods.
-- setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth);
+- /**
+- * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its
{@link PrivateKey} directly from
+- * an {@code OpenSSL engine} via the
+- * <a
href="https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_load_priva...
+- * function.
+- */
+- public static OpenSslX509KeyManagerFactory newEngineBased(File certificateChain,
String password)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException,
UnrecoverableKeyException {
+- return newEngineBased(SslContext.toX509Certificates(certificateChain),
password);
+- }
-
-- if (context.protocols != null) {
-- setEnabledProtocols(context.protocols);
-- }
+- /**
+- * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its
{@link PrivateKey} directly from
+- * an {@code OpenSSL engine} via the
+- * <a
href="https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_load_priva...
+- * function.
+- */
+- public static OpenSslX509KeyManagerFactory newEngineBased(X509Certificate[]
certificateChain, String password)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException,
UnrecoverableKeyException {
+- KeyStore store = new OpenSslKeyStore(certificateChain.clone(), false);
+- store.load(null, null);
+- OpenSslX509KeyManagerFactory factory = new OpenSslX509KeyManagerFactory();
+- factory.init(store, password == null ? null : password.toCharArray());
+- return factory;
+- }
-
-- // Use SNI if peerHost was specified
-- // See
https://github.com/netty/netty/issues/4746
-- if (clientMode && peerHost != null) {
-- SSL.setTlsExtHostName(ssl, peerHost);
-- }
+- /**
+- * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[],
String)}.
+- */
+- public static OpenSslX509KeyManagerFactory newKeyless(File chain)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- return newKeyless(SslContext.toX509Certificates(chain));
+- }
-
-- if (enableOcsp) {
-- SSL.enableOcsp(ssl);
-- }
-- } catch (Throwable cause) {
-- SSL.freeSSL(ssl);
-- PlatformDependent.throwException(cause);
-- }
+- /**
+- * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[],
String)}.
+- */
+- public static OpenSslX509KeyManagerFactory newKeyless(InputStream chain)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- return newKeyless(SslContext.toX509Certificates(chain));
- }
-
- /**
-- * Sets the OCSP response.
+- * Returns a new initialized {@link OpenSslX509KeyManagerFactory} which will provide
its private key by using the
+- * {@link OpenSslPrivateKeyMethod}.
- */
-- @UnstableApi
-- public void setOcspResponse(byte[] response) {
-- if (!enableOcsp) {
-- throw new IllegalStateException("OCSP stapling is not enabled");
-- }
+- public static OpenSslX509KeyManagerFactory newKeyless(X509Certificate...
certificateChain)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- KeyStore store = new OpenSslKeyStore(certificateChain.clone(), true);
+- store.load(null, null);
+- OpenSslX509KeyManagerFactory factory = new OpenSslX509KeyManagerFactory();
+- factory.init(store, null);
+- return factory;
+- }
-
-- if (clientMode) {
-- throw new IllegalStateException("Not a server SSLEngine");
-- }
+- private static final class OpenSslKeyStore extends KeyStore {
+- private OpenSslKeyStore(final X509Certificate[] certificateChain, final boolean
keyless) {
+- super(new KeyStoreSpi() {
-
-- synchronized (this) {
-- SSL.setOcspResponse(ssl, response);
+- private final Date creationDate = new Date();
+-
+- @Override
+- public Key engineGetKey(String alias, char[] password) throws
UnrecoverableKeyException {
+- if (engineContainsAlias(alias)) {
+- final long privateKeyAddress;
+- if (keyless) {
+- privateKeyAddress = 0;
+- } else {
+- try {
+- privateKeyAddress = SSL.loadPrivateKeyFromEngine(
+- alias, password == null ? null : new
String(password));
+- } catch (Exception e) {
+- UnrecoverableKeyException keyException =
+- new UnrecoverableKeyException("Unable to
load key from engine");
+- keyException.initCause(e);
+- throw keyException;
+- }
+- }
+- return new OpenSslPrivateKey(privateKeyAddress);
+- }
+- return null;
+- }
+-
+- @Override
+- public Certificate[] engineGetCertificateChain(String alias) {
+- return engineContainsAlias(alias)? certificateChain.clone() : null;
+- }
+-
+- @Override
+- public Certificate engineGetCertificate(String alias) {
+- return engineContainsAlias(alias)? certificateChain[0] : null;
+- }
+-
+- @Override
+- public Date engineGetCreationDate(String alias) {
+- return engineContainsAlias(alias)? creationDate : null;
+- }
+-
+- @Override
+- public void engineSetKeyEntry(String alias, Key key, char[] password,
Certificate[] chain)
+- throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public void engineSetKeyEntry(String alias, byte[] key, Certificate[]
chain) throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public void engineSetCertificateEntry(String alias, Certificate cert)
throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public void engineDeleteEntry(String alias) throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public Enumeration<String> engineAliases() {
+- return
Collections.enumeration(Collections.singleton(SslContext.ALIAS));
+- }
+-
+- @Override
+- public boolean engineContainsAlias(String alias) {
+- return SslContext.ALIAS.equals(alias);
+- }
+-
+- @Override
+- public int engineSize() {
+- return 1;
+- }
+-
+- @Override
+- public boolean engineIsKeyEntry(String alias) {
+- return engineContainsAlias(alias);
+- }
+-
+- @Override
+- public boolean engineIsCertificateEntry(String alias) {
+- return engineContainsAlias(alias);
+- }
+-
+- @Override
+- public String engineGetCertificateAlias(Certificate cert) {
+- if (cert instanceof X509Certificate) {
+- for (X509Certificate x509Certificate : certificateChain) {
+- if (x509Certificate.equals(cert)) {
+- return SslContext.ALIAS;
+- }
+- }
+- }
+- return null;
+- }
+-
+- @Override
+- public void engineStore(OutputStream stream, char[] password) {
+- throw new UnsupportedOperationException();
+- }
+-
+- @Override
+- public void engineLoad(InputStream stream, char[] password) {
+- if (stream != null && password != null) {
+- throw new UnsupportedOperationException();
+- }
+- }
+- }, null, "native");
+-
+- OpenSsl.ensureAvailability();
- }
- }
+-}
+diff --git
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
+deleted file mode 100644
+index 6b945506b9..0000000000
+---
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
++++ /dev/null
+@@ -1,343 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.internal.tcnative.CertificateCallback;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-
+-import java.security.KeyStore;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-
+-import java.util.Arrays;
+-import java.util.Collections;
+-import java.util.HashSet;
+-import java.util.LinkedHashSet;
+-import java.util.Set;
-
-- /**
-- * Returns the OCSP response or {@code null} if the server didn't provide a
stapled OCSP response.
-- */
-- @UnstableApi
-- public byte[] getOcspResponse() {
-- if (!enableOcsp) {
-- throw new IllegalStateException("OCSP stapling is not enabled");
-- }
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.TrustManagerFactory;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509TrustManager;
+-import javax.security.auth.x500.X500Principal;
-
-- if (!clientMode) {
-- throw new IllegalStateException("Not a client SSLEngine");
-- }
+-/**
+- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * <p>Instances of this class must be {@link #release() released} or else native
memory will leak!
+- *
+- * <p>Instances of this class <strong>must not</strong> be released
before any {@link ReferenceCountedOpenSslEngine}
+- * which depends upon the instance of this class is released. Otherwise if any method
of
+- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI
resources the JVM may crash.
+- */
+-public final class ReferenceCountedOpenSslClientContext extends
ReferenceCountedOpenSslContext {
+- private static final InternalLogger logger =
+-
InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class);
+- private static final Set<String> SUPPORTED_KEY_TYPES =
Collections.unmodifiableSet(new LinkedHashSet<String>(
+- Arrays.asList(OpenSslKeyMaterialManager.KEY_TYPE_RSA,
+- OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA,
+- OpenSslKeyMaterialManager.KEY_TYPE_EC,
+- OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA,
+- OpenSslKeyMaterialManager.KEY_TYPE_EC_EC)));
+- private static final boolean ENABLE_SESSION_TICKET =
+-
SystemPropertyUtil.getBoolean("jdk.tls.client.enableSessionTicketExtension",
false);
+- private final OpenSslSessionContext sessionContext;
-
-- synchronized (this) {
-- return SSL.getOcspResponse(ssl);
+- ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection,
TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key,
String keyPassword,
+- KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
+- String[] protocols, long sessionCacheSize, long
sessionTimeout,
+- boolean enableOcsp, String keyStore) throws
SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
SSL.SSL_MODE_CLIENT, keyCertChain,
+- ClientAuth.NONE, protocols, false, enableOcsp, true);
+- boolean success = false;
+- try {
+- sessionContext = newSessionContext(this, ctx, engineMap,
trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword,
keyManagerFactory, keyStore);
+- if (ENABLE_SESSION_TICKET) {
+- sessionContext.setTicketKeys();
+- }
+- success = true;
+- } finally {
+- if (!success) {
+- release();
+- }
- }
- }
-
- @Override
-- public final int refCnt() {
-- return refCnt.refCnt();
-- }
--
-- @Override
-- public final ReferenceCounted retain() {
-- refCnt.retain();
-- return this;
+- public OpenSslSessionContext sessionContext() {
+- return sessionContext;
- }
-
-- @Override
-- public final ReferenceCounted retain(int increment) {
-- refCnt.retain(increment);
-- return this;
-- }
+- static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz,
long ctx,
+- OpenSslEngineMap engineMap,
+- X509Certificate[]
trustCertCollection,
+- TrustManagerFactory
trustManagerFactory,
+- X509Certificate[] keyCertChain,
PrivateKey key,
+- String keyPassword, KeyManagerFactory
keyManagerFactory,
+- String keyStore) throws SSLException
{
+- if (key == null && keyCertChain != null || key != null &&
keyCertChain == null) {
+- throw new IllegalArgumentException(
+- "Either both keyCertChain and key needs to be null or none of
them");
+- }
+- OpenSslKeyMaterialProvider keyMaterialProvider = null;
+- try {
+- try {
+- if (!OpenSsl.useKeyManagerFactory()) {
+- if (keyManagerFactory != null) {
+- throw new IllegalArgumentException(
+- "KeyManagerFactory not supported");
+- }
+- if (keyCertChain != null/* && key != null*/) {
+- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
+- }
+- } else {
+- // javadocs state that keyManagerFactory has precedent over
keyCertChain
+- if (keyManagerFactory == null && keyCertChain != null) {
+- char[] keyPasswordChars = keyStorePassword(keyPassword);
+- KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars,
keyStore);
+- if (ks.aliases().hasMoreElements()) {
+- keyManagerFactory = new OpenSslX509KeyManagerFactory();
+- } else {
+- keyManagerFactory = new
OpenSslCachingX509KeyManagerFactory(
+-
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
+- }
+- keyManagerFactory.init(ks, keyPasswordChars);
+- keyMaterialProvider = providerFor(keyManagerFactory,
keyPassword);
+- } else if (keyManagerFactory != null) {
+- keyMaterialProvider = providerFor(keyManagerFactory,
keyPassword);
+- }
-
-- @Override
-- public final ReferenceCounted touch() {
-- refCnt.touch();
-- return this;
-- }
+- if (keyMaterialProvider != null) {
+- OpenSslKeyMaterialManager materialManager = new
OpenSslKeyMaterialManager(keyMaterialProvider);
+- SSLContext.setCertificateCallback(ctx, new
OpenSslClientCertificateCallback(
+- engineMap, materialManager));
+- }
+- }
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate and key",
e);
+- }
-
-- @Override
-- public final ReferenceCounted touch(Object hint) {
-- refCnt.touch(hint);
-- return this;
-- }
+- // On the client side we always need to use SSL_CVERIFY_OPTIONAL (which will
translate to SSL_VERIFY_PEER)
+- // to ensure that when the TrustManager throws we will produce the correct
alert back to the server.
+- //
+- // See:
+- // -
https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
+- // -
https://github.com/netty/netty/issues/8942
+- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_OPTIONAL, VERIFY_DEPTH);
-
-- @Override
-- public final boolean release() {
-- return refCnt.release();
-- }
+- try {
+- if (trustCertCollection != null) {
+- trustManagerFactory = buildTrustManagerFactory(trustCertCollection,
trustManagerFactory, keyStore);
+- } else if (trustManagerFactory == null) {
+- trustManagerFactory = TrustManagerFactory.getInstance(
+- TrustManagerFactory.getDefaultAlgorithm());
+- trustManagerFactory.init((KeyStore) null);
+- }
+- final X509TrustManager manager =
chooseTrustManager(trustManagerFactory.getTrustManagers());
-
-- @Override
-- public final boolean release(int decrement) {
-- return refCnt.release(decrement);
-- }
+- // IMPORTANT: The callbacks set for verification must be static to
prevent memory leak as
+- // otherwise the context can never be collected. This is
because the JNI code holds
+- // a global reference to the callbacks.
+- //
+- // See
https://github.com/netty/netty/issues/5372
-
-- @Override
-- public final synchronized SSLSession getHandshakeSession() {
-- // Javadocs state return value should be:
-- // null if this instance is not currently handshaking, or if the current
handshake has not
-- // progressed far enough to create a basic SSLSession. Otherwise, this method
returns the
-- // SSLSession currently being negotiated.
-- switch(handshakeState) {
-- case NOT_STARTED:
-- case FINISHED:
-- return null;
-- default:
-- return session;
+- setVerifyCallback(ctx, engineMap, manager);
+- } catch (Exception e) {
+- if (keyMaterialProvider != null) {
+- keyMaterialProvider.destroy();
+- }
+- throw new SSLException("unable to setup trustmanager", e);
+- }
+- OpenSslClientSessionContext context = new OpenSslClientSessionContext(thiz,
keyMaterialProvider);
+- keyMaterialProvider = null;
+- return context;
+- } finally {
+- if (keyMaterialProvider != null) {
+- keyMaterialProvider.destroy();
+- }
- }
- }
-
-- /**
-- * Returns the pointer to the {@code SSL} object for this {@link
ReferenceCountedOpenSslEngine}.
-- * Be aware that it is freed as soon as the {@link #release()} or {@link
#shutdown()} methods are called.
-- * At this point {@code 0} will be returned.
-- */
-- public final synchronized long sslPointer() {
-- return ssl;
+- @SuppressJava6Requirement(reason = "Guarded by java version check")
+- private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap,
X509TrustManager manager) {
+- // Use this to prevent an error when running on java < 7
+- if (useExtendedTrustManager(manager)) {
+- SSLContext.setCertVerifyCallback(ctx,
+- new ExtendedTrustManagerVerifyCallback(engineMap,
(X509ExtendedTrustManager) manager));
+- } else {
+- SSLContext.setCertVerifyCallback(ctx, new
TrustManagerVerifyCallback(engineMap, manager));
+- }
- }
-
-- /**
-- * Destroys this engine.
-- */
-- public final synchronized void shutdown() {
-- if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) {
-- engineMap.remove(ssl);
-- SSL.freeSSL(ssl);
-- ssl = networkBIO = 0;
--
-- isInboundDone = outboundClosed = true;
+- // No cache is currently supported for client side mode.
+- static final class OpenSslClientSessionContext extends OpenSslSessionContext {
+- OpenSslClientSessionContext(ReferenceCountedOpenSslContext context,
OpenSslKeyMaterialProvider provider) {
+- super(context, provider);
- }
-
-- // On shutdown clear all errors
-- SSL.clearError();
-- }
+- @Override
+- public void setSessionTimeout(int seconds) {
+- if (seconds < 0) {
+- throw new IllegalArgumentException();
+- }
+- }
-
-- /**
-- * Write plaintext data to the OpenSSL internal BIO
-- *
-- * Calling this function with src.remaining == 0 is undefined.
-- */
-- private int writePlaintextData(final ByteBuffer src, int len) {
-- final int pos = src.position();
-- final int limit = src.limit();
-- final int sslWrote;
+- @Override
+- public int getSessionTimeout() {
+- return 0;
+- }
-
-- if (src.isDirect()) {
-- sslWrote = SSL.writeToSSL(ssl, Buffer.address(src) + pos, len);
-- if (sslWrote > 0) {
-- src.position(pos + sslWrote);
+- @Override
+- public void setSessionCacheSize(int size) {
+- if (size < 0) {
+- throw new IllegalArgumentException();
- }
-- } else {
-- ByteBuf buf = alloc.directBuffer(len);
-- try {
-- src.limit(pos + len);
+- }
-
-- buf.setBytes(0, src);
-- src.limit(limit);
+- @Override
+- public int getSessionCacheSize() {
+- return 0;
+- }
-
-- sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len);
-- if (sslWrote > 0) {
-- src.position(pos + sslWrote);
-- } else {
-- src.position(pos);
-- }
-- } finally {
-- buf.release();
-- }
+- @Override
+- public void setSessionCacheEnabled(boolean enabled) {
+- // ignored
+- }
+-
+- @Override
+- public boolean isSessionCacheEnabled() {
+- return false;
- }
-- return sslWrote;
- }
-
-- /**
-- * Write encrypted data to the OpenSSL network BIO.
-- */
-- private ByteBuf writeEncryptedData(final ByteBuffer src, int len) {
-- final int pos = src.position();
-- if (src.isDirect()) {
-- SSL.bioSetByteBuffer(networkBIO, Buffer.address(src) + pos, len, false);
-- } else {
-- final ByteBuf buf = alloc.directBuffer(len);
-- try {
-- final int limit = src.limit();
-- src.limit(pos + len);
-- buf.writeBytes(src);
-- // Restore the original position and limit because we don't want to
consume from `src`.
-- src.position(pos);
-- src.limit(limit);
+- private static final class TrustManagerVerifyCallback extends
AbstractCertificateVerifier {
+- private final X509TrustManager manager;
-
-- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false);
-- return buf;
-- } catch (Throwable cause) {
-- buf.release();
-- PlatformDependent.throwException(cause);
-- }
+- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager)
{
+- super(engineMap);
+- this.manager = manager;
- }
-- return null;
-- }
-
-- /**
-- * Read plaintext data from the OpenSSL internal BIO
-- */
-- private int readPlaintextData(final ByteBuffer dst) {
-- final int sslRead;
-- final int pos = dst.position();
-- if (dst.isDirect()) {
-- sslRead = SSL.readFromSSL(ssl, Buffer.address(dst) + pos, dst.limit() -
pos);
-- if (sslRead > 0) {
-- dst.position(pos + sslRead);
-- }
-- } else {
-- final int limit = dst.limit();
-- final int len = min(MAX_ENCRYPTED_PACKET_LENGTH, limit - pos);
-- final ByteBuf buf = alloc.directBuffer(len);
-- try {
-- sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len);
-- if (sslRead > 0) {
-- dst.limit(pos + sslRead);
-- buf.getBytes(buf.readerIndex(), dst);
-- dst.limit(limit);
-- }
-- } finally {
-- buf.release();
-- }
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
String auth)
+- throws Exception {
+- manager.checkServerTrusted(peerCerts, auth);
- }
--
-- return sslRead;
- }
-
-- @Override
-- public final SSLEngineResult wrap(
-- final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst)
throws SSLException {
-- // Throw required runtime exceptions
-- if (srcs == null) {
-- throw new IllegalArgumentException("srcs is null");
-- }
-- if (dst == null) {
-- throw new IllegalArgumentException("dst is null");
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- private static final class ExtendedTrustManagerVerifyCallback extends
AbstractCertificateVerifier {
+- private final X509ExtendedTrustManager manager;
+-
+- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap,
X509ExtendedTrustManager manager) {
+- super(engineMap);
+- this.manager = OpenSslTlsv13X509ExtendedTrustManager.wrap(manager);
- }
-
-- if (offset >= srcs.length || offset + length > srcs.length) {
-- throw new IndexOutOfBoundsException(
-- "offset: " + offset + ", length: " + length +
-- " (expected: offset <= offset + length <=
srcs.length (" + srcs.length + "))");
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
String auth)
+- throws Exception {
+- manager.checkServerTrusted(peerCerts, auth, engine);
- }
+- }
-
-- if (dst.isReadOnly()) {
-- throw new ReadOnlyBufferException();
+- private static final class OpenSslClientCertificateCallback implements
CertificateCallback {
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslKeyMaterialManager keyManagerHolder;
+-
+- OpenSslClientCertificateCallback(OpenSslEngineMap engineMap,
OpenSslKeyMaterialManager keyManagerHolder) {
+- this.engineMap = engineMap;
+- this.keyManagerHolder = keyManagerHolder;
- }
-
-- synchronized (this) {
-- if (isOutboundDone()) {
-- // All drained in the outbound buffer
-- return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING :
NEED_UNWRAP_CLOSED;
+- @Override
+- public void handle(long ssl, byte[] keyTypeBytes, byte[][]
asn1DerEncodedPrincipals) throws Exception {
+- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- // May be null if it was destroyed in the meantime.
+- if (engine == null) {
+- return;
- }
--
-- int bytesProduced = 0;
-- ByteBuf bioReadCopyBuf = null;
- try {
-- // Setup the BIO buffer so that we directly write the encryption results
into dst.
-- if (dst.isDirect()) {
-- SSL.bioSetByteBuffer(networkBIO, Buffer.address(dst) +
dst.position(), dst.remaining(),
-- true);
+- final Set<String> keyTypesSet =
supportedClientKeyTypes(keyTypeBytes);
+- final String[] keyTypes = keyTypesSet.toArray(new String[0]);
+- final X500Principal[] issuers;
+- if (asn1DerEncodedPrincipals == null) {
+- issuers = null;
- } else {
-- bioReadCopyBuf = alloc.directBuffer(dst.remaining());
-- SSL.bioSetByteBuffer(networkBIO, memoryAddress(bioReadCopyBuf),
bioReadCopyBuf.writableBytes(),
-- true);
-- }
--
-- int bioLengthBefore = SSL.bioLengthByteBuffer(networkBIO);
--
-- // Explicit use outboundClosed as we want to drain any bytes that are
still present.
-- if (outboundClosed) {
-- // There is something left to drain.
-- // See
https://github.com/netty/netty/issues/6260
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-- if (bytesProduced <= 0) {
-- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0);
-- }
-- // It is possible when the outbound was closed there was not enough
room in the non-application
-- // buffers to hold the close_notify. We should keep trying to close
until we consume all the data
-- // OpenSSL can give us.
-- if (!doSSLShutdown()) {
-- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0,
bytesProduced);
+- issuers = new X500Principal[asn1DerEncodedPrincipals.length];
+- for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
+- issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
- }
-- bytesProduced = bioLengthBefore -
SSL.bioLengthByteBuffer(networkBIO);
-- return newResultMayFinishHandshake(NEED_WRAP, 0, bytesProduced);
- }
+- keyManagerHolder.setKeyMaterialClientSide(engine, keyTypes, issuers);
+- } catch (Throwable cause) {
+- logger.debug("request of key failed", cause);
+- engine.initHandshakeException(cause);
+- }
+- }
-
-- // Flush any data that may be implicitly generated by OpenSSL
(handshake, close, etc..).
-- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
-- // Prepare OpenSSL to work in server mode and receive handshake
-- if (handshakeState != HandshakeState.FINISHED) {
-- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
-- // Update accepted so we know we triggered the handshake via
wrap
-- handshakeState = HandshakeState.STARTED_IMPLICITLY;
-- }
--
-- // Flush any data that may have been written implicitly during the
handshake by OpenSSL.
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
--
-- if (bytesProduced > 0 && handshakeException != null) {
-- // TODO(scott): It is possible that when the handshake failed
there was not enough room in the
-- // non-application buffers to hold the alert. We should get all
the data before progressing on.
-- // However I'm not aware of a way to do this with the
OpenSSL APIs.
-- // See
https://github.com/netty/netty/issues/6385.
--
-- // We produced / consumed some data during the handshake, signal
back to the caller.
-- // If there is a handshake exception and we have produced data,
we should send the data before
-- // we allow handshake() to throw the handshake exception.
-- return newResult(NEED_WRAP, 0, bytesProduced);
-- }
--
-- status = handshake();
+- /**
+- * Gets the supported key types for client certificates.
+- *
+- * @param clientCertificateTypes {@code ClientCertificateType} values provided
by the server.
+- * See
https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml.
+- * @return supported key types that can be used in {@code
X509KeyManager.chooseClientAlias} and
+- * {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
+- */
+- private static Set<String> supportedClientKeyTypes(byte[]
clientCertificateTypes) {
+- if (clientCertificateTypes == null) {
+- // Try all of the supported key types.
+- return SUPPORTED_KEY_TYPES;
+- }
+- Set<String> result = new
HashSet<String>(clientCertificateTypes.length);
+- for (byte keyTypeCode : clientCertificateTypes) {
+- String keyType = clientKeyType(keyTypeCode);
+- if (keyType == null) {
+- // Unsupported client key type -- ignore
+- continue;
+- }
+- result.add(keyType);
+- }
+- return result;
+- }
-
-- if (renegotiationPending && status == FINISHED) {
-- // If renegotiationPending is true that means when we attempted
to start renegotiation
-- // the BIO buffer didn't have enough space to hold the
HelloRequest which prompts the
-- // client to initiate a renegotiation. At this point the
HelloRequest has been written
-- // so we can actually start the handshake process.
-- renegotiationPending = false;
-- SSL.setState(ssl, SSL.SSL_ST_ACCEPT);
-- handshakeState = HandshakeState.STARTED_EXPLICITLY;
-- status = handshake();
-- }
+- private static String clientKeyType(byte clientCertificateType) {
+- // See also
http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
+- switch (clientCertificateType) {
+- case CertificateCallback.TLS_CT_RSA_SIGN:
+- return OpenSslKeyMaterialManager.KEY_TYPE_RSA; // RFC rsa_sign
+- case CertificateCallback.TLS_CT_RSA_FIXED_DH:
+- return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA; // RFC
rsa_fixed_dh
+- case CertificateCallback.TLS_CT_ECDSA_SIGN:
+- return OpenSslKeyMaterialManager.KEY_TYPE_EC; // RFC ecdsa_sign
+- case CertificateCallback.TLS_CT_RSA_FIXED_ECDH:
+- return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA; // RFC
rsa_fixed_ecdh
+- case CertificateCallback.TLS_CT_ECDSA_FIXED_ECDH:
+- return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC; // RFC
ecdsa_fixed_ecdh
+- default:
+- return null;
+- }
+- }
+- }
+-}
+diff --git
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
+deleted file mode 100644
+index 27eb43574c..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
++++ /dev/null
+@@ -1,968 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- // Handshake may have generated more data, for example if the
internal SSL buffer is small
-- // we may have freed up space by flushing above.
-- bytesProduced = bioLengthBefore -
SSL.bioLengthByteBuffer(networkBIO);
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.internal.tcnative.CertificateVerifier;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.internal.tcnative.SSLPrivateKeyMethod;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.ReferenceCounted;
+-import io.netty.util.ResourceLeakDetector;
+-import io.netty.util.ResourceLeakDetectorFactory;
+-import io.netty.util.ResourceLeakTracker;
+-import io.netty.util.internal.ObjectUtil;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.StringUtil;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.UnstableApi;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-- if (bytesProduced > 0) {
-- // If we have filled up the dst buffer and we have not finished
the handshake we should try to
-- // wrap again. Otherwise we should only try to wrap again if
there is still data pending in
-- // SSL buffers.
-- return newResult(mayFinishHandshake(status != FINISHED ?
-- bytesProduced == bioLengthBefore ? NEED_WRAP :
--
getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) : FINISHED),
-- 0, bytesProduced);
-- }
+-import java.security.PrivateKey;
+-import java.security.SignatureException;
+-import java.security.cert.CertPathValidatorException;
+-import java.security.cert.Certificate;
+-import java.security.cert.CertificateExpiredException;
+-import java.security.cert.CertificateNotYetValidException;
+-import java.security.cert.CertificateRevokedException;
+-import java.security.cert.X509Certificate;
+-import java.util.Arrays;
+-import java.util.Collections;
+-import java.util.List;
+-import java.util.Map;
+-import java.util.concurrent.Executor;
+-import java.util.concurrent.locks.Lock;
+-import java.util.concurrent.locks.ReadWriteLock;
+-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-- if (status == NEED_UNWRAP) {
-- // Signal if the outbound is done or not.
-- return isOutboundDone() ? NEED_UNWRAP_CLOSED : NEED_UNWRAP_OK;
-- }
+-import javax.net.ssl.KeyManager;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.TrustManager;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509KeyManager;
+-import javax.net.ssl.X509TrustManager;
-
-- // Explicit use outboundClosed and not outboundClosed() as we want
to drain any bytes that are
-- // still present.
-- if (outboundClosed) {
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-- return newResultMayFinishHandshake(status, 0, bytesProduced);
-- }
-- }
+-import static io.netty.handler.ssl.OpenSsl.DEFAULT_CIPHERS;
+-import static io.netty.handler.ssl.OpenSsl.availableJavaCipherSuites;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
-
-- int srcsLen = 0;
-- final int endOffset = offset + length;
-- for (int i = offset; i < endOffset; ++i) {
-- final ByteBuffer src = srcs[i];
-- if (src == null) {
-- throw new IllegalArgumentException("srcs[" + i +
"] is null");
-- }
-- if (srcsLen == MAX_PLAINTEXT_LENGTH) {
-- continue;
-- }
+-/**
+- * An implementation of {@link SslContext} which works with libraries that support the
+- * <a
href="https://www.openssl.org/">OpenSsl</a> C library API.
+- * <p>Instances of this class must be {@link #release() released} or else native
memory will leak!
+- *
+- * <p>Instances of this class <strong>must not</strong> be released
before any {@link ReferenceCountedOpenSslEngine}
+- * which depends upon the instance of this class is released. Otherwise if any method
of
+- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI
resources the JVM may crash.
+- */
+-public abstract class ReferenceCountedOpenSslContext extends SslContext implements
ReferenceCounted {
+- private static final InternalLogger logger =
+- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class);
-
-- srcsLen += src.remaining();
-- if (srcsLen > MAX_PLAINTEXT_LENGTH || srcsLen < 0) {
-- // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set
it to MAX_PLAINTEXT_LENGTH.
-- // This also help us to guard against overflow.
-- // We not break out here as we still need to check for null
entries in srcs[].
-- srcsLen = MAX_PLAINTEXT_LENGTH;
-- }
-- }
+- private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE = Math.max(1,
+-
SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize",
+- 2048));
+- static final boolean USE_TASKS =
+-
SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.useTasks", false);
+- private static final Integer DH_KEY_LENGTH;
+- private static final ResourceLeakDetector<ReferenceCountedOpenSslContext>
leakDetector =
+-
ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class);
-
-- // we will only produce a single TLS packet, and we don't aggregate
src buffers,
-- // so we always fix the number of buffers to 1 when checking if the dst
buffer is large enough.
-- if (dst.remaining() < calculateOutNetBufSize(srcsLen, 1)) {
-- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0,
0);
-- }
+- // TODO: Maybe make configurable ?
+- protected static final int VERIFY_DEPTH = 10;
-
-- // There was no pending data in the network BIO -- encrypt any
application data
-- int bytesConsumed = 0;
-- // Flush any data that may have been written implicitly by OpenSSL in
case a shutdown/alert occurs.
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-- for (; offset < endOffset; ++offset) {
-- final ByteBuffer src = srcs[offset];
-- final int remaining = src.remaining();
-- if (remaining == 0) {
-- continue;
-- }
+- /**
+- * The OpenSSL SSL_CTX object.
+- *
+- * <strong>{@link #ctxLock} must be hold while using ctx!</strong>
+- */
+- protected long ctx;
+- private final List<String> unmodifiableCiphers;
+- private final long sessionCacheSize;
+- private final long sessionTimeout;
+- private final OpenSslApplicationProtocolNegotiator apn;
+- private final int mode;
-
-- // Write plaintext application data to the SSL engine
-- int bytesWritten = writePlaintextData(src, min(remaining,
MAX_PLAINTEXT_LENGTH - bytesConsumed));
+- // Reference Counting
+- private final ResourceLeakTracker<ReferenceCountedOpenSslContext> leak;
+- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
+- @Override
+- public ReferenceCounted touch(Object hint) {
+- if (leak != null) {
+- leak.record(hint);
+- }
-
-- if (bytesWritten > 0) {
-- bytesConsumed += bytesWritten;
+- return ReferenceCountedOpenSslContext.this;
+- }
-
-- // Determine how much encrypted data was generated:
-- final int pendingNow = SSL.bioLengthByteBuffer(networkBIO);
-- bytesProduced += bioLengthBefore - pendingNow;
-- bioLengthBefore = pendingNow;
+- @Override
+- protected void deallocate() {
+- destroy();
+- if (leak != null) {
+- boolean closed = leak.close(ReferenceCountedOpenSslContext.this);
+- assert closed;
+- }
+- }
+- };
-
-- return newResultMayFinishHandshake(status, bytesConsumed,
bytesProduced);
-- } else {
-- int sslError = SSL.getError(ssl, bytesWritten);
-- if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
-- // This means the connection was shutdown correctly, close
inbound and outbound
-- if (!receivedShutdown) {
-- closeAll();
+- final Certificate[] keyCertChain;
+- final ClientAuth clientAuth;
+- final String[] protocols;
+- final boolean enableOcsp;
+- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
+- final ReadWriteLock ctxLock = new ReentrantReadWriteLock();
-
-- bytesProduced += bioLengthBefore -
SSL.bioLengthByteBuffer(networkBIO);
+- private volatile int bioNonApplicationBufferSize =
DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE;
-
-- // If we have filled up the dst buffer and we have not
finished the handshake we should
-- // try to wrap again. Otherwise we should only try to
wrap again if there is still data
-- // pending in SSL buffers.
-- SSLEngineResult.HandshakeStatus hs =
mayFinishHandshake(
-- status != FINISHED ? bytesProduced ==
dst.remaining() ? NEED_WRAP
-- :
getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO))
-- : FINISHED);
-- return newResult(hs, bytesConsumed, bytesProduced);
-- }
+- @SuppressWarnings("deprecation")
+- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR =
+- new OpenSslApplicationProtocolNegotiator() {
+- @Override
+- public ApplicationProtocolConfig.Protocol protocol() {
+- return ApplicationProtocolConfig.Protocol.NONE;
+- }
-
-- return newResult(NOT_HANDSHAKING, bytesConsumed,
bytesProduced);
-- } else if (sslError == SSL.SSL_ERROR_WANT_READ) {
-- // If there is no pending data to read from BIO we should go
back to event loop and try
-- // to read more data [1]. It is also possible that event
loop will detect the socket has
-- // been closed. [1]
https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
-- return newResult(NEED_UNWRAP, bytesConsumed,
bytesProduced);
-- } else if (sslError == SSL.SSL_ERROR_WANT_WRITE) {
-- // SSL_ERROR_WANT_WRITE typically means that the underlying
transport is not writable
-- // and we should set the "want write" flag on the
selector and try again when the
-- // underlying transport is writable [1]. However we are not
directly writing to the
-- // underlying transport and instead writing to a BIO buffer.
The OpenSsl documentation
-- // says we should do the following [1]:
-- //
-- // "When using a buffering BIO, like a BIO pair, data
must be written into or retrieved
-- // out of the BIO before being able to continue."
-- //
-- // So we attempt to drain the BIO buffer below, but if there
is no data this condition
-- // is undefined and we assume their is a fatal error with
the openssl engine and close.
-- // [1]
https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
-- return newResult(NEED_WRAP, bytesConsumed, bytesProduced);
-- } else {
-- // Everything else is considered as error
-- throw shutdownWithError("SSL_write");
-- }
-- }
+- @Override
+- public List<String> protocols() {
+- return Collections.emptyList();
- }
-- return newResultMayFinishHandshake(status, bytesConsumed,
bytesProduced);
-- } finally {
-- SSL.bioClearByteBuffer(networkBIO);
-- if (bioReadCopyBuf == null) {
-- dst.position(dst.position() + bytesProduced);
-- } else {
-- assert bioReadCopyBuf.readableBytes() <= dst.remaining() :
"The destination buffer " + dst +
-- " didn't have enough remaining space to hold the
encrypted content in " + bioReadCopyBuf;
--
dst.put(bioReadCopyBuf.internalNioBuffer(bioReadCopyBuf.readerIndex(), bytesProduced));
-- bioReadCopyBuf.release();
+-
+- @Override
+- public ApplicationProtocolConfig.SelectorFailureBehavior
selectorFailureBehavior() {
+- return
ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL;
- }
-- }
-- }
-- }
-
-- private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int
bytesConsumed, int bytesProduced) {
-- return newResult(OK, hs, bytesConsumed, bytesProduced);
-- }
+- @Override
+- public ApplicationProtocolConfig.SelectedListenerFailureBehavior
selectedListenerFailureBehavior() {
+- return
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT;
+- }
+- };
-
-- private SSLEngineResult newResult(SSLEngineResult.Status status,
SSLEngineResult.HandshakeStatus hs,
-- int bytesConsumed, int bytesProduced) {
-- // If isOutboundDone, then the data from the network BIO
-- // was the close_notify message and all was consumed we are not required to
wait
-- // for the receipt the peer's close_notify message -- shutdown.
-- if (isOutboundDone()) {
-- if (isInboundDone()) {
-- // If the inbound was done as well, we need to ensure we return
NOT_HANDSHAKING to signal we are done.
-- hs = NOT_HANDSHAKING;
+- static {
+- Integer dhLen = null;
-
-- // As the inbound and the outbound is done we can shutdown the engine
now.
-- shutdown();
+- try {
+- String dhKeySize =
SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize");
+- if (dhKeySize != null) {
+- try {
+- dhLen = Integer.valueOf(dhKeySize);
+- } catch (NumberFormatException e) {
+- logger.debug("ReferenceCountedOpenSslContext supports
-Djdk.tls.ephemeralDHKeySize={int}, but got: "
+- + dhKeySize);
+- }
- }
-- return new SSLEngineResult(CLOSED, hs, bytesConsumed, bytesProduced);
+- } catch (Throwable ignore) {
+- // ignore
- }
-- return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced);
+- DH_KEY_LENGTH = dhLen;
- }
-
-- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus
hs,
-- int bytesConsumed, int
bytesProduced) throws SSLException {
-- return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() :
FINISHED),
-- bytesConsumed, bytesProduced);
+- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter
cipherFilter,
+- ApplicationProtocolConfig apnCfg, long
sessionCacheSize, long sessionTimeout,
+- int mode, Certificate[] keyCertChain, ClientAuth
clientAuth, String[] protocols,
+- boolean startTls, boolean enableOcsp, boolean
leakDetection) throws SSLException {
+- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize,
sessionTimeout, mode, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp, leakDetection);
- }
-
-- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status,
-- SSLEngineResult.HandshakeStatus
hs,
-- int bytesConsumed, int
bytesProduced) throws SSLException {
-- return newResult(status, mayFinishHandshake(hs != FINISHED ?
getHandshakeStatus() : FINISHED),
-- bytesConsumed, bytesProduced);
-- }
+- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter
cipherFilter,
+- OpenSslApplicationProtocolNegotiator apn, long
sessionCacheSize,
+- long sessionTimeout, int mode, Certificate[]
keyCertChain,
+- ClientAuth clientAuth, String[] protocols, boolean
startTls, boolean enableOcsp,
+- boolean leakDetection) throws SSLException {
+- super(startTls);
-
-- /**
-- * Log the error, shutdown the engine and throw an exception.
-- */
-- private SSLException shutdownWithError(String operations) {
-- String err = SSL.getLastError();
-- return shutdownWithError(operations, err);
-- }
+- OpenSsl.ensureAvailability();
-
-- private SSLException shutdownWithError(String operation, String err) {
-- if (logger.isDebugEnabled()) {
-- logger.debug("{} failed: OpenSSL error: {}", operation, err);
+- if (enableOcsp && !OpenSsl.isOcspSupported()) {
+- throw new IllegalStateException("OCSP is not supported.");
- }
-
-- // There was an internal error -- shutdown
-- shutdown();
-- if (handshakeState == HandshakeState.FINISHED) {
-- return new SSLException(err);
+- if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) {
+- throw new IllegalArgumentException("mode most be either
SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT");
- }
-- return new SSLHandshakeException(err);
-- }
+- leak = leakDetection ? leakDetector.track(this) : null;
+- this.mode = mode;
+- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth")
: ClientAuth.NONE;
+- this.protocols = protocols;
+- this.enableOcsp = enableOcsp;
-
-- public final SSLEngineResult unwrap(
-- final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
-- final ByteBuffer[] dsts, int dstsOffset, final int dstsLength) throws
SSLException {
+- this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone();
-
-- // Throw required runtime exceptions
-- if (srcs == null) {
-- throw new NullPointerException("srcs");
-- }
-- if (srcsOffset >= srcs.length
-- || srcsOffset + srcsLength > srcs.length) {
-- throw new IndexOutOfBoundsException(
-- "offset: " + srcsOffset + ", length: " +
srcsLength +
-- " (expected: offset <= offset + length <=
srcs.length (" + srcs.length + "))");
-- }
-- if (dsts == null) {
-- throw new IllegalArgumentException("dsts is null");
-- }
-- if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) {
-- throw new IndexOutOfBoundsException(
-- "offset: " + dstsOffset + ", length: " +
dstsLength +
-- " (expected: offset <= offset + length <=
dsts.length (" + dsts.length + "))");
-- }
-- long capacity = 0;
-- final int dstsEndOffset = dstsOffset + dstsLength;
-- for (int i = dstsOffset; i < dstsEndOffset; i ++) {
-- ByteBuffer dst = dsts[i];
-- if (dst == null) {
-- throw new IllegalArgumentException("dsts[" + i + "] is
null");
-- }
-- if (dst.isReadOnly()) {
-- throw new ReadOnlyBufferException();
+- unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter,
"cipherFilter").filterCipherSuites(
+- ciphers, DEFAULT_CIPHERS, availableJavaCipherSuites()));
+-
+- this.apn = checkNotNull(apn, "apn");
+-
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- try {
+- int protocolOpts = SSL.SSL_PROTOCOL_SSLV3 | SSL.SSL_PROTOCOL_TLSV1 |
+- SSL.SSL_PROTOCOL_TLSV1_1 | SSL.SSL_PROTOCOL_TLSV1_2;
+- if (OpenSsl.isTlsv13Supported()) {
+- protocolOpts |= SSL.SSL_PROTOCOL_TLSV1_3;
+- }
+- ctx = SSLContext.make(protocolOpts, mode);
+- } catch (Exception e) {
+- throw new SSLException("failed to create an SSL_CTX", e);
- }
-- capacity += dst.remaining();
-- }
-
-- final int srcsEndOffset = srcsOffset + srcsLength;
-- long len = 0;
-- for (int i = srcsOffset; i < srcsEndOffset; i++) {
-- ByteBuffer src = srcs[i];
-- if (src == null) {
-- throw new IllegalArgumentException("srcs[" + i + "] is
null");
+- boolean tlsv13Supported = OpenSsl.isTlsv13Supported();
+- StringBuilder cipherBuilder = new StringBuilder();
+- StringBuilder cipherTLSv13Builder = new StringBuilder();
+-
+- /* List the ciphers that are permitted to negotiate. */
+- try {
+- if (unmodifiableCiphers.isEmpty()) {
+- // Set non TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, false);
+- if (tlsv13Supported) {
+- // Set TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, true);
+- }
+- } else {
+- CipherSuiteConverter.convertToCipherStrings(
+- unmodifiableCiphers, cipherBuilder, cipherTLSv13Builder,
OpenSsl.isBoringSSL());
+-
+- // Set non TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, cipherBuilder.toString(), false);
+- if (tlsv13Supported) {
+- // Set TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, cipherTLSv13Builder.toString(),
true);
+- }
+- }
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("failed to set cipher suite: " +
unmodifiableCiphers, e);
- }
-- len += src.remaining();
-- }
-
-- synchronized (this) {
-- if (isInboundDone()) {
-- return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING :
NEED_WRAP_CLOSED;
+- int options = SSLContext.getOptions(ctx) |
+- SSL.SSL_OP_NO_SSLv2 |
+- SSL.SSL_OP_NO_SSLv3 |
+- // Disable TLSv1.3 by default for now. Even if TLSv1.3 is not
supported this will
+- // work fine as in this case SSL_OP_NO_TLSv1_3 will be 0.
+- SSL.SSL_OP_NO_TLSv1_3 |
+-
+- SSL.SSL_OP_CIPHER_SERVER_PREFERENCE |
+-
+- // We do not support compression at the moment so we should
explicitly disable it.
+- SSL.SSL_OP_NO_COMPRESSION |
+-
+- // Disable ticket support by default to be more inline with
SSLEngineImpl of the JDK.
+- // This also let SSLSession.getId() work the same way for the
JDK implementation and the
+- // OpenSSLEngine. If tickets are supported SSLSession.getId()
will only return an ID on the
+- // server-side if it could make use of tickets.
+- SSL.SSL_OP_NO_TICKET;
+-
+- if (cipherBuilder.length() == 0) {
+- // No ciphers that are compatible with SSLv2 / SSLv3 / TLSv1 / TLSv1.1 /
TLSv1.2
+- options |= SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 |
SSL.SSL_OP_NO_TLSv1
+- | SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2;
- }
-
-- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
-- // Prepare OpenSSL to work in server mode and receive handshake
-- if (handshakeState != HandshakeState.FINISHED) {
-- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
-- // Update accepted so we know we triggered the handshake via wrap
-- handshakeState = HandshakeState.STARTED_IMPLICITLY;
-- }
+- SSLContext.setOptions(ctx, options);
+-
+- // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory
address may change between
+- // calling OpenSSLEngine.wrap(...).
+- // See
https://github.com/netty/netty-tcnative/issues/100
+- SSLContext.setMode(ctx, SSLContext.getMode(ctx) |
SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-
-- status = handshake();
-- if (status == NEED_WRAP) {
-- return NEED_WRAP_OK;
-- }
-- // Check if the inbound is considered to be closed if so let us try to
wrap again.
-- if (isInboundDone) {
-- return NEED_WRAP_CLOSED;
-- }
+- if (DH_KEY_LENGTH != null) {
+- SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH);
- }
-
-- if (len < SSL_RECORD_HEADER_LENGTH) {
-- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- List<String> nextProtoList = apn.protocols();
+- /* Set next protocols for next protocol negotiation extension, if
specified */
+- if (!nextProtoList.isEmpty()) {
+- String[] appProtocols = nextProtoList.toArray(new String[0]);
+- int selectorBehavior =
opensslSelectorFailureBehavior(apn.selectorFailureBehavior());
+-
+- switch (apn.protocol()) {
+- case NPN:
+- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
+- break;
+- case ALPN:
+- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
+- break;
+- case NPN_AND_ALPN:
+- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
+- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
+- break;
+- default:
+- throw new Error();
+- }
- }
-
-- int packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset);
+- /* Set session cache size, if specified */
+- if (sessionCacheSize <= 0) {
+- // Get the default session cache size using
SSLContext.setSessionCacheSize()
+- sessionCacheSize = SSLContext.setSessionCacheSize(ctx, 20480);
+- }
+- this.sessionCacheSize = sessionCacheSize;
+- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
-
-- if (packetLength == SslUtils.NOT_ENCRYPTED) {
-- throw new NotSslRecordException("not an SSL/TLS record");
+- /* Set session timeout, if specified */
+- if (sessionTimeout <= 0) {
+- // Get the default session timeout using
SSLContext.setSessionCacheTimeout()
+- sessionTimeout = SSLContext.setSessionCacheTimeout(ctx, 300);
- }
+- this.sessionTimeout = sessionTimeout;
+- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
-
-- if (packetLength - SSL_RECORD_HEADER_LENGTH > capacity) {
-- // No enough space in the destination buffer so signal the caller
-- // that the buffer needs to be increased.
-- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
+- if (enableOcsp) {
+- SSLContext.enableOcsp(ctx, isClient());
- }
-
-- if (len < packetLength) {
-- // We either have no enough data to read the packet length at all or not
enough for reading
-- // the whole packet.
-- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- SSLContext.setUseTasks(ctx, USE_TASKS);
+- success = true;
+- } finally {
+- if (!success) {
+- release();
- }
+- }
+- }
-
-- // This must always be the case when we reached here as if not we returned
BUFFER_UNDERFLOW.
-- assert srcsOffset < srcsEndOffset;
+- private static int
opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior)
{
+- switch (behavior) {
+- case NO_ADVERTISE:
+- return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE;
+- case CHOOSE_MY_LAST_PROTOCOL:
+- return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL;
+- default:
+- throw new Error();
+- }
+- }
-
-- // This must always be the case if we reached here.
-- assert capacity > 0;
+- @Override
+- public final List<String> cipherSuites() {
+- return unmodifiableCiphers;
+- }
-
-- // Number of produced bytes
-- int bytesProduced = 0;
-- int bytesConsumed = 0;
-- try {
-- for (; srcsOffset < srcsEndOffset; ++srcsOffset) {
-- ByteBuffer src = srcs[srcsOffset];
-- int remaining = src.remaining();
-- if (remaining == 0) {
-- // We must skip empty buffers as BIO_write will return 0 if
asked to write something
-- // with length 0.
-- continue;
-- }
-- // Write more encrypted data into the BIO. Ensure we only read one
packet at a time as
-- // stated in the SSLEngine javadocs.
-- int pendingEncryptedBytes = min(packetLength, remaining);
-- ByteBuf bioWriteCopyBuf = writeEncryptedData(src,
pendingEncryptedBytes);
-- try {
-- readLoop:
-- for (; dstsOffset < dstsEndOffset; ++dstsOffset) {
-- ByteBuffer dst = dsts[dstsOffset];
-- if (!dst.hasRemaining()) {
-- // No space left in the destination buffer, skip it.
-- continue;
-- }
+- @Override
+- public final long sessionCacheSize() {
+- return sessionCacheSize;
+- }
-
-- int bytesRead = readPlaintextData(dst);
-- // We are directly using the ByteBuffer memory for the
write, and so we only know what
-- // has been consumed after we let SSL decrypt the data. At
this point we should update
-- // the number of bytes consumed, update the ByteBuffer
position, and release temp
-- // ByteBuf.
-- int localBytesConsumed = pendingEncryptedBytes -
SSL.bioLengthByteBuffer(networkBIO);
-- bytesConsumed += localBytesConsumed;
-- packetLength -= localBytesConsumed;
-- pendingEncryptedBytes -= localBytesConsumed;
-- src.position(src.position() + localBytesConsumed);
+- @Override
+- public final long sessionTimeout() {
+- return sessionTimeout;
+- }
-
-- if (bytesRead > 0) {
-- bytesProduced += bytesRead;
+- @Override
+- public ApplicationProtocolNegotiator applicationProtocolNegotiator() {
+- return apn;
+- }
-
-- if (!dst.hasRemaining()) {
-- // Move to the next dst buffer as this one is full.
-- continue;
-- }
-- if (packetLength == 0) {
-- // We read everything return now.
-- return newResultMayFinishHandshake(isInboundDone() ?
CLOSED : OK, status,
-- bytesConsumed,
bytesProduced);
-- }
-- // try to write again to the BIO. stop reading from it
by break out of the readLoop.
-- break;
-- } else {
-- int sslError = SSL.getError(ssl, bytesRead);
-- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError ==
SSL.SSL_ERROR_WANT_WRITE) {
-- // break to the outer loop as we want to read more
data which means we need to
-- // write more to the BIO.
-- break readLoop;
-- } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
-- // This means the connection was shutdown correctly,
close inbound and outbound
-- if (!receivedShutdown) {
-- closeAll();
-- }
-- return newResultMayFinishHandshake(isInboundDone() ?
CLOSED : OK, status,
-- bytesConsumed,
bytesProduced);
-- } else {
-- return sslReadErrorResult(SSL.getLastErrorNumber(),
bytesConsumed,
-- bytesProduced);
-- }
-- }
-- }
+- @Override
+- public final boolean isClient() {
+- return mode == SSL.SSL_MODE_CLIENT;
+- }
-
-- // Either we have no more dst buffers to put the data, or no
more data to generate; we are done.
-- if (dstsOffset >= dstsEndOffset || packetLength == 0) {
-- break;
-- }
-- } finally {
-- if (bioWriteCopyBuf != null) {
-- bioWriteCopyBuf.release();
-- }
-- }
-- }
-- } finally {
-- SSL.bioClearByteBuffer(networkBIO);
-- rejectRemoteInitiatedRenegotiation();
-- }
+- @Override
+- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int
peerPort) {
+- return newEngine0(alloc, peerHost, peerPort, true);
+- }
-
-- // Check to see if we received a close_notify message from the peer.
-- if (!receivedShutdown && (SSL.getShutdown(ssl) &
SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
-- closeAll();
-- }
+- @Override
+- protected final SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
+- return new SslHandler(newEngine0(alloc, null, -1, false), startTls);
+- }
-
-- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
bytesConsumed, bytesProduced);
-- }
+- @Override
+- protected final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int
peerPort, boolean startTls) {
+- return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), startTls);
- }
-
-- private SSLEngineResult sslReadErrorResult(int err, int bytesConsumed, int
bytesProduced) throws SSLException {
-- String errStr = SSL.getErrorString(err);
+- @Override
+- protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor
executor) {
+- return new SslHandler(newEngine0(alloc, null, -1, false), startTls, executor);
+- }
-
-- // Check if we have a pending handshakeException and if so see if we need to
consume all pending data from the
-- // BIO first or can just shutdown and throw it now.
-- // This is needed so we ensure close_notify etc is correctly send to the remote
peer.
-- // See
https://github.com/netty/netty/issues/3900
-- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
-- if (handshakeException == null && handshakeState !=
HandshakeState.FINISHED) {
-- // we seems to have data left that needs to be transfered and so the
user needs
-- // call wrap(...). Store the error so we can pick it up later.
-- handshakeException = new SSLHandshakeException(errStr);
-- }
-- return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced);
-- }
-- throw shutdownWithError("SSL_read", errStr);
+- @Override
+- protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int
peerPort,
+- boolean startTls, Executor executor) {
+- return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), executor);
- }
-
-- private void closeAll() throws SSLException {
-- receivedShutdown = true;
-- closeOutbound();
-- closeInbound();
+- SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean
jdkCompatibilityMode) {
+- return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort,
jdkCompatibilityMode, true);
- }
-
-- private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException {
-- if (rejectRemoteInitiatedRenegotiation && SSL.getHandshakeCount(ssl)
> 1) {
-- // TODO: In future versions me may also want to send a fatal_alert to the
client and so notify it
-- // that the renegotiation failed.
-- shutdown();
-- throw new SSLHandshakeException("remote-initiated renegotiation not
allowed");
-- }
+- /**
+- * Returns a new server-side {@link SSLEngine} with the current configuration.
+- */
+- @Override
+- public final SSLEngine newEngine(ByteBufAllocator alloc) {
+- return newEngine(alloc, null, -1);
- }
-
-- public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[]
dsts) throws SSLException {
-- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
+- /**
+- * Returns the pointer to the {@code SSL_CTX} object for this {@link
ReferenceCountedOpenSslContext}.
+- * Be aware that it is freed as soon as the {@link #finalize()} method is called.
+- * At this point {@code 0} will be returned.
+- *
+- * @deprecated this method is considered unsafe as the returned pointer may be
released later. Dont use it!
+- */
+- @Deprecated
+- public final long context() {
+- return sslCtxPointer();
- }
-
-- private ByteBuffer[] singleSrcBuffer(ByteBuffer src) {
-- singleSrcBuffer[0] = src;
-- return singleSrcBuffer;
+- /**
+- * Returns the stats of this context.
+- *
+- * @deprecated use {@link #sessionContext#stats()}
+- */
+- @Deprecated
+- public final OpenSslSessionStats stats() {
+- return sessionContext().stats();
- }
-
-- private void resetSingleSrcBuffer() {
-- singleSrcBuffer[0] = null;
+- /**
+- * {@deprecated Renegotiation is not supported}
+- * Specify if remote initiated renegotiation is supported or not. If not supported
and the remote side tries
+- * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during
decoding.
+- */
+- @Deprecated
+- public void setRejectRemoteInitiatedRenegotiation(boolean
rejectRemoteInitiatedRenegotiation) {
+- if (!rejectRemoteInitiatedRenegotiation) {
+- throw new UnsupportedOperationException("Renegotiation is not
supported");
+- }
- }
-
-- private ByteBuffer[] singleDstBuffer(ByteBuffer src) {
-- singleDstBuffer[0] = src;
-- return singleDstBuffer;
+- /**
+- * {@deprecated Renegotiation is not supported}
+- * @return {@code true} because renegotiation is not supported.
+- */
+- @Deprecated
+- public boolean getRejectRemoteInitiatedRenegotiation() {
+- return true;
- }
-
-- private void resetSingleDstBuffer() {
-- singleDstBuffer[0] = null;
+- /**
+- * Set the size of the buffer used by the BIO for non-application based writes
+- * (e.g. handshake, renegotiation, etc...).
+- */
+- public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) {
+- this.bioNonApplicationBufferSize =
+- checkPositiveOrZero(bioNonApplicationBufferSize,
"bioNonApplicationBufferSize");
+- }
+-
+- /**
+- * Returns the size of the buffer used by the BIO for non-application based writes
+- */
+- public int getBioNonApplicationBufferSize() {
+- return bioNonApplicationBufferSize;
+- }
+-
+- /**
+- * Sets the SSL session ticket keys of this context.
+- *
+- * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])}
+- */
+- @Deprecated
+- public final void setTicketKeys(byte[] keys) {
+- sessionContext().setTicketKeys(keys);
- }
-
- @Override
-- public final synchronized SSLEngineResult unwrap(
-- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int
length) throws SSLException {
+- public abstract OpenSslSessionContext sessionContext();
+-
+- /**
+- * Returns the pointer to the {@code SSL_CTX} object for this {@link
ReferenceCountedOpenSslContext}.
+- * Be aware that it is freed as soon as the {@link #release()} method is called.
+- * At this point {@code 0} will be returned.
+- *
+- * @deprecated this method is considered unsafe as the returned pointer may be
released later. Dont use it!
+- */
+- @Deprecated
+- public final long sslCtxPointer() {
+- Lock readerLock = ctxLock.readLock();
+- readerLock.lock();
- try {
-- return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length);
+- return SSLContext.getSslCtx(ctx);
- } finally {
-- resetSingleSrcBuffer();
+- readerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst)
throws SSLException {
+- /**
+- * Set the {@link OpenSslPrivateKeyMethod} to use. This allows to offload
private-key operations
+- * if needed.
+- *
+- * This method is currently only supported when {@code BoringSSL} is used.
+- *
+- * @param method method to use.
+- */
+- @UnstableApi
+- public final void setPrivateKeyMethod(OpenSslPrivateKeyMethod method) {
+- ObjectUtil.checkNotNull(method, "method");
+- Lock writerLock = ctxLock.writeLock();
+- writerLock.lock();
- try {
-- return wrap(singleSrcBuffer(src), dst);
+- SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap,
method));
- } finally {
-- resetSingleSrcBuffer();
+- writerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst)
throws SSLException {
+- public final void setUseTasks(boolean useTasks) {
+- Lock writerLock = ctxLock.writeLock();
+- writerLock.lock();
- try {
-- return unwrap(singleSrcBuffer(src), singleDstBuffer(dst));
+- SSLContext.setUseTasks(ctx, useTasks);
- } finally {
-- resetSingleSrcBuffer();
-- resetSingleDstBuffer();
+- writerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts)
throws SSLException {
+- // IMPORTANT: This method must only be called from either the constructor or the
finalizer as a user MUST never
+- // get access to an OpenSslSessionContext after this method was called to
prevent the user from
+- // producing a segfault.
+- private void destroy() {
+- Lock writerLock = ctxLock.writeLock();
+- writerLock.lock();
- try {
-- return unwrap(singleSrcBuffer(src), dsts);
-- } finally {
-- resetSingleSrcBuffer();
-- }
-- }
--
-- @Override
-- public final Runnable getDelegatedTask() {
-- // Currently, we do not delegate SSL computation tasks
-- // TODO: in the future, possibly create tasks to do encrypt / decrypt async
--
-- return null;
-- }
--
-- @Override
-- public final synchronized void closeInbound() throws SSLException {
-- if (isInboundDone) {
-- return;
-- }
--
-- isInboundDone = true;
+- if (ctx != 0) {
+- if (enableOcsp) {
+- SSLContext.disableOcsp(ctx);
+- }
-
-- if (isOutboundDone()) {
-- // Only call shutdown if there is no outbound data pending.
-- // See
https://github.com/netty/netty/issues/6167
-- shutdown();
-- }
+- SSLContext.free(ctx);
+- ctx = 0;
-
-- if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown)
{
-- throw new SSLException(
-- "Inbound closed before receiving peer's close_notify:
possible truncation attack?");
+- OpenSslSessionContext context = sessionContext();
+- if (context != null) {
+- context.destroy();
+- }
+- }
+- } finally {
+- writerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized boolean isInboundDone() {
-- return isInboundDone;
+- protected static X509Certificate[] certificates(byte[][] chain) {
+- X509Certificate[] peerCerts = new X509Certificate[chain.length];
+- for (int i = 0; i < peerCerts.length; i++) {
+- peerCerts[i] = new OpenSslX509Certificate(chain[i]);
+- }
+- return peerCerts;
- }
-
-- @Override
-- public final synchronized void closeOutbound() {
-- if (outboundClosed) {
-- return;
+- protected static X509TrustManager chooseTrustManager(TrustManager[] managers) {
+- for (TrustManager m : managers) {
+- if (m instanceof X509TrustManager) {
+- if (PlatformDependent.javaVersion() >= 7) {
+- return
OpenSslX509TrustManagerWrapper.wrapIfNeeded((X509TrustManager) m);
+- }
+- return (X509TrustManager) m;
+- }
- }
+- throw new IllegalStateException("no X509TrustManager found");
+- }
-
-- outboundClosed = true;
--
-- if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) {
-- int mode = SSL.getShutdown(ssl);
-- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) {
-- doSSLShutdown();
+- protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) {
+- for (KeyManager km : kms) {
+- if (km instanceof X509KeyManager) {
+- return (X509KeyManager) km;
- }
-- } else {
-- // engine closing before initial handshake
-- shutdown();
- }
+- throw new IllegalStateException("no X509KeyManager found");
- }
-
- /**
-- * Attempt to call {@link SSL#shutdownSSL(long)}.
-- * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not
attempted or returned an error.
+- * Translate a {@link ApplicationProtocolConfig} object to a
+- * {@link OpenSslApplicationProtocolNegotiator} object.
+- *
+- * @param config The configuration which defines the translation
+- * @return The results of the translation
- */
-- private boolean doSSLShutdown() {
-- if (SSL.isInInit(ssl) != 0) {
-- // Only try to call SSL_shutdown if we are not in the init state anymore.
-- // Otherwise we will see 'error:140E0197:SSL
routines:SSL_shutdown:shutdown while in init' in our logs.
-- //
-- // See also
http://hg.nginx.org/nginx/rev/062c189fee20
-- return false;
+- @SuppressWarnings("deprecation")
+- static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig
config) {
+- if (config == null) {
+- return NONE_PROTOCOL_NEGOTIATOR;
- }
-- int err = SSL.shutdownSSL(ssl);
-- if (err < 0) {
-- int sslErr = SSL.getError(ssl, err);
-- if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) {
-- if (logger.isDebugEnabled()) {
-- logger.debug("SSL_shutdown failed: OpenSSL error: {}",
SSL.getLastError());
+-
+- switch (config.protocol()) {
+- case NONE:
+- return NONE_PROTOCOL_NEGOTIATOR;
+- case ALPN:
+- case NPN:
+- case NPN_AND_ALPN:
+- switch (config.selectedListenerFailureBehavior()) {
+- case CHOOSE_MY_LAST_PROTOCOL:
+- case ACCEPT:
+- switch (config.selectorFailureBehavior()) {
+- case CHOOSE_MY_LAST_PROTOCOL:
+- case NO_ADVERTISE:
+- return new OpenSslDefaultApplicationProtocolNegotiator(
+- config);
+- default:
+- throw new UnsupportedOperationException(
+- new StringBuilder("OpenSSL provider does
not support ")
+-
.append(config.selectorFailureBehavior())
+- .append("
behavior").toString());
+- }
+- default:
+- throw new UnsupportedOperationException(
+- new StringBuilder("OpenSSL provider does not
support ")
+-
.append(config.selectedListenerFailureBehavior())
+- .append(" behavior").toString());
- }
-- // There was an internal error -- shutdown
-- shutdown();
-- return false;
-- }
-- SSL.clearError();
+- default:
+- throw new Error();
- }
-- return true;
- }
-
-- @Override
-- public final synchronized boolean isOutboundDone() {
-- // Check if there is anything left in the outbound buffer.
-- // We need to ensure we only call SSL.pendingWrittenBytesInBIO(...) if the
engine was not destroyed yet.
-- return outboundClosed && (networkBIO == 0 ||
SSL.bioLengthNonApplication(networkBIO) == 0);
+- @SuppressJava6Requirement(reason = "Guarded by java version check")
+- static boolean useExtendedTrustManager(X509TrustManager trustManager) {
+- return PlatformDependent.javaVersion() >= 7 && trustManager
instanceof X509ExtendedTrustManager;
- }
-
- @Override
-- public final String[] getSupportedCipherSuites() {
-- return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new
String[OpenSsl.AVAILABLE_CIPHER_SUITES.size()]);
+- public final int refCnt() {
+- return refCnt.refCnt();
- }
-
- @Override
-- public final String[] getEnabledCipherSuites() {
-- final String[] enabled;
-- synchronized (this) {
-- if (!isDestroyed()) {
-- enabled = SSL.getCiphers(ssl);
-- } else {
-- return EmptyArrays.EMPTY_STRINGS;
-- }
-- }
-- if (enabled == null) {
-- return EmptyArrays.EMPTY_STRINGS;
-- } else {
-- synchronized (this) {
-- for (int i = 0; i < enabled.length; i++) {
-- String mapped = toJavaCipherSuite(enabled[i]);
-- if (mapped != null) {
-- enabled[i] = mapped;
-- }
-- }
-- }
-- return enabled;
-- }
+- public final ReferenceCounted retain() {
+- refCnt.retain();
+- return this;
- }
-
- @Override
-- public final void setEnabledCipherSuites(String[] cipherSuites) {
-- checkNotNull(cipherSuites, "cipherSuites");
--
-- final StringBuilder buf = new StringBuilder();
-- for (String c: cipherSuites) {
-- if (c == null) {
-- break;
-- }
--
-- String converted = CipherSuiteConverter.toOpenSsl(c);
-- if (converted == null) {
-- converted = c;
-- }
--
-- if (!OpenSsl.isCipherSuiteAvailable(converted)) {
-- throw new IllegalArgumentException("unsupported cipher suite:
" + c + '(' + converted + ')');
-- }
--
-- buf.append(converted);
-- buf.append(':');
-- }
--
-- if (buf.length() == 0) {
-- throw new IllegalArgumentException("empty cipher suites");
-- }
-- buf.setLength(buf.length() - 1);
--
-- final String cipherSuiteSpec = buf.toString();
--
-- synchronized (this) {
-- if (!isDestroyed()) {
-- try {
-- SSL.setCipherSuites(ssl, cipherSuiteSpec);
-- } catch (Exception e) {
-- throw new IllegalStateException("failed to enable cipher
suites: " + cipherSuiteSpec, e);
-- }
-- } else {
-- throw new IllegalStateException("failed to enable cipher suites:
" + cipherSuiteSpec);
-- }
-- }
+- public final ReferenceCounted retain(int increment) {
+- refCnt.retain(increment);
+- return this;
- }
-
- @Override
-- public final String[] getSupportedProtocols() {
-- return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new
String[OpenSsl.SUPPORTED_PROTOCOLS_SET.size()]);
+- public final ReferenceCounted touch() {
+- refCnt.touch();
+- return this;
- }
-
- @Override
-- public final String[] getEnabledProtocols() {
-- List<String> enabled = new ArrayList<String>(6);
-- // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is
always enabled
-- enabled.add(OpenSsl.PROTOCOL_SSL_V2_HELLO);
--
-- int opts;
-- synchronized (this) {
-- if (!isDestroyed()) {
-- opts = SSL.getOptions(ssl);
-- } else {
-- return enabled.toArray(new String[1]);
-- }
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, OpenSsl.PROTOCOL_TLS_V1)) {
-- enabled.add(OpenSsl.PROTOCOL_TLS_V1);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, OpenSsl.PROTOCOL_TLS_V1_1))
{
-- enabled.add(OpenSsl.PROTOCOL_TLS_V1_1);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, OpenSsl.PROTOCOL_TLS_V1_2))
{
-- enabled.add(OpenSsl.PROTOCOL_TLS_V1_2);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, OpenSsl.PROTOCOL_SSL_V2)) {
-- enabled.add(OpenSsl.PROTOCOL_SSL_V2);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, OpenSsl.PROTOCOL_SSL_V3)) {
-- enabled.add(OpenSsl.PROTOCOL_SSL_V3);
-- }
-- return enabled.toArray(new String[enabled.size()]);
+- public final ReferenceCounted touch(Object hint) {
+- refCnt.touch(hint);
+- return this;
- }
-
-- private static boolean isProtocolEnabled(int opts, int disableMask, String
protocolString) {
-- // We also need to check if the actual protocolString is supported as depending
on the openssl API
-- // implementations it may use a disableMask of 0 (BoringSSL is doing this for
example).
-- return (opts & disableMask) == 0 &&
OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString);
+- @Override
+- public final boolean release() {
+- return refCnt.release();
- }
-
- @Override
-- public final void setEnabledProtocols(String[] protocols) {
-- if (protocols == null) {
-- // This is correct from the API docs
-- throw new IllegalArgumentException();
+- public final boolean release(int decrement) {
+- return refCnt.release(decrement);
+- }
+-
+- abstract static class AbstractCertificateVerifier extends CertificateVerifier {
+- private final OpenSslEngineMap engineMap;
+-
+- AbstractCertificateVerifier(OpenSslEngineMap engineMap) {
+- this.engineMap = engineMap;
- }
-- boolean sslv2 = false;
-- boolean sslv3 = false;
-- boolean tlsv1 = false;
-- boolean tlsv1_1 = false;
-- boolean tlsv1_2 = false;
-- for (String p: protocols) {
-- if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) {
-- throw new IllegalArgumentException("Protocol " + p + " is
not supported.");
-- }
-- if (p.equals(OpenSsl.PROTOCOL_SSL_V2)) {
-- sslv2 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_SSL_V3)) {
-- sslv3 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1)) {
-- tlsv1 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_1)) {
-- tlsv1_1 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_2)) {
-- tlsv1_2 = true;
+-
+- @Override
+- public final int verify(long ssl, byte[][] chain, String auth) {
+- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine == null) {
+- // May be null if it was destroyed in the meantime.
+- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
- }
-- }
-- synchronized (this) {
-- if (!isDestroyed()) {
-- // Clear out options which disable protocols
-- SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 |
SSL.SSL_OP_NO_TLSv1 |
-- SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2);
+- X509Certificate[] peerCerts = certificates(chain);
+- try {
+- verify(engine, peerCerts, auth);
+- return CertificateVerifier.X509_V_OK;
+- } catch (Throwable cause) {
+- logger.debug("verification of certificate failed", cause);
+- engine.initHandshakeException(cause);
-
-- int opts = 0;
-- if (!sslv2) {
-- opts |= SSL.SSL_OP_NO_SSLv2;
-- }
-- if (!sslv3) {
-- opts |= SSL.SSL_OP_NO_SSLv3;
+- // Try to extract the correct error code that should be used.
+- if (cause instanceof OpenSslCertificateException) {
+- // This will never return a negative error code as its validated
when constructing the
+- // OpenSslCertificateException.
+- return ((OpenSslCertificateException) cause).errorCode();
- }
-- if (!tlsv1) {
-- opts |= SSL.SSL_OP_NO_TLSv1;
+- if (cause instanceof CertificateExpiredException) {
+- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
- }
-- if (!tlsv1_1) {
-- opts |= SSL.SSL_OP_NO_TLSv1_1;
+- if (cause instanceof CertificateNotYetValidException) {
+- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
- }
-- if (!tlsv1_2) {
-- opts |= SSL.SSL_OP_NO_TLSv1_2;
+- if (PlatformDependent.javaVersion() >= 7) {
+- return translateToError(cause);
- }
-
-- // Disable protocols we do not want
-- SSL.setOptions(ssl, opts);
-- } else {
-- throw new IllegalStateException("failed to enable protocols: "
+ Arrays.asList(protocols));
+- // Could not detect a specific error code to use, so fallback to a
default code.
+- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
- }
- }
-- }
--
-- @Override
-- public final SSLSession getSession() {
-- return session;
-- }
--
-- @Override
-- public final synchronized void beginHandshake() throws SSLException {
-- switch (handshakeState) {
-- case STARTED_IMPLICITLY:
-- checkEngineClosed(BEGIN_HANDSHAKE_ENGINE_CLOSED);
-
-- // A user did not start handshake by calling this method by
him/herself,
-- // but handshake has been started already by wrap() or unwrap()
implicitly.
-- // Because it's the user's first time to call this method, it is
unfair to
-- // raise an exception. From the user's standpoint, he or she never
asked
-- // for renegotiation.
+- @SuppressJava6Requirement(reason = "Usage guarded by java version
check")
+- private static int translateToError(Throwable cause) {
+- if (cause instanceof CertificateRevokedException) {
+- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
+- }
-
-- handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this
method is invoked by the user,
-- // we should raise an exception.
-- break;
-- case STARTED_EXPLICITLY:
-- // Nothing to do as the handshake is not done yet.
-- break;
-- case FINISHED:
-- if (clientMode) {
-- // Only supported for server mode at the moment.
-- throw RENEGOTIATION_UNSUPPORTED;
-- }
-- // For renegotiate on the server side we need to issue the following
command sequence with openssl:
-- //
-- // SSL_renegotiate(ssl)
-- // SSL_do_handshake(ssl)
-- // ssl->state = SSL_ST_ACCEPT
-- // SSL_do_handshake(ssl)
-- //
-- // Because of this we fall-through to call handshake() after setting the
state, as this will also take
-- // care of updating the internal OpenSslSession object.
-- //
-- // See also:
-- //
https://github.com/apache/httpd/blob/2.4.16/modules/ssl/ssl_engine_kernel...
-- //
http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html
-- int status;
-- if ((status = SSL.renegotiate(ssl)) != 1 || (status =
SSL.doHandshake(ssl)) != 1) {
-- int err = SSL.getError(ssl, status);
-- if (err == SSL.SSL_ERROR_WANT_READ || err ==
SSL.SSL_ERROR_WANT_WRITE) {
-- // If the internal SSL buffer is small it is possible that
doHandshake may "fail" because
-- // there is not enough room to write, so we should wait until
the renegotiation has been.
-- renegotiationPending = true;
-- handshakeState = HandshakeState.STARTED_EXPLICITLY;
-- lastAccessed = System.currentTimeMillis();
-- return;
-- } else {
-- throw shutdownWithError("renegotiation failed");
+- // The X509TrustManagerImpl uses a Validator which wraps a
CertPathValidatorException into
+- // an CertificateException. So we need to handle the wrapped
CertPathValidatorException to be
+- // able to send the correct alert.
+- Throwable wrapped = cause.getCause();
+- while (wrapped != null) {
+- if (wrapped instanceof CertPathValidatorException) {
+- CertPathValidatorException ex = (CertPathValidatorException)
wrapped;
+- CertPathValidatorException.Reason reason = ex.getReason();
+- if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
+- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
+- }
+- if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID)
{
+- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
+- }
+- if (reason == CertPathValidatorException.BasicReason.REVOKED) {
+- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
- }
- }
+- wrapped = wrapped.getCause();
+- }
+- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
+- }
-
-- SSL.setState(ssl, SSL.SSL_ST_ACCEPT);
+- abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[]
peerCerts,
+- String auth) throws Exception;
+- }
-
-- lastAccessed = System.currentTimeMillis();
+- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
+- private final Map<Long, ReferenceCountedOpenSslEngine> engines =
PlatformDependent.newConcurrentHashMap();
-
-- // fall-through
-- case NOT_STARTED:
-- handshakeState = HandshakeState.STARTED_EXPLICITLY;
-- handshake();
-- break;
-- default:
-- throw new Error();
+- @Override
+- public ReferenceCountedOpenSslEngine remove(long ssl) {
+- return engines.remove(ssl);
- }
-- }
-
-- private void checkEngineClosed(SSLException cause) throws SSLException {
-- if (isDestroyed()) {
-- throw cause;
+- @Override
+- public void add(ReferenceCountedOpenSslEngine engine) {
+- engines.put(engine.sslPointer(), engine);
- }
-- }
-
-- private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingStatus) {
-- // Depending on if there is something left in the BIO we need to WRAP or UNWRAP
-- return pendingStatus > 0 ? NEED_WRAP : NEED_UNWRAP;
+- @Override
+- public ReferenceCountedOpenSslEngine get(long ssl) {
+- return engines.get(ssl);
+- }
- }
-
-- private static boolean isEmpty(Object[] arr) {
-- return arr == null || arr.length == 0;
-- }
+- static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key,
String keyPassword)
+- throws SSLException {
+- /* Load the certificate file and private key. */
+- long keyBio = 0;
+- long keyCertChainBio = 0;
+- long keyCertChainBio2 = 0;
+- PemEncoded encoded = null;
+- try {
+- // Only encode one time
+- encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true,
keyCertChain);
+- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
+- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-
-- private static boolean isEmpty(byte[] cert) {
-- return cert == null || cert.length == 0;
-- }
+- if (key != null) {
+- keyBio = toBIO(ByteBufAllocator.DEFAULT, key);
+- }
-
-- private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
-- if (handshakeState == HandshakeState.FINISHED) {
-- return FINISHED;
+- SSLContext.setCertificateBio(
+- ctx, keyCertChainBio, keyBio,
+- keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword);
+- // We may have more then one cert in the chain so add all of them now.
+- SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true);
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate and key", e);
+- } finally {
+- freeBio(keyBio);
+- freeBio(keyCertChainBio);
+- freeBio(keyCertChainBio2);
+- if (encoded != null) {
+- encoded.release();
+- }
- }
-- checkEngineClosed(HANDSHAKE_ENGINE_CLOSED);
+- }
-
-- // Check if we have a pending handshakeException and if so see if we need to
consume all pending data from the
-- // BIO first or can just shutdown and throw it now.
-- // This is needed so we ensure close_notify etc is correctly send to the remote
peer.
-- // See
https://github.com/netty/netty/issues/3900
-- SSLHandshakeException exception = handshakeException;
-- if (exception != null) {
-- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
-- // There is something pending, we need to consume it first via a WRAP so
we don't loose anything.
-- return NEED_WRAP;
-- }
-- // No more data left to send to the remote peer, so null out the exception
field, shutdown and throw
-- // the exception.
-- handshakeException = null;
-- shutdown();
-- throw exception;
+- static void freeBio(long bio) {
+- if (bio != 0) {
+- SSL.freeBIO(bio);
- }
+- }
-
-- // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the
AbstractCertificateVerifier.
-- engineMap.add(this);
-- if (lastAccessed == -1) {
-- lastAccessed = System.currentTimeMillis();
+- /**
+- * Return the pointer to a <a
href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html"...
BIO</a>
+- * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of
the {@code key}.
+- */
+- static long toBIO(ByteBufAllocator allocator, PrivateKey key) throws Exception {
+- if (key == null) {
+- return 0;
- }
-
-- if (!certificateSet && keyMaterialManager != null) {
-- certificateSet = true;
-- keyMaterialManager.setKeyMaterial(this);
+- PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key);
+- try {
+- return toBIO(allocator, pem.retain());
+- } finally {
+- pem.release();
- }
+- }
-
-- int code = SSL.doHandshake(ssl);
-- if (code <= 0) {
-- // Check if we have a pending exception that was created during the
handshake and if so throw it after
-- // shutdown the connection.
-- if (handshakeException != null) {
-- exception = handshakeException;
-- handshakeException = null;
-- shutdown();
-- throw exception;
-- }
+- /**
+- * Return the pointer to a <a
href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html"...
BIO</a>
+- * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the
content of the {@code certChain}.
+- */
+- static long toBIO(ByteBufAllocator allocator, X509Certificate... certChain) throws
Exception {
+- if (certChain == null) {
+- return 0;
+- }
-
-- int sslError = SSL.getError(ssl, code);
-- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError ==
SSL.SSL_ERROR_WANT_WRITE) {
-- return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
-- } else {
-- // Everything else is considered as error
-- throw shutdownWithError("SSL_do_handshake");
-- }
+- if (certChain.length == 0) {
+- throw new IllegalArgumentException("certChain can't be
empty");
- }
-- // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means
the handshake was finished.
-- session.handshakeFinished();
-- engineMap.remove(ssl);
-- return FINISHED;
-- }
-
-- private SSLEngineResult.HandshakeStatus
mayFinishHandshake(SSLEngineResult.HandshakeStatus status)
-- throws SSLException {
-- if (status == NOT_HANDSHAKING && handshakeState !=
HandshakeState.FINISHED) {
-- // If the status was NOT_HANDSHAKING and we not finished the handshake we
need to call
-- // SSL_do_handshake() again
-- return handshake();
+- PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain);
+- try {
+- return toBIO(allocator, pem.retain());
+- } finally {
+- pem.release();
- }
-- return status;
- }
-
-- @Override
-- public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
-- // Check if we are in the initial handshake phase or shutdown phase
-- return needPendingStatus() ?
pendingStatus(SSL.bioLengthNonApplication(networkBIO)) : NOT_HANDSHAKING;
-- }
+- static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception {
+- try {
+- // We can turn direct buffers straight into BIOs. No need to
+- // make a yet another copy.
+- ByteBuf content = pem.content();
-
-- private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
-- // Check if we are in the initial handshake phase or shutdown phase
-- return needPendingStatus() ? pendingStatus(pending) : NOT_HANDSHAKING;
+- if (content.isDirect()) {
+- return newBIO(content.retainedSlice());
+- }
+-
+- ByteBuf buffer = allocator.directBuffer(content.readableBytes());
+- try {
+- buffer.writeBytes(content, content.readerIndex(),
content.readableBytes());
+- return newBIO(buffer.retainedSlice());
+- } finally {
+- try {
+- // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey)
we
+- // need to zero out the bytes of the copy before we're releasing
it.
+- if (pem.isSensitive()) {
+- SslUtils.zeroout(buffer);
+- }
+- } finally {
+- buffer.release();
+- }
+- }
+- } finally {
+- pem.release();
+- }
- }
-
-- private boolean needPendingStatus() {
-- return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()
-- && (handshakeState != HandshakeState.FINISHED || isInboundDone()
|| isOutboundDone());
+- private static long newBIO(ByteBuf buffer) throws Exception {
+- try {
+- long bio = SSL.newMemBIO();
+- int readable = buffer.readableBytes();
+- if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(),
readable) != readable) {
+- SSL.freeBIO(bio);
+- throw new IllegalStateException("Could not write data to memory
BIO");
+- }
+- return bio;
+- } finally {
+- buffer.release();
+- }
- }
-
- /**
-- * Converts the specified OpenSSL cipher suite to the Java cipher suite.
+- * Returns the {@link OpenSslKeyMaterialProvider} that should be used for OpenSSL.
Depending on the given
+- * {@link KeyManagerFactory} this may cache the {@link OpenSslKeyMaterial} for
better performance if it can
+- * ensure that the same material is always returned for the same alias.
- */
-- private String toJavaCipherSuite(String openSslCipherSuite) {
-- if (openSslCipherSuite == null) {
-- return null;
+- static OpenSslKeyMaterialProvider providerFor(KeyManagerFactory factory, String
password) {
+- if (factory instanceof OpenSslX509KeyManagerFactory) {
+- return ((OpenSslX509KeyManagerFactory) factory).newProvider();
- }
-
-- String prefix = toJavaCipherSuitePrefix(SSL.getVersion(ssl));
-- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix);
+- if (factory instanceof OpenSslCachingX509KeyManagerFactory) {
+- // The user explicit used OpenSslCachingX509KeyManagerFactory which signals
us that its fine to cache.
+- return ((OpenSslCachingX509KeyManagerFactory)
factory).newProvider(password);
+- }
+- // We can not be sure if the material may change at runtime so we will not cache
it.
+- return new
OpenSslKeyMaterialProvider(chooseX509KeyManager(factory.getKeyManagers()), password);
- }
-
-- /**
-- * Converts the protocol version string returned by {@link SSL#getVersion(long)} to
protocol family string.
-- */
-- private static String toJavaCipherSuitePrefix(String protocolVersion) {
-- final char c;
-- if (protocolVersion == null || protocolVersion.isEmpty()) {
-- c = 0;
-- } else {
-- c = protocolVersion.charAt(0);
+- private static final class PrivateKeyMethod implements SSLPrivateKeyMethod {
+-
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslPrivateKeyMethod keyMethod;
+- PrivateKeyMethod(OpenSslEngineMap engineMap, OpenSslPrivateKeyMethod keyMethod)
{
+- this.engineMap = engineMap;
+- this.keyMethod = keyMethod;
- }
-
-- switch (c) {
-- case 'T':
-- return "TLS";
-- case 'S':
-- return "SSL";
-- default:
-- return "UNKNOWN";
+- private ReferenceCountedOpenSslEngine retrieveEngine(long ssl) throws
SSLException {
+- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine == null) {
+- throw new SSLException("Could not find a " +
+- StringUtil.simpleClassName(ReferenceCountedOpenSslEngine.class)
+ " for sslPointer " + ssl);
+- }
+- return engine;
- }
-- }
-
-- @Override
-- public final void setUseClientMode(boolean clientMode) {
-- if (clientMode != this.clientMode) {
-- throw new UnsupportedOperationException();
+- @Override
+- public byte[] sign(long ssl, int signatureAlgorithm, byte[] digest) throws
Exception {
+- ReferenceCountedOpenSslEngine engine = retrieveEngine(ssl);
+- try {
+- return verifyResult(keyMethod.sign(engine, signatureAlgorithm,
digest));
+- } catch (Exception e) {
+- engine.initHandshakeException(e);
+- throw e;
+- }
- }
-- }
-
-- @Override
-- public final boolean getUseClientMode() {
-- return clientMode;
-- }
+- @Override
+- public byte[] decrypt(long ssl, byte[] input) throws Exception {
+- ReferenceCountedOpenSslEngine engine = retrieveEngine(ssl);
+- try {
+- return verifyResult(keyMethod.decrypt(engine, input));
+- } catch (Exception e) {
+- engine.initHandshakeException(e);
+- throw e;
+- }
+- }
-
-- @Override
-- public final void setNeedClientAuth(boolean b) {
-- setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE);
+- private static byte[] verifyResult(byte[] result) throws SignatureException {
+- if (result == null) {
+- throw new SignatureException();
+- }
+- return result;
+- }
- }
+-}
+diff --git
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
+deleted file mode 100644
+index b404a1076b..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
++++ /dev/null
+@@ -1,2467 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- @Override
-- public final boolean getNeedClientAuth() {
-- return clientAuth == ClientAuth.REQUIRE;
-- }
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.internal.tcnative.Buffer;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.CharsetUtil;
+-import io.netty.util.ReferenceCounted;
+-import io.netty.util.ResourceLeakDetector;
+-import io.netty.util.ResourceLeakDetectorFactory;
+-import io.netty.util.ResourceLeakTracker;
+-import io.netty.util.internal.EmptyArrays;
+-import io.netty.util.internal.ObjectUtil;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.StringUtil;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.ThrowableUtil;
+-import io.netty.util.internal.UnstableApi;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-- @Override
-- public final void setWantClientAuth(boolean b) {
-- setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE);
-- }
+-import java.nio.ByteBuffer;
+-import java.nio.ReadOnlyBufferException;
+-import java.security.Principal;
+-import java.security.cert.Certificate;
+-import java.util.ArrayList;
+-import java.util.Arrays;
+-import java.util.Collection;
+-import java.util.Collections;
+-import java.util.HashMap;
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-import java.util.Map;
+-import java.util.Set;
+-import java.util.concurrent.locks.Lock;
-
-- @Override
-- public final boolean getWantClientAuth() {
-- return clientAuth == ClientAuth.OPTIONAL;
-- }
+-import javax.crypto.spec.SecretKeySpec;
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLEngineResult;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.SSLParameters;
+-import javax.net.ssl.SSLPeerUnverifiedException;
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionBindingEvent;
+-import javax.net.ssl.SSLSessionBindingListener;
+-import javax.net.ssl.SSLSessionContext;
+-import javax.security.cert.X509Certificate;
-
-- /**
-- * See <a
href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html&...
and
-- * {@link SSL#setVerify(long, int, int)}.
-- */
-- @UnstableApi
-- public final synchronized void setVerify(int verifyMode, int depth) {
-- SSL.setVerify(ssl, verifyMode, depth);
-- }
+-import static io.netty.handler.ssl.OpenSsl.memoryAddress;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V2;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V2_HELLO;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V3;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_1;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_2;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_3;
+-import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static java.lang.Integer.MAX_VALUE;
+-import static java.lang.Math.min;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_TASK;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
+-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
+-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
+-import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
+-import static javax.net.ssl.SSLEngineResult.Status.OK;
-
-- private void setClientAuth(ClientAuth mode) {
-- if (clientMode) {
-- return;
-- }
-- synchronized (this) {
-- if (clientAuth == mode) {
-- // No need to issue any JNI calls if the mode is the same
-- return;
-- }
-- switch (mode) {
-- case NONE:
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE,
ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-- break;
-- case REQUIRE:
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED,
ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-- break;
-- case OPTIONAL:
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL,
ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-- break;
-- default:
-- throw new Error(mode.toString());
-- }
-- clientAuth = mode;
-- }
-- }
+-/**
+- * Implements a {@link SSLEngine} using
+- * <a
href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE&quo... BIO
abstractions</a>.
+- * <p>Instances of this class must be {@link #release() released} or else native
memory will leak!
+- *
+- * <p>Instances of this class <strong>must</strong> be released before
the {@link ReferenceCountedOpenSslContext}
+- * the instance depends upon are released. Otherwise if any method of this class is
called which uses the
+- * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash.
+- */
+-public class ReferenceCountedOpenSslEngine extends SSLEngine implements
ReferenceCounted, ApplicationProtocolAccessor {
-
-- @Override
-- public final void setEnableSessionCreation(boolean b) {
-- if (b) {
-- throw new UnsupportedOperationException();
-- }
-- }
+- private static final InternalLogger logger =
InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class);
-
-- @Override
-- public final boolean getEnableSessionCreation() {
-- return false;
-- }
+- private static final ResourceLeakDetector<ReferenceCountedOpenSslEngine>
leakDetector =
+-
ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class);
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2 = 0;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3 = 1;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1 = 2;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1 = 3;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2 = 4;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3 = 5;
+- private static final int[] OPENSSL_OP_NO_PROTOCOLS = {
+- SSL.SSL_OP_NO_SSLv2,
+- SSL.SSL_OP_NO_SSLv3,
+- SSL.SSL_OP_NO_TLSv1,
+- SSL.SSL_OP_NO_TLSv1_1,
+- SSL.SSL_OP_NO_TLSv1_2,
+- SSL.SSL_OP_NO_TLSv1_3
+- };
-
-- @Override
-- public final synchronized SSLParameters getSSLParameters() {
-- SSLParameters sslParameters = super.getSSLParameters();
+- /**
+- * Depends upon tcnative ... only use if tcnative is available!
+- */
+- static final int MAX_PLAINTEXT_LENGTH = SSL.SSL_MAX_PLAINTEXT_LENGTH;
+- /**
+- * Depends upon tcnative ... only use if tcnative is available!
+- */
+- private static final int MAX_RECORD_SIZE = SSL.SSL_MAX_RECORD_LENGTH;
-
-- int version = PlatformDependent.javaVersion();
-- if (version >= 7) {
--
sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
-- Java7SslParametersUtils.setAlgorithmConstraints(sslParameters,
algorithmConstraints);
-- if (version >= 8) {
-- if (sniHostNames != null) {
-- Java8SslUtils.setSniHostNames(sslParameters, sniHostNames);
-- }
-- if (!isDestroyed()) {
-- Java8SslUtils.setUseCipherSuitesOrder(
-- sslParameters, (SSL.getOptions(ssl) &
SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0);
-- }
+- private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK,
NEED_UNWRAP, 0, 0);
+- private static final SSLEngineResult NEED_UNWRAP_CLOSED = new
SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
+- private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK,
NEED_WRAP, 0, 0);
+- private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED,
NEED_WRAP, 0, 0);
+- private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new
SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
-
-- Java8SslUtils.setSNIMatchers(sslParameters, matchers);
-- }
-- }
-- return sslParameters;
+- // OpenSSL state
+- private long ssl;
+- private long networkBIO;
+-
+- private enum HandshakeState {
+- /**
+- * Not started yet.
+- */
+- NOT_STARTED,
+- /**
+- * Started via unwrap/wrap.
+- */
+- STARTED_IMPLICITLY,
+- /**
+- * Started via {@link #beginHandshake()}.
+- */
+- STARTED_EXPLICITLY,
+- /**
+- * Handshake is finished.
+- */
+- FINISHED
- }
-
-- @Override
-- public final synchronized void setSSLParameters(SSLParameters sslParameters) {
-- int version = PlatformDependent.javaVersion();
-- if (version >= 7) {
-- if (sslParameters.getAlgorithmConstraints() != null) {
-- throw new IllegalArgumentException("AlgorithmConstraints are not
supported.");
-- }
+- private HandshakeState handshakeState = HandshakeState.NOT_STARTED;
+- private boolean receivedShutdown;
+- private volatile boolean destroyed;
+- private volatile String applicationProtocol;
+- private volatile boolean needTask;
-
-- if (version >= 8) {
-- if (!isDestroyed()) {
-- if (clientMode) {
-- final List<String> sniHostNames =
Java8SslUtils.getSniHostNames(sslParameters);
-- for (String name: sniHostNames) {
-- SSL.setTlsExtHostName(ssl, name);
-- }
-- this.sniHostNames = sniHostNames;
-- }
-- if (Java8SslUtils.getUseCipherSuitesOrder(sslParameters)) {
-- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
-- } else {
-- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
-- }
-- }
-- matchers = sslParameters.getSNIMatchers();
+- // Reference Counting
+- private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak;
+- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
+- @Override
+- public ReferenceCounted touch(Object hint) {
+- if (leak != null) {
+- leak.record(hint);
- }
-
-- final String endPointIdentificationAlgorithm =
sslParameters.getEndpointIdentificationAlgorithm();
-- final boolean endPointVerificationEnabled = endPointIdentificationAlgorithm
!= null &&
-- !endPointIdentificationAlgorithm.isEmpty();
-- SSL.setHostNameValidation(ssl, DEFAULT_HOSTNAME_VALIDATION_FLAGS,
-- endPointVerificationEnabled ? getPeerHost() : null);
-- // If the user asks for hostname verification we must ensure we verify the
peer.
-- // If the user disables hostname verification we leave it up to the user to
change the mode manually.
-- if (clientMode && endPointVerificationEnabled) {
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1);
-- }
+- return ReferenceCountedOpenSslEngine.this;
+- }
-
-- this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm;
-- algorithmConstraints = sslParameters.getAlgorithmConstraints();
+- @Override
+- protected void deallocate() {
+- shutdown();
+- if (leak != null) {
+- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this);
+- assert closed;
+- }
+- parentContext.release();
- }
-- super.setSSLParameters(sslParameters);
-- }
+- };
-
-- private boolean isDestroyed() {
-- return destroyed != 0;
-- }
+- private volatile ClientAuth clientAuth = ClientAuth.NONE;
+- private volatile Certificate[] localCertificateChain;
-
-- static int calculateOutNetBufSize(int pendingBytes, int numComponents) {
-- return (int) min(MAX_ENCRYPTED_PACKET_LENGTH,
-- pendingBytes + (long) MAX_TLS_RECORD_OVERHEAD_LENGTH * numComponents);
-- }
+- // Updated once a new handshake is started and so the SSLSession reused.
+- private volatile long lastAccessed = -1;
-
-- final boolean checkSniHostnameMatch(String hostname) {
-- return Java8SslUtils.checkSniHostnameMatch(matchers, hostname);
-- }
+- private String endPointIdentificationAlgorithm;
+- // Store as object as AlgorithmConstraints only exists since java 7.
+- private Object algorithmConstraints;
+- private List<String> sniHostNames;
-
-- private final class OpenSslSession implements SSLSession,
ApplicationProtocolAccessor {
-- private final OpenSslSessionContext sessionContext;
+- // Mark as volatile as accessed by checkSniHostnameMatch(...) and also not specify
the SNIMatcher type to allow us
+- // using it with java7.
+- private volatile Collection<?> matchers;
-
-- // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished()
may be triggered by any
-- // thread.
-- private X509Certificate[] x509PeerCerts;
-- private Certificate[] peerCerts;
-- private String protocol;
-- private String applicationProtocol;
-- private String cipher;
-- private byte[] id;
-- private long creationTime;
+- // SSL Engine status variables
+- private boolean isInboundDone;
+- private boolean outboundClosed;
-
-- // lazy init for memory reasons
-- private Map<String, Object> values;
+- final boolean jdkCompatibilityMode;
+- private final boolean clientMode;
+- final ByteBufAllocator alloc;
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslApplicationProtocolNegotiator apn;
+- private final ReferenceCountedOpenSslContext parentContext;
+- private final OpenSslSession session;
+- private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1];
+- private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1];
+- private final boolean enableOcsp;
+- private int maxWrapOverhead;
+- private int maxWrapBufferSize;
+- private Throwable pendingException;
-
-- OpenSslSession(OpenSslSessionContext sessionContext) {
-- this.sessionContext = sessionContext;
-- }
+- /**
+- * Create a new instance.
+- * @param context Reference count release responsibility is not transferred! The
callee still owns this object.
+- * @param alloc The allocator to use.
+- * @param peerHost The peer host name.
+- * @param peerPort The peer port.
+- * @param jdkCompatibilityMode {@code true} to behave like described in
+- *
https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html.
+- * {@code false} allows for partial and/or multiple
packets to be process in a single
+- * wrap or unwrap call.
+- * @param leakDetection {@code true} to enable leak detection of this object.
+- */
+- ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context, final
ByteBufAllocator alloc, String peerHost,
+- int peerPort, boolean jdkCompatibilityMode, boolean
leakDetection) {
+- super(peerHost, peerPort);
+- OpenSsl.ensureAvailability();
+- this.alloc = checkNotNull(alloc, "alloc");
+- apn = (OpenSslApplicationProtocolNegotiator)
context.applicationProtocolNegotiator();
+- clientMode = context.isClient();
+- if (PlatformDependent.javaVersion() >= 7) {
+- session = new ExtendedOpenSslSession(new
DefaultOpenSslSession(context.sessionContext())) {
+- private String[] peerSupportedSignatureAlgorithms;
+- private List requestedServerNames;
-
-- @Override
-- public byte[] getId() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (id == null) {
-- return EmptyArrays.EMPTY_BYTES;
+- @Override
+- public List getRequestedServerNames() {
+- if (clientMode) {
+- return Java8SslUtils.getSniHostNames(sniHostNames);
+- } else {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (requestedServerNames == null) {
+- if (isDestroyed()) {
+- requestedServerNames = Collections.emptyList();
+- } else {
+- String name = SSL.getSniHostname(ssl);
+- if (name == null) {
+- requestedServerNames = Collections.emptyList();
+- } else {
+- // Convert to bytes as we do not want to do any
strict validation of the
+- // SNIHostName while creating it.
+- requestedServerNames =
+- Java8SslUtils.getSniHostName(
+-
SSL.getSniHostname(ssl).getBytes(CharsetUtil.UTF_8));
+- }
+- }
+- }
+- return requestedServerNames;
+- }
+- }
- }
-- return id.clone();
-- }
-- }
-
-- @Override
-- public SSLSessionContext getSessionContext() {
-- return sessionContext;
-- }
+- @Override
+- public String[] getPeerSupportedSignatureAlgorithms() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (peerSupportedSignatureAlgorithms == null) {
+- if (isDestroyed()) {
+- peerSupportedSignatureAlgorithms =
EmptyArrays.EMPTY_STRINGS;
+- } else {
+- String[] algs = SSL.getSigAlgs(ssl);
+- if (algs == null) {
+- peerSupportedSignatureAlgorithms =
EmptyArrays.EMPTY_STRINGS;
+- } else {
+- Set<String> algorithmList = new
LinkedHashSet<String>(algs.length);
+- for (String alg: algs) {
+- String converted =
SignatureAlgorithmConverter.toJavaName(alg);
-
-- @Override
-- public long getCreationTime() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (creationTime == 0 && !isDestroyed()) {
-- creationTime = SSL.getTime(ssl) * 1000L;
+- if (converted != null) {
+- algorithmList.add(converted);
+- }
+- }
+- peerSupportedSignatureAlgorithms =
algorithmList.toArray(new String[0]);
+- }
+- }
+- }
+- return peerSupportedSignatureAlgorithms.clone();
+- }
- }
-- }
-- return creationTime;
-- }
--
-- @Override
-- public long getLastAccessedTime() {
-- long lastAccessed = ReferenceCountedOpenSslEngine.this.lastAccessed;
-- // if lastAccessed is -1 we will just return the creation time as the
handshake was not started yet.
-- return lastAccessed == -1 ? getCreationTime() : lastAccessed;
-- }
-
-- @Override
-- public void invalidate() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- SSL.setTimeout(ssl, 0);
+- @Override
+- public List<byte[]> getStatusResponses() {
+- byte[] ocspResponse = null;
+- if (enableOcsp && clientMode) {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- ocspResponse = SSL.getOcspResponse(ssl);
+- }
+- }
+- }
+- return ocspResponse == null ?
+- Collections.<byte[]>emptyList() :
Collections.singletonList(ocspResponse);
- }
-- }
+- };
+- } else {
+- session = new DefaultOpenSslSession(context.sessionContext());
- }
--
-- @Override
-- public boolean isValid() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L)
< (SSL.getTime(ssl) * 1000L);
-- }
-- }
-- return false;
+- engineMap = context.engineMap;
+- enableOcsp = context.enableOcsp;
+- if (!context.sessionContext().useKeyManager()) {
+- // If we do not use the KeyManagerFactory we need to set
localCertificateChain now.
+- // When we use a KeyManagerFactory it will be set during
setKeyMaterial(...).
+- localCertificateChain = context.keyCertChain;
- }
-
-- @Override
-- public void putValue(String name, Object value) {
-- if (name == null) {
-- throw new NullPointerException("name");
-- }
-- if (value == null) {
-- throw new NullPointerException("value");
-- }
-- Map<String, Object> values = this.values;
-- if (values == null) {
-- // Use size of 2 to keep the memory overhead small
-- values = this.values = new HashMap<String, Object>(2);
-- }
-- Object old = values.put(name, value);
-- if (value instanceof SSLSessionBindingListener) {
-- ((SSLSessionBindingListener) value).valueBound(new
SSLSessionBindingEvent(this, name));
-- }
-- notifyUnbound(old, name);
+- this.jdkCompatibilityMode = jdkCompatibilityMode;
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- final long finalSsl;
+- try {
+- finalSsl = SSL.newSSL(context.ctx, !context.isClient());
+- } finally {
+- readerLock.unlock();
- }
+- synchronized (this) {
+- ssl = finalSsl;
+- try {
+- networkBIO = SSL.bioNewByteBuffer(ssl,
context.getBioNonApplicationBufferSize());
-
-- @Override
-- public Object getValue(String name) {
-- if (name == null) {
-- throw new NullPointerException("name");
-- }
-- if (values == null) {
-- return null;
-- }
-- return values.get(name);
-- }
+- // Set the client auth mode, this needs to be done via
setClientAuth(...) method so we actually call the
+- // needed JNI methods.
+- setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth);
-
-- @Override
-- public void removeValue(String name) {
-- if (name == null) {
-- throw new NullPointerException("name");
-- }
-- Map<String, Object> values = this.values;
-- if (values == null) {
-- return;
-- }
-- Object old = values.remove(name);
-- notifyUnbound(old, name);
-- }
+- if (context.protocols != null) {
+- setEnabledProtocols(context.protocols);
+- }
-
-- @Override
-- public String[] getValueNames() {
-- Map<String, Object> values = this.values;
-- if (values == null || values.isEmpty()) {
-- return EmptyArrays.EMPTY_STRINGS;
-- }
-- return values.keySet().toArray(new String[values.size()]);
-- }
+- // Use SNI if peerHost was specified and a valid hostname
+- // See
https://github.com/netty/netty/issues/4746
+- if (clientMode && SslUtils.isValidHostNameForSNI(peerHost)) {
+- SSL.setTlsExtHostName(ssl, peerHost);
+- sniHostNames = Collections.singletonList(peerHost);
+- }
-
-- private void notifyUnbound(Object value, String name) {
-- if (value instanceof SSLSessionBindingListener) {
-- ((SSLSessionBindingListener) value).valueUnbound(new
SSLSessionBindingEvent(this, name));
-- }
-- }
+- if (enableOcsp) {
+- SSL.enableOcsp(ssl);
+- }
-
-- /**
-- * Finish the handshake and so init everything in the {@link OpenSslSession}
that should be accessible by
-- * the user.
-- */
-- void handshakeFinished() throws SSLException {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- id = SSL.getSessionId(ssl);
-- cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
-- protocol = SSL.getVersion(ssl);
+- if (!jdkCompatibilityMode) {
+- SSL.setMode(ssl, SSL.getMode(ssl) |
SSL.SSL_MODE_ENABLE_PARTIAL_WRITE);
+- }
-
-- initPeerCerts();
-- selectApplicationProtocol();
+- // setMode may impact the overhead.
+- calculateMaxWrapOverhead();
+- } catch (Throwable cause) {
+- // Call shutdown so we are sure we correctly release all native memory
and also guard against the
+- // case when shutdown() will be called by the finalizer again.
+- shutdown();
-
-- handshakeState = HandshakeState.FINISHED;
-- } else {
-- throw new SSLException("Already closed");
-- }
+- PlatformDependent.throwException(cause);
- }
- }
-
-- /**
-- * Init peer certificates that can be obtained via {@link
#getPeerCertificateChain()}
-- * and {@link #getPeerCertificates()}.
-- */
-- private void initPeerCerts() {
-- // Return the full chain from the JNI layer.
-- byte[][] chain = SSL.getPeerCertChain(ssl);
-- if (clientMode) {
-- if (isEmpty(chain)) {
-- peerCerts = EMPTY_CERTIFICATES;
-- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES;
-- } else {
-- peerCerts = new Certificate[chain.length];
-- x509PeerCerts = new X509Certificate[chain.length];
-- initCerts(chain, 0);
-- }
-- } else {
-- // if used on the server side SSL_get_peer_cert_chain(...) will not
include the remote peer
-- // certificate. We use SSL_get_peer_certificate to get it in this case
and add it to our
-- // array later.
-- //
-- // See
https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
-- byte[] clientCert = SSL.getPeerCertificate(ssl);
-- if (isEmpty(clientCert)) {
-- peerCerts = EMPTY_CERTIFICATES;
-- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES;
-- } else {
-- if (isEmpty(chain)) {
-- peerCerts = new Certificate[] {new
OpenSslX509Certificate(clientCert)};
-- x509PeerCerts = new X509Certificate[] {new
OpenSslJavaxX509Certificate(clientCert)};
-- } else {
-- peerCerts = new Certificate[chain.length + 1];
-- x509PeerCerts = new X509Certificate[chain.length + 1];
-- peerCerts[0] = new OpenSslX509Certificate(clientCert);
-- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert);
-- initCerts(chain, 1);
-- }
-- }
-- }
+- // Now that everything looks good and we're going to successfully return
the
+- // object so we need to retain a reference to the parent context.
+- parentContext = context;
+- parentContext.retain();
+-
+- // Only create the leak after everything else was executed and so ensure we
don't produce a false-positive for
+- // the ResourceLeakDetector.
+- leak = leakDetection ? leakDetector.track(this) : null;
+- }
+-
+- final synchronized String[] authMethods() {
+- if (isDestroyed()) {
+- return EmptyArrays.EMPTY_STRINGS;
- }
+- return SSL.authenticationMethods(ssl);
+- }
-
-- private void initCerts(byte[][] chain, int startPos) {
-- for (int i = 0; i < chain.length; i++) {
-- int certPos = startPos + i;
-- peerCerts[certPos] = new OpenSslX509Certificate(chain[i]);
-- x509PeerCerts[certPos] = new OpenSslJavaxX509Certificate(chain[i]);
+- final boolean setKeyMaterial(OpenSslKeyMaterial keyMaterial) throws Exception {
+- synchronized (this) {
+- if (isDestroyed()) {
+- return false;
- }
+- SSL.setKeyMaterial(ssl, keyMaterial.certificateChainAddress(),
keyMaterial.privateKeyAddress());
- }
+- localCertificateChain = keyMaterial.certificateChain();
+- return true;
+- }
-
-- /**
-- * Select the application protocol used.
-- */
-- private void selectApplicationProtocol() throws SSLException {
-- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior =
apn.selectedListenerFailureBehavior();
-- List<String> protocols = apn.protocols();
-- String applicationProtocol;
-- switch (apn.protocol()) {
-- case NONE:
-- break;
-- // We always need to check for applicationProtocol == null as the remote
peer may not support
-- // the TLS extension or may have returned an empty selection.
-- case ALPN:
-- applicationProtocol = SSL.getAlpnSelected(ssl);
-- if (applicationProtocol != null) {
-- this.applicationProtocol = selectApplicationProtocol(
-- protocols, behavior, applicationProtocol);
-- }
-- break;
-- case NPN:
-- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
-- if (applicationProtocol != null) {
-- this.applicationProtocol = selectApplicationProtocol(
-- protocols, behavior, applicationProtocol);
-- }
-- break;
-- case NPN_AND_ALPN:
-- applicationProtocol = SSL.getAlpnSelected(ssl);
-- if (applicationProtocol == null) {
-- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
-- }
-- if (applicationProtocol != null) {
-- this.applicationProtocol = selectApplicationProtocol(
-- protocols, behavior, applicationProtocol);
-- }
-- break;
-- default:
-- throw new Error();
-- }
+- final synchronized SecretKeySpec masterKey() {
+- if (isDestroyed()) {
+- return null;
- }
+- return new SecretKeySpec(SSL.getMasterKey(ssl), "AES");
+- }
-
-- private String selectApplicationProtocol(List<String> protocols,
--
ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior,
-- String applicationProtocol) throws
SSLException {
-- if (behavior ==
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) {
-- return applicationProtocol;
-- } else {
-- int size = protocols.size();
-- assert size > 0;
-- if (protocols.contains(applicationProtocol)) {
-- return applicationProtocol;
-- } else {
-- if (behavior ==
ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) {
-- return protocols.get(size - 1);
-- } else {
-- throw new SSLException("unknown protocol " +
applicationProtocol);
-- }
-- }
+- /**
+- * Sets the OCSP response.
+- */
+- @UnstableApi
+- public void setOcspResponse(byte[] response) {
+- if (!enableOcsp) {
+- throw new IllegalStateException("OCSP stapling is not enabled");
+- }
+-
+- if (clientMode) {
+- throw new IllegalStateException("Not a server SSLEngine");
+- }
+-
+- synchronized (this) {
+- if (!isDestroyed()) {
+- SSL.setOcspResponse(ssl, response);
- }
- }
+- }
-
-- @Override
-- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (isEmpty(peerCerts)) {
-- throw new SSLPeerUnverifiedException("peer not
verified");
-- }
-- return peerCerts.clone();
+- /**
+- * Returns the OCSP response or {@code null} if the server didn't provide a
stapled OCSP response.
+- */
+- @UnstableApi
+- public byte[] getOcspResponse() {
+- if (!enableOcsp) {
+- throw new IllegalStateException("OCSP stapling is not enabled");
+- }
+-
+- if (!clientMode) {
+- throw new IllegalStateException("Not a client SSLEngine");
+- }
+-
+- synchronized (this) {
+- if (isDestroyed()) {
+- return EmptyArrays.EMPTY_BYTES;
- }
+- return SSL.getOcspResponse(ssl);
- }
+- }
-
-- @Override
-- public Certificate[] getLocalCertificates() {
-- if (localCerts == null) {
+- @Override
+- public final int refCnt() {
+- return refCnt.refCnt();
+- }
+-
+- @Override
+- public final ReferenceCounted retain() {
+- refCnt.retain();
+- return this;
+- }
+-
+- @Override
+- public final ReferenceCounted retain(int increment) {
+- refCnt.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public final ReferenceCounted touch() {
+- refCnt.touch();
+- return this;
+- }
+-
+- @Override
+- public final ReferenceCounted touch(Object hint) {
+- refCnt.touch(hint);
+- return this;
+- }
+-
+- @Override
+- public final boolean release() {
+- return refCnt.release();
+- }
+-
+- @Override
+- public final boolean release(int decrement) {
+- return refCnt.release(decrement);
+- }
+-
+- @Override
+- public final synchronized SSLSession getHandshakeSession() {
+- // Javadocs state return value should be:
+- // null if this instance is not currently handshaking, or if the current
handshake has not
+- // progressed far enough to create a basic SSLSession. Otherwise, this method
returns the
+- // SSLSession currently being negotiated.
+- switch(handshakeState) {
+- case NOT_STARTED:
+- case FINISHED:
- return null;
-- }
-- return localCerts.clone();
+- default:
+- return session;
- }
+- }
-
-- @Override
-- public X509Certificate[] getPeerCertificateChain() throws
SSLPeerUnverifiedException {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (isEmpty(x509PeerCerts)) {
-- throw new SSLPeerUnverifiedException("peer not
verified");
+- /**
+- * Returns the pointer to the {@code SSL} object for this {@link
ReferenceCountedOpenSslEngine}.
+- * Be aware that it is freed as soon as the {@link #release()} or {@link
#shutdown()} methods are called.
+- * At this point {@code 0} will be returned.
+- */
+- public final synchronized long sslPointer() {
+- return ssl;
+- }
+-
+- /**
+- * Destroys this engine.
+- */
+- public final synchronized void shutdown() {
+- if (!destroyed) {
+- destroyed = true;
+- engineMap.remove(ssl);
+- SSL.freeSSL(ssl);
+- ssl = networkBIO = 0;
+-
+- isInboundDone = outboundClosed = true;
+- }
+-
+- // On shutdown clear all errors
+- SSL.clearError();
+- }
+-
+- /**
+- * Write plaintext data to the OpenSSL internal BIO
+- *
+- * Calling this function with src.remaining == 0 is undefined.
+- */
+- private int writePlaintextData(final ByteBuffer src, int len) {
+- final int pos = src.position();
+- final int limit = src.limit();
+- final int sslWrote;
+-
+- if (src.isDirect()) {
+- sslWrote = SSL.writeToSSL(ssl, bufferAddress(src) + pos, len);
+- if (sslWrote > 0) {
+- src.position(pos + sslWrote);
+- }
+- } else {
+- ByteBuf buf = alloc.directBuffer(len);
+- try {
+- src.limit(pos + len);
+-
+- buf.setBytes(0, src);
+- src.limit(limit);
+-
+- sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len);
+- if (sslWrote > 0) {
+- src.position(pos + sslWrote);
+- } else {
+- src.position(pos);
- }
-- return x509PeerCerts.clone();
+- } finally {
+- buf.release();
- }
- }
+- return sslWrote;
+- }
-
-- @Override
-- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
-- Certificate[] peer = getPeerCertificates();
-- // No need for null or length > 0 is needed as this is done in
getPeerCertificates()
-- // already.
-- return ((java.security.cert.X509Certificate)
peer[0]).getSubjectX500Principal();
-- }
+- /**
+- * Write encrypted data to the OpenSSL network BIO.
+- */
+- private ByteBuf writeEncryptedData(final ByteBuffer src, int len) {
+- final int pos = src.position();
+- if (src.isDirect()) {
+- SSL.bioSetByteBuffer(networkBIO, bufferAddress(src) + pos, len, false);
+- } else {
+- final ByteBuf buf = alloc.directBuffer(len);
+- try {
+- final int limit = src.limit();
+- src.limit(pos + len);
+- buf.writeBytes(src);
+- // Restore the original position and limit because we don't want to
consume from `src`.
+- src.position(pos);
+- src.limit(limit);
-
-- @Override
-- public Principal getLocalPrincipal() {
-- Certificate[] local = localCerts;
-- if (local == null || local.length == 0) {
-- return null;
+- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false);
+- return buf;
+- } catch (Throwable cause) {
+- buf.release();
+- PlatformDependent.throwException(cause);
- }
-- return ((java.security.cert.X509Certificate)
local[0]).getIssuerX500Principal();
- }
+- return null;
+- }
-
-- @Override
-- public String getCipherSuite() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (cipher == null) {
-- return INVALID_CIPHER;
-- }
-- return cipher;
+- /**
+- * Read plaintext data from the OpenSSL internal BIO
+- */
+- private int readPlaintextData(final ByteBuffer dst) {
+- final int sslRead;
+- final int pos = dst.position();
+- if (dst.isDirect()) {
+- sslRead = SSL.readFromSSL(ssl, bufferAddress(dst) + pos, dst.limit() -
pos);
+- if (sslRead > 0) {
+- dst.position(pos + sslRead);
- }
-- }
--
-- @Override
-- public String getProtocol() {
-- String protocol = this.protocol;
-- if (protocol == null) {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- protocol = SSL.getVersion(ssl);
-- } else {
-- protocol = StringUtil.EMPTY_STRING;
-- }
+- } else {
+- final int limit = dst.limit();
+- final int len = min(maxEncryptedPacketLength0(), limit - pos);
+- final ByteBuf buf = alloc.directBuffer(len);
+- try {
+- sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len);
+- if (sslRead > 0) {
+- dst.limit(pos + sslRead);
+- buf.getBytes(buf.readerIndex(), dst);
+- dst.limit(limit);
- }
+- } finally {
+- buf.release();
- }
-- return protocol;
-- }
--
-- @Override
-- public String getApplicationProtocol() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- return applicationProtocol;
-- }
-- }
--
-- @Override
-- public String getPeerHost() {
-- return ReferenceCountedOpenSslEngine.this.getPeerHost();
- }
-
-- @Override
-- public int getPeerPort() {
-- return ReferenceCountedOpenSslEngine.this.getPeerPort();
-- }
+- return sslRead;
+- }
-
-- @Override
-- public int getPacketBufferSize() {
-- return MAX_ENCRYPTED_PACKET_LENGTH;
-- }
+- /**
+- * Visible only for testing!
+- */
+- final synchronized int maxWrapOverhead() {
+- return maxWrapOverhead;
+- }
-
-- @Override
-- public int getApplicationBufferSize() {
-- return MAX_PLAINTEXT_LENGTH;
-- }
+- /**
+- * Visible only for testing!
+- */
+- final synchronized int maxEncryptedPacketLength() {
+- return maxEncryptedPacketLength0();
- }
--}
-diff --git
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
-deleted file mode 100644
-index 4c9df31..0000000
----
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
-+++ /dev/null
-@@ -1,239 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
--import io.netty.internal.tcnative.SniHostNameMatcher;
--import io.netty.util.internal.PlatformDependent;
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
+- /**
+- * This method is intentionally not synchronized, only use if you know you are in
the EventLoop
+- * thread and visibility on {@link #maxWrapOverhead} is achieved via other
synchronized blocks.
+- */
+- final int maxEncryptedPacketLength0() {
+- return maxWrapOverhead + MAX_PLAINTEXT_LENGTH;
+- }
-
--import java.security.KeyStore;
--import java.security.PrivateKey;
--import java.security.cert.X509Certificate;
--import javax.net.ssl.KeyManagerFactory;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.TrustManagerFactory;
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.net.ssl.X509ExtendedTrustManager;
--import javax.net.ssl.X509KeyManager;
--import javax.net.ssl.X509TrustManager;
+- /**
+- * This method is intentionally not synchronized, only use if you know you are in
the EventLoop
+- * thread and visibility on {@link #maxWrapBufferSize} and {@link #maxWrapOverhead}
is achieved
+- * via other synchronized blocks.
+- */
+- final int calculateMaxLengthForWrap(int plaintextLength, int numComponents) {
+- return (int) min(maxWrapBufferSize, plaintextLength + (long) maxWrapOverhead *
numComponents);
+- }
-
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
+- final synchronized int sslPending() {
+- return sslPending0();
+- }
-
--/**
-- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
-- * <p>Instances of this class must be {@link #release() released} or else native
memory will leak!
-- *
-- * <p>Instances of this class <strong>must not</strong> be released
before any {@link ReferenceCountedOpenSslEngine}
-- * which depends upon the instance of this class is released. Otherwise if any method
of
-- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI
resources the JVM may crash.
-- */
--public final class ReferenceCountedOpenSslServerContext extends
ReferenceCountedOpenSslContext {
-- private static final InternalLogger logger =
--
InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class);
-- private static final byte[] ID = {'n', 'e', 't',
't', 'y'};
-- private final OpenSslServerSessionContext sessionContext;
-- private final OpenSslKeyMaterialManager keyMaterialManager;
+- /**
+- * It is assumed this method is called in a synchronized block (or the
constructor)!
+- */
+- private void calculateMaxWrapOverhead() {
+- maxWrapOverhead = SSL.getMaxWrapOverhead(ssl);
-
-- ReferenceCountedOpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory
trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[]
protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers,
-- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout,
clientAuth, protocols, startTls,
-- enableOcsp);
+- // maxWrapBufferSize must be set after maxWrapOverhead because there is a
dependency on this value.
+- // If jdkCompatibility mode is off we allow enough space to encrypt 16 buffers
at a time. This could be
+- // configurable in the future if necessary.
+- maxWrapBufferSize = jdkCompatibilityMode ? maxEncryptedPacketLength0() :
maxEncryptedPacketLength0() << 4;
- }
-
-- private ReferenceCountedOpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory
trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[]
protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
SSL.SSL_MODE_SERVER, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp, true);
-- // Create a new SSL_CTX and configure it.
-- boolean success = false;
-- try {
-- ServerContext context = newSessionContext(this, ctx, engineMap,
trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword,
keyManagerFactory);
-- sessionContext = context.sessionContext;
-- keyMaterialManager = context.keyMaterialManager;
-- success = true;
-- } finally {
-- if (!success) {
-- release();
-- }
-- }
+- private int sslPending0() {
+- // OpenSSL has a limitation where if you call SSL_pending before the handshake
is complete OpenSSL will throw a
+- // "called a function you should not call" error. Using the TLS_method
instead of SSLv23_method may solve this
+- // issue but this API is only available in 1.1.0+ [1].
+- // [1]
https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_new.html
+- return handshakeState != HandshakeState.FINISHED ? 0 : SSL.sslPending(ssl);
- }
-
-- @Override
-- public OpenSslServerSessionContext sessionContext() {
-- return sessionContext;
+- private boolean isBytesAvailableEnoughForWrap(int bytesAvailable, int
plaintextLength, int numComponents) {
+- return bytesAvailable - (long) maxWrapOverhead * numComponents >=
plaintextLength;
- }
-
- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return keyMaterialManager;
-- }
+- public final SSLEngineResult wrap(
+- final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst)
throws SSLException {
+- // Throw required runtime exceptions
+- if (srcs == null) {
+- throw new IllegalArgumentException("srcs is null");
+- }
+- if (dst == null) {
+- throw new IllegalArgumentException("dst is null");
+- }
-
-- static final class ServerContext {
-- OpenSslServerSessionContext sessionContext;
-- OpenSslKeyMaterialManager keyMaterialManager;
-- }
+- if (offset >= srcs.length || offset + length > srcs.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + offset + ", length: " + length +
+- " (expected: offset <= offset + length <=
srcs.length (" + srcs.length + "))");
+- }
-
-- static ServerContext newSessionContext(ReferenceCountedOpenSslContext thiz, long
ctx, OpenSslEngineMap engineMap,
-- X509Certificate[] trustCertCollection,
-- TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey
key,
-- String keyPassword, KeyManagerFactory
keyManagerFactory)
-- throws SSLException {
-- ServerContext result = new ServerContext();
-- try {
-- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
-- if (!OpenSsl.useKeyManagerFactory()) {
-- if (keyManagerFactory != null) {
-- throw new IllegalArgumentException(
-- "KeyManagerFactory not supported");
+- if (dst.isReadOnly()) {
+- throw new ReadOnlyBufferException();
+- }
+-
+- synchronized (this) {
+- if (isOutboundDone()) {
+- // All drained in the outbound buffer
+- return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING :
NEED_UNWRAP_CLOSED;
+- }
+-
+- int bytesProduced = 0;
+- ByteBuf bioReadCopyBuf = null;
+- try {
+- // Setup the BIO buffer so that we directly write the encryption results
into dst.
+- if (dst.isDirect()) {
+- SSL.bioSetByteBuffer(networkBIO, bufferAddress(dst) +
dst.position(), dst.remaining(),
+- true);
+- } else {
+- bioReadCopyBuf = alloc.directBuffer(dst.remaining());
+- SSL.bioSetByteBuffer(networkBIO, memoryAddress(bioReadCopyBuf),
bioReadCopyBuf.writableBytes(),
+- true);
+- }
+-
+- int bioLengthBefore = SSL.bioLengthByteBuffer(networkBIO);
+-
+- // Explicitly use outboundClosed as we want to drain any bytes that are
still present.
+- if (outboundClosed) {
+- // If the outbound was closed we want to ensure we can produce the
alert to the destination buffer.
+- // This is true even if we not using jdkCompatibilityMode.
+- //
+- // We use a plaintextLength of 2 as we at least want to have an
alert fit into it.
+- //
https://tools.ietf.org/html/rfc5246#section-7.2
+- if (!isBytesAvailableEnoughForWrap(dst.remaining(), 2, 1)) {
+- return new SSLEngineResult(BUFFER_OVERFLOW,
getHandshakeStatus(), 0, 0);
+- }
+-
+- // There is something left to drain.
+- // See
https://github.com/netty/netty/issues/6260
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
+- if (bytesProduced <= 0) {
+- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0);
+- }
+- // It is possible when the outbound was closed there was not enough
room in the non-application
+- // buffers to hold the close_notify. We should keep trying to close
until we consume all the data
+- // OpenSSL can give us.
+- if (!doSSLShutdown()) {
+- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0,
bytesProduced);
+- }
+- bytesProduced = bioLengthBefore -
SSL.bioLengthByteBuffer(networkBIO);
+- return newResultMayFinishHandshake(NEED_WRAP, 0, bytesProduced);
- }
-- checkNotNull(keyCertChain, "keyCertChain");
-
-- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
-- } else {
-- // javadocs state that keyManagerFactory has precedent over
keyCertChain, and we must have a
-- // keyManagerFactory for the server so build one if it is not
specified.
-- if (keyManagerFactory == null) {
-- keyManagerFactory = buildKeyManagerFactory(
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- }
-- X509KeyManager keyManager =
chooseX509KeyManager(keyManagerFactory.getKeyManagers());
-- result.keyMaterialManager = useExtendedKeyManager(keyManager) ?
-- new OpenSslExtendedKeyMaterialManager(
-- (X509ExtendedKeyManager) keyManager, keyPassword) :
-- new OpenSslKeyMaterialManager(keyManager, keyPassword);
-- }
-- } catch (Exception e) {
-- throw new SSLException("failed to set certificate and key", e);
-- }
-- try {
-- if (trustCertCollection != null) {
-- trustManagerFactory = buildTrustManagerFactory(trustCertCollection,
trustManagerFactory);
-- } else if (trustManagerFactory == null) {
-- // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
-- trustManagerFactory = TrustManagerFactory.getInstance(
-- TrustManagerFactory.getDefaultAlgorithm());
-- trustManagerFactory.init((KeyStore) null);
-- }
+- // Flush any data that may be implicitly generated by OpenSSL
(handshake, close, etc..).
+- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
+- // Prepare OpenSSL to work in server mode and receive handshake
+- if (handshakeState != HandshakeState.FINISHED) {
+- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
+- // Update accepted so we know we triggered the handshake via
wrap
+- handshakeState = HandshakeState.STARTED_IMPLICITLY;
+- }
+-
+- // Flush any data that may have been written implicitly during the
handshake by OpenSSL.
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
+-
+- if (pendingException != null) {
+- // TODO(scott): It is possible that when the handshake failed
there was not enough room in the
+- // non-application buffers to hold the alert. We should get all
the data before progressing on.
+- // However I'm not aware of a way to do this with the
OpenSSL APIs.
+- // See
https://github.com/netty/netty/issues/6385.
+-
+- // We produced / consumed some data during the handshake, signal
back to the caller.
+- // If there is a handshake exception and we have produced data,
we should send the data before
+- // we allow handshake() to throw the handshake exception.
+- //
+- // When the user calls wrap() again we will propagate the
handshake error back to the user as
+- // soon as there is no more data to was produced (as part of an
alert etc).
+- if (bytesProduced > 0) {
+- return newResult(NEED_WRAP, 0, bytesProduced);
+- }
+- // Nothing was produced see if there is a handshakeException
that needs to be propagated
+- // to the caller by calling handshakeException() which will
return the right HandshakeStatus
+- // if it can "recover" from the exception for now.
+- return newResult(handshakeException(), 0, 0);
+- }
+-
+- status = handshake();
+-
+- // Handshake may have generated more data, for example if the
internal SSL buffer is small
+- // we may have freed up space by flushing above.
+- bytesProduced = bioLengthBefore -
SSL.bioLengthByteBuffer(networkBIO);
+-
+- if (status == NEED_TASK) {
+- return newResult(status, 0, bytesProduced);
+- }
+-
+- if (bytesProduced > 0) {
+- // If we have filled up the dst buffer and we have not finished
the handshake we should try to
+- // wrap again. Otherwise we should only try to wrap again if
there is still data pending in
+- // SSL buffers.
+- return newResult(mayFinishHandshake(status != FINISHED ?
+- bytesProduced == bioLengthBefore ? NEED_WRAP :
+-
getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) : FINISHED),
+- 0, bytesProduced);
+- }
+-
+- if (status == NEED_UNWRAP) {
+- // Signal if the outbound is done or not.
+- return isOutboundDone() ? NEED_UNWRAP_CLOSED : NEED_UNWRAP_OK;
+- }
-
-- final X509TrustManager manager =
chooseTrustManager(trustManagerFactory.getTrustManagers());
+- // Explicit use outboundClosed and not outboundClosed() as we want
to drain any bytes that are
+- // still present.
+- if (outboundClosed) {
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
+- return newResultMayFinishHandshake(status, 0, bytesProduced);
+- }
+- }
-
-- // IMPORTANT: The callbacks set for verification must be static to prevent
memory leak as
-- // otherwise the context can never be collected. This is because
the JNI code holds
-- // a global reference to the callbacks.
-- //
-- // See
https://github.com/netty/netty/issues/5372
+- final int endOffset = offset + length;
+- if (jdkCompatibilityMode) {
+- int srcsLen = 0;
+- for (int i = offset; i < endOffset; ++i) {
+- final ByteBuffer src = srcs[i];
+- if (src == null) {
+- throw new IllegalArgumentException("srcs[" + i +
"] is null");
+- }
+- if (srcsLen == MAX_PLAINTEXT_LENGTH) {
+- continue;
+- }
-
-- // Use this to prevent an error when running on java < 7
-- if (useExtendedTrustManager(manager)) {
-- SSLContext.setCertVerifyCallback(ctx,
-- new ExtendedTrustManagerVerifyCallback(engineMap,
(X509ExtendedTrustManager) manager));
-- } else {
-- SSLContext.setCertVerifyCallback(ctx, new
TrustManagerVerifyCallback(engineMap, manager));
-- }
+- srcsLen += src.remaining();
+- if (srcsLen > MAX_PLAINTEXT_LENGTH || srcsLen < 0) {
+- // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just
set it to MAX_PLAINTEXT_LENGTH.
+- // This also help us to guard against overflow.
+- // We not break out here as we still need to check for null
entries in srcs[].
+- srcsLen = MAX_PLAINTEXT_LENGTH;
+- }
+- }
-
-- X509Certificate[] issuers = manager.getAcceptedIssuers();
-- if (issuers != null && issuers.length > 0) {
-- long bio = 0;
-- try {
-- bio = toBIO(issuers);
-- if (!SSLContext.setCACertificateBio(ctx, bio)) {
-- throw new SSLException("unable to setup accepted issuers
for trustmanager " + manager);
+- // jdkCompatibilityMode will only produce a single TLS packet, and
we don't aggregate src buffers,
+- // so we always fix the number of buffers to 1 when checking if the
dst buffer is large enough.
+- if (!isBytesAvailableEnoughForWrap(dst.remaining(), srcsLen, 1)) {
+- return new SSLEngineResult(BUFFER_OVERFLOW,
getHandshakeStatus(), 0, 0);
- }
-- } finally {
-- freeBio(bio);
- }
-- }
-
-- if (PlatformDependent.javaVersion() >= 8) {
-- // Only do on Java8+ as SNIMatcher is not supported in earlier
releases.
-- // IMPORTANT: The callbacks set for hostname matching must be static to
prevent memory leak as
-- // otherwise the context can never be collected. This is
because the JNI code holds
-- // a global reference to the matcher.
-- SSLContext.setSniHostnameMatcher(ctx, new
OpenSslSniHostnameMatcher(engineMap));
-- }
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException("unable to setup trustmanager", e);
-- }
+- // There was no pending data in the network BIO -- encrypt any
application data
+- int bytesConsumed = 0;
+- assert bytesProduced == 0;
-
-- result.sessionContext = new OpenSslServerSessionContext(thiz);
-- result.sessionContext.setSessionIdContext(ID);
-- return result;
-- }
+- // Flush any data that may have been written implicitly by OpenSSL in
case a shutdown/alert occurs.
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-
-- private static final class TrustManagerVerifyCallback extends
AbstractCertificateVerifier {
-- private final X509TrustManager manager;
+- if (bytesProduced > 0) {
+- return newResultMayFinishHandshake(status, bytesConsumed,
bytesProduced);
+- }
+- // There was a pending exception that we just delayed because there was
something to produce left.
+- // Throw it now and shutdown the engine.
+- if (pendingException != null) {
+- Throwable error = pendingException;
+- pendingException = null;
+- shutdown();
+- // Throw a new exception wrapping the pending exception, so the
stacktrace is meaningful and
+- // contains all the details.
+- throw new SSLException(error);
+- }
-
-- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager)
{
-- super(engineMap);
-- this.manager = manager;
-- }
+- for (; offset < endOffset; ++offset) {
+- final ByteBuffer src = srcs[offset];
+- final int remaining = src.remaining();
+- if (remaining == 0) {
+- continue;
+- }
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
String auth)
-- throws Exception {
-- manager.checkClientTrusted(peerCerts, auth);
-- }
-- }
+- final int bytesWritten;
+- if (jdkCompatibilityMode) {
+- // Write plaintext application data to the SSL engine. We
don't have to worry about checking
+- // if there is enough space if jdkCompatibilityMode because we
only wrap at most
+- // MAX_PLAINTEXT_LENGTH and we loop over the input before hand
and check if there is space.
+- bytesWritten = writePlaintextData(src, min(remaining,
MAX_PLAINTEXT_LENGTH - bytesConsumed));
+- } else {
+- // OpenSSL's SSL_write keeps state between calls. We should
make sure the amount we attempt to
+- // write is guaranteed to succeed so we don't have to worry
about keeping state consistent
+- // between calls.
+- final int availableCapacityForWrap = dst.remaining() -
bytesProduced - maxWrapOverhead;
+- if (availableCapacityForWrap <= 0) {
+- return new SSLEngineResult(BUFFER_OVERFLOW,
getHandshakeStatus(), bytesConsumed,
+- bytesProduced);
+- }
+- bytesWritten = writePlaintextData(src, min(remaining,
availableCapacityForWrap));
+- }
-
-- private static final class ExtendedTrustManagerVerifyCallback extends
AbstractCertificateVerifier {
-- private final X509ExtendedTrustManager manager;
+- // Determine how much encrypted data was generated.
+- //
+- // Even if SSL_write doesn't consume any application data it is
possible that OpenSSL will
+- // produce non-application data into the BIO. For example session
tickets....
+- // See
https://github.com/netty/netty/issues/10041
+- final int pendingNow = SSL.bioLengthByteBuffer(networkBIO);
+- bytesProduced += bioLengthBefore - pendingNow;
+- bioLengthBefore = pendingNow;
-
-- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap,
X509ExtendedTrustManager manager) {
-- super(engineMap);
-- this.manager = manager;
-- }
+- if (bytesWritten > 0) {
+- bytesConsumed += bytesWritten;
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
String auth)
-- throws Exception {
-- manager.checkClientTrusted(peerCerts, auth, engine);
-- }
-- }
+- if (jdkCompatibilityMode || bytesProduced == dst.remaining()) {
+- return newResultMayFinishHandshake(status, bytesConsumed,
bytesProduced);
+- }
+- } else {
+- int sslError = SSL.getError(ssl, bytesWritten);
+- if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
+- // This means the connection was shutdown correctly, close
inbound and outbound
+- if (!receivedShutdown) {
+- closeAll();
-
-- private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher
{
-- private final OpenSslEngineMap engineMap;
+- bytesProduced += bioLengthBefore -
SSL.bioLengthByteBuffer(networkBIO);
-
-- OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) {
-- this.engineMap = engineMap;
-- }
+- // If we have filled up the dst buffer and we have not
finished the handshake we should
+- // try to wrap again. Otherwise we should only try to
wrap again if there is still data
+- // pending in SSL buffers.
+- SSLEngineResult.HandshakeStatus hs =
mayFinishHandshake(
+- status != FINISHED ? bytesProduced ==
dst.remaining() ? NEED_WRAP
+- :
getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO))
+- : FINISHED);
+- return newResult(hs, bytesConsumed, bytesProduced);
+- }
-
-- @Override
-- public boolean match(long ssl, String hostname) {
-- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-- if (engine != null) {
-- return engine.checkSniHostnameMatch(hostname);
-- }
-- logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer:
{}", ssl);
-- return false;
-- }
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java
b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
-index 4998d0d..8dbc3cf 100644
---- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
-@@ -115,11 +115,7 @@ public abstract class SslContext {
- }
-
- private static SslProvider defaultProvider() {
-- if (OpenSsl.isAvailable()) {
-- return SslProvider.OPENSSL;
-- } else {
-- return SslProvider.JDK;
-- }
-+ return SslProvider.JDK;
- }
-
- /**
-@@ -416,18 +412,6 @@ public abstract class SslContext {
- trustCertCollection, trustManagerFactory, keyCertChain, key,
keyPassword,
- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize,
sessionTimeout,
- clientAuth, protocols, startTls);
-- case OPENSSL:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new OpenSslServerContext(
-- trustCertCollection, trustManagerFactory, keyCertChain, key,
keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize,
sessionTimeout,
-- clientAuth, protocols, startTls, enableOcsp);
-- case OPENSSL_REFCNT:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new ReferenceCountedOpenSslServerContext(
-- trustCertCollection, trustManagerFactory, keyCertChain, key,
keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize,
sessionTimeout,
-- clientAuth, protocols, startTls, enableOcsp);
- default:
- throw new Error(provider.toString());
- }
-@@ -770,18 +754,6 @@ public abstract class SslContext {
- return new JdkSslClientContext(sslContextProvider,
- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
- keyManagerFactory, ciphers, cipherFilter, apn, protocols,
sessionCacheSize, sessionTimeout);
-- case OPENSSL:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new OpenSslClientContext(
-- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, protocols,
sessionCacheSize, sessionTimeout,
-- enableOcsp);
-- case OPENSSL_REFCNT:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new ReferenceCountedOpenSslClientContext(
-- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, protocols,
sessionCacheSize, sessionTimeout,
-- enableOcsp);
- default:
- throw new Error(provider.toString());
- }
-diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-index c054964..05c451a 100644
---- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-@@ -159,6 +159,12 @@ import static
io.netty.handler.ssl.SslUtils.getEncryptedPacketLength;
- * <a
href="https://github.com/netty/netty/issues/832">#832</a> in
our issue tracker.
- */
- public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler
{
-+ private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
-+ private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024;
-+ private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024;
-+ // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) +
Padding (256)
-+ static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 +
256;
-+ static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = MAX_ENCRYPTED_PACKET_LENGTH -
MAX_PLAINTEXT_LENGTH;
-
- private static final InternalLogger logger =
- InternalLoggerFactory.getInstance(SslHandler.class);
-@@ -181,40 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements
ChannelOutboundH
- new ClosedChannelException(), SslHandler.class,
"channelInactive(...)");
-
- private enum SslEngineType {
-- TCNATIVE(true, COMPOSITE_CUMULATOR) {
-- @Override
-- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int
len, ByteBuf out)
-- throws SSLException {
-- int nioBufferCount = in.nioBufferCount();
-- int writerIndex = out.writerIndex();
-- final SSLEngineResult result;
-- if (nioBufferCount > 1) {
-- /*
-- * If {@link OpenSslEngine} is in use,
-- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[],
ByteBuffer[])} method
-- * that accepts multiple {@link ByteBuffer}s without additional
memory copies.
-- */
-- ReferenceCountedOpenSslEngine opensslEngine =
(ReferenceCountedOpenSslEngine) handler.engine;
-- try {
-- handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
-- out.writableBytes());
-- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len),
handler.singleBuffer);
-- } finally {
-- handler.singleBuffer[0] = null;
+- return newResult(NOT_HANDSHAKING, bytesConsumed,
bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_READ) {
+- // If there is no pending data to read from BIO we should go
back to event loop and try
+- // to read more data [1]. It is also possible that event
loop will detect the socket has
+- // been closed. [1]
https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
+- return newResult(NEED_UNWRAP, bytesConsumed,
bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_WRITE) {
+- // SSL_ERROR_WANT_WRITE typically means that the underlying
transport is not writable
+- // and we should set the "want write" flag on the
selector and try again when the
+- // underlying transport is writable [1]. However we are not
directly writing to the
+- // underlying transport and instead writing to a BIO buffer.
The OpenSsl documentation
+- // says we should do the following [1]:
+- //
+- // "When using a buffering BIO, like a BIO pair, data
must be written into or retrieved
+- // out of the BIO before being able to continue."
+- //
+- // In practice this means the destination buffer doesn't
have enough space for OpenSSL
+- // to write encrypted data to. This is an OVERFLOW
condition.
+- // [1]
https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
+- if (bytesProduced > 0) {
+- // If we produced something we should report this back
and let the user call
+- // wrap again.
+- return newResult(NEED_WRAP, bytesConsumed,
bytesProduced);
+- }
+- return newResult(BUFFER_OVERFLOW, status, bytesConsumed,
bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
+- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
+- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
+-
+- return newResult(NEED_TASK, bytesConsumed, bytesProduced);
+- } else {
+- // Everything else is considered as error
+- throw shutdownWithError("SSL_write", sslError);
+- }
- }
-- } else {
-- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
-- toByteBuffer(out, writerIndex, out.writableBytes()));
- }
-- out.writerIndex(writerIndex + result.bytesProduced());
-- return result;
-- }
--
-- @Override
-- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int
numComponents) {
-- return
ReferenceCountedOpenSslEngine.calculateOutNetBufSize(pendingBytes, numComponents);
-- }
-- },
- CONSCRYPT(true, COMPOSITE_CUMULATOR) {
- @Override
- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int
len, ByteBuf out)
-@@ -265,9 +237,6 @@ public class SslHandler extends ByteToMessageDecoder implements
ChannelOutboundH
- };
-
- static SslEngineType forEngine(SSLEngine engine) {
-- if (engine instanceof ReferenceCountedOpenSslEngine) {
-- return TCNATIVE;
-- }
- if (engine instanceof ConscryptAlpnSslEngine) {
- return CONSCRYPT;
- }
-@@ -1034,7 +1003,7 @@ public class SslHandler extends ByteToMessageDecoder implements
ChannelOutboundH
-
- boolean nonSslRecord = false;
-
-- while (totalLength <
ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) {
-+ while (totalLength < MAX_ENCRYPTED_PACKET_LENGTH) {
- final int readableBytes = endOffset - offset;
- if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) {
- break;
-@@ -1055,7 +1024,7 @@ public class SslHandler extends ByteToMessageDecoder implements
ChannelOutboundH
- }
-
- int newTotalLength = totalLength + packetLength;
-- if (newTotalLength >
ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) {
-+ if (newTotalLength > MAX_ENCRYPTED_PACKET_LENGTH) {
- // Don't read too much.
- break;
- }
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
b/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
-deleted file mode 100644
-index aff0949..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
-+++ /dev/null
-@@ -1,65 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl.ocsp;
--
--import io.netty.channel.ChannelHandlerContext;
--import io.netty.channel.ChannelInboundHandlerAdapter;
--import io.netty.handler.ssl.ReferenceCountedOpenSslContext;
--import io.netty.handler.ssl.ReferenceCountedOpenSslEngine;
--import io.netty.handler.ssl.SslHandshakeCompletionEvent;
--import io.netty.util.internal.ObjectUtil;
--import io.netty.util.internal.ThrowableUtil;
--import io.netty.util.internal.UnstableApi;
+- return newResultMayFinishHandshake(status, bytesConsumed,
bytesProduced);
+- } finally {
+- SSL.bioClearByteBuffer(networkBIO);
+- if (bioReadCopyBuf == null) {
+- dst.position(dst.position() + bytesProduced);
+- } else {
+- assert bioReadCopyBuf.readableBytes() <= dst.remaining() :
"The destination buffer " + dst +
+- " didn't have enough remaining space to hold the
encrypted content in " + bioReadCopyBuf;
+-
dst.put(bioReadCopyBuf.internalNioBuffer(bioReadCopyBuf.readerIndex(), bytesProduced));
+- bioReadCopyBuf.release();
+- }
+- }
+- }
+- }
-
--import javax.net.ssl.SSLHandshakeException;
+- private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int
bytesConsumed, int bytesProduced) {
+- return newResult(OK, hs, bytesConsumed, bytesProduced);
+- }
-
--/**
-- * A handler for SSL clients to handle and act upon stapled OCSP responses.
-- *
-- * @see ReferenceCountedOpenSslContext#enableOcsp()
-- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
-- */
--@UnstableApi
--public abstract class OcspClientHandler extends ChannelInboundHandlerAdapter {
+- private SSLEngineResult newResult(SSLEngineResult.Status status,
SSLEngineResult.HandshakeStatus hs,
+- int bytesConsumed, int bytesProduced) {
+- // If isOutboundDone, then the data from the network BIO
+- // was the close_notify message and all was consumed we are not required to
wait
+- // for the receipt the peer's close_notify message -- shutdown.
+- if (isOutboundDone()) {
+- if (isInboundDone()) {
+- // If the inbound was done as well, we need to ensure we return
NOT_HANDSHAKING to signal we are done.
+- hs = NOT_HANDSHAKING;
-
-- private static final SSLHandshakeException OCSP_VERIFICATION_EXCEPTION =
ThrowableUtil.unknownStackTrace(
-- new SSLHandshakeException("Bad OCSP response"),
OcspClientHandler.class, "verify(...)");
+- // As the inbound and the outbound is done we can shutdown the engine
now.
+- shutdown();
+- }
+- return new SSLEngineResult(CLOSED, hs, bytesConsumed, bytesProduced);
+- }
+- if (hs == NEED_TASK) {
+- // Set needTask to true so getHandshakeStatus() will return the correct
value.
+- needTask = true;
+- }
+- return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced);
+- }
-
-- private final ReferenceCountedOpenSslEngine engine;
+- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus
hs,
+- int bytesConsumed, int
bytesProduced) throws SSLException {
+- return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() :
FINISHED),
+- bytesConsumed, bytesProduced);
+- }
-
-- protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) {
-- this.engine = ObjectUtil.checkNotNull(engine, "engine");
+- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status,
+- SSLEngineResult.HandshakeStatus
hs,
+- int bytesConsumed, int
bytesProduced) throws SSLException {
+- return newResult(status, mayFinishHandshake(hs != FINISHED ?
getHandshakeStatus() : FINISHED),
+- bytesConsumed, bytesProduced);
- }
-
- /**
-- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
+- * Log the error, shutdown the engine and throw an exception.
- */
-- protected abstract boolean verify(ChannelHandlerContext ctx,
ReferenceCountedOpenSslEngine engine) throws Exception;
+- private SSLException shutdownWithError(String operations, int sslError) {
+- return shutdownWithError(operations, sslError, SSL.getLastErrorNumber());
+- }
-
-- @Override
-- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws
Exception {
-- if (evt instanceof SslHandshakeCompletionEvent) {
-- ctx.pipeline().remove(this);
+- private SSLException shutdownWithError(String operation, int sslError, int error) {
+- String errorString = SSL.getErrorString(error);
+- if (logger.isDebugEnabled()) {
+- logger.debug("{} failed with {}: OpenSSL error: {} {}",
+- operation, sslError, error, errorString);
+- }
-
-- SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt;
-- if (event.isSuccess() && !verify(ctx, engine)) {
-- throw OCSP_VERIFICATION_EXCEPTION;
-- }
+- // There was an internal error -- shutdown
+- shutdown();
+- if (handshakeState == HandshakeState.FINISHED) {
+- return new SSLException(errorString);
- }
-
-- ctx.fireUserEventTriggered(evt);
+- SSLHandshakeException exception = new SSLHandshakeException(errorString);
+- // If we have a handshakeException stored already we should include it as well
to help the user debug things.
+- if (pendingException != null) {
+- exception.initCause(pendingException);
+- pendingException = null;
+- }
+- return exception;
- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
b/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
-deleted file mode 100644
-index 2883ff4..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
-+++ /dev/null
-@@ -1,23 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
-
--/**
-- * <a
href="https://en.wikipedia.org/wiki/OCSP_stapling">OCSP
stapling</a>,
-- * formally known as the TLS Certificate Status Request extension, is an
-- * alternative approach to the Online Certificate Status Protocol (OCSP)
-- * for checking the revocation status of X.509 digital certificates.
-- */
--package io.netty.handler.ssl.ocsp;
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java
b/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java
-deleted file mode 100644
-index d696d6b..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java
-+++ /dev/null
-@@ -1,108 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
+- public final SSLEngineResult unwrap(
+- final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
+- final ByteBuffer[] dsts, int dstsOffset, final int dstsLength) throws
SSLException {
+-
+- // Throw required runtime exceptions
+- ObjectUtil.checkNotNull(srcs, "srcs");
+- if (srcsOffset >= srcs.length
+- || srcsOffset + srcsLength > srcs.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + srcsOffset + ", length: " +
srcsLength +
+- " (expected: offset <= offset + length <=
srcs.length (" + srcs.length + "))");
+- }
+- if (dsts == null) {
+- throw new IllegalArgumentException("dsts is null");
+- }
+- if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + dstsOffset + ", length: " +
dstsLength +
+- " (expected: offset <= offset + length <=
dsts.length (" + dsts.length + "))");
+- }
+- long capacity = 0;
+- final int dstsEndOffset = dstsOffset + dstsLength;
+- for (int i = dstsOffset; i < dstsEndOffset; i ++) {
+- ByteBuffer dst = dsts[i];
+- if (dst == null) {
+- throw new IllegalArgumentException("dsts[" + i + "] is
null");
+- }
+- if (dst.isReadOnly()) {
+- throw new ReadOnlyBufferException();
+- }
+- capacity += dst.remaining();
+- }
-
--import org.junit.BeforeClass;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
+- final int srcsEndOffset = srcsOffset + srcsLength;
+- long len = 0;
+- for (int i = srcsOffset; i < srcsEndOffset; i++) {
+- ByteBuffer src = srcs[i];
+- if (src == null) {
+- throw new IllegalArgumentException("srcs[" + i + "] is
null");
+- }
+- len += src.remaining();
+- }
-
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
+- synchronized (this) {
+- if (isInboundDone()) {
+- return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING :
NEED_WRAP_CLOSED;
+- }
+-
+- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
+- // Prepare OpenSSL to work in server mode and receive handshake
+- if (handshakeState != HandshakeState.FINISHED) {
+- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
+- // Update accepted so we know we triggered the handshake via wrap
+- handshakeState = HandshakeState.STARTED_IMPLICITLY;
+- }
+-
+- status = handshake();
+-
+- if (status == NEED_TASK) {
+- return newResult(status, 0, 0);
+- }
+-
+- if (status == NEED_WRAP) {
+- return NEED_WRAP_OK;
+- }
+- // Check if the inbound is considered to be closed if so let us try to
wrap again.
+- if (isInboundDone) {
+- return NEED_WRAP_CLOSED;
+- }
+- }
+-
+- int sslPending = sslPending0();
+- int packetLength;
+- // The JDK implies that only a single SSL packet should be processed per
unwrap call [1]. If we are in
+- // JDK compatibility mode then we should honor this, but if not we just wrap
as much as possible. If there
+- // are multiple records or partial records this may reduce thrashing events
through the pipeline.
+- // [1]
https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html
+- if (jdkCompatibilityMode) {
+- if (len < SSL_RECORD_HEADER_LENGTH) {
+- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- }
+-
+- packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset);
+- if (packetLength == SslUtils.NOT_ENCRYPTED) {
+- throw new NotSslRecordException("not an SSL/TLS record");
+- }
+-
+- final int packetLengthDataOnly = packetLength -
SSL_RECORD_HEADER_LENGTH;
+- if (packetLengthDataOnly > capacity) {
+- // Not enough space in the destination buffer so signal the caller
that the buffer needs to be
+- // increased.
+- if (packetLengthDataOnly > MAX_RECORD_SIZE) {
+- // The packet length MUST NOT exceed 2^14 [1]. However we do
accommodate more data to support
+- // legacy use cases which may violate this condition (e.g.
OpenJDK's SslEngineImpl). If the max
+- // length is exceeded we fail fast here to avoid an infinite
loop due to the fact that we
+- // won't allocate a buffer large enough.
+- // [1]
https://tools.ietf.org/html/rfc5246#section-6.2.1
+- throw new SSLException("Illegal packet length: " +
packetLengthDataOnly + " > " +
+- session.getApplicationBufferSize());
+- } else {
+- session.tryExpandApplicationBufferSize(packetLengthDataOnly);
+- }
+- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
+- }
+-
+- if (len < packetLength) {
+- // We either don't have enough data to read the packet length or
not enough for reading the whole
+- // packet.
+- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- }
+- } else if (len == 0 && sslPending <= 0) {
+- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- } else if (capacity == 0) {
+- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
+- } else {
+- packetLength = (int) min(MAX_VALUE, len);
+- }
+-
+- // This must always be the case when we reached here as if not we returned
BUFFER_UNDERFLOW.
+- assert srcsOffset < srcsEndOffset;
+-
+- // This must always be the case if we reached here.
+- assert capacity > 0;
+-
+- // Number of produced bytes
+- int bytesProduced = 0;
+- int bytesConsumed = 0;
+- try {
+- srcLoop:
+- for (;;) {
+- ByteBuffer src = srcs[srcsOffset];
+- int remaining = src.remaining();
+- final ByteBuf bioWriteCopyBuf;
+- int pendingEncryptedBytes;
+- if (remaining == 0) {
+- if (sslPending <= 0) {
+- // We must skip empty buffers as BIO_write will return 0 if
asked to write something
+- // with length 0.
+- if (++srcsOffset >= srcsEndOffset) {
+- break;
+- }
+- continue;
+- } else {
+- bioWriteCopyBuf = null;
+- pendingEncryptedBytes =
SSL.bioLengthByteBuffer(networkBIO);
+- }
+- } else {
+- // Write more encrypted data into the BIO. Ensure we only read
one packet at a time as
+- // stated in the SSLEngine javadocs.
+- pendingEncryptedBytes = min(packetLength, remaining);
+- bioWriteCopyBuf = writeEncryptedData(src,
pendingEncryptedBytes);
+- }
+- try {
+- for (;;) {
+- ByteBuffer dst = dsts[dstsOffset];
+- if (!dst.hasRemaining()) {
+- // No space left in the destination buffer, skip it.
+- if (++dstsOffset >= dstsEndOffset) {
+- break srcLoop;
+- }
+- continue;
+- }
+-
+- int bytesRead = readPlaintextData(dst);
+- // We are directly using the ByteBuffer memory for the
write, and so we only know what has
+- // been consumed after we let SSL decrypt the data. At this
point we should update the
+- // number of bytes consumed, update the ByteBuffer position,
and release temp ByteBuf.
+- int localBytesConsumed = pendingEncryptedBytes -
SSL.bioLengthByteBuffer(networkBIO);
+- bytesConsumed += localBytesConsumed;
+- packetLength -= localBytesConsumed;
+- pendingEncryptedBytes -= localBytesConsumed;
+- src.position(src.position() + localBytesConsumed);
+-
+- if (bytesRead > 0) {
+- bytesProduced += bytesRead;
+-
+- if (!dst.hasRemaining()) {
+- sslPending = sslPending0();
+- // Move to the next dst buffer as this one is full.
+- if (++dstsOffset >= dstsEndOffset) {
+- return sslPending > 0 ?
+- newResult(BUFFER_OVERFLOW, status,
bytesConsumed, bytesProduced) :
+-
newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
+-
bytesConsumed, bytesProduced);
+- }
+- } else if (packetLength == 0 || jdkCompatibilityMode) {
+- // We either consumed all data or we are in
jdkCompatibilityMode and have consumed
+- // a single TLS packet and should stop consuming
until this method is called again.
+- break srcLoop;
+- }
+- } else {
+- int sslError = SSL.getError(ssl, bytesRead);
+- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError ==
SSL.SSL_ERROR_WANT_WRITE) {
+- // break to the outer loop as we want to read more
data which means we need to
+- // write more to the BIO.
+- break;
+- } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
+- // This means the connection was shutdown correctly,
close inbound and outbound
+- if (!receivedShutdown) {
+- closeAll();
+- }
+- return newResultMayFinishHandshake(isInboundDone() ?
CLOSED : OK, status,
+- bytesConsumed, bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP
||
+- sslError ==
SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
+- sslError ==
SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
+- return newResult(isInboundDone() ? CLOSED : OK,
+- NEED_TASK, bytesConsumed, bytesProduced);
+- } else {
+- return sslReadErrorResult(sslError,
SSL.getLastErrorNumber(), bytesConsumed,
+- bytesProduced);
+- }
+- }
+- }
-
--import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
--import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED;
--import static org.junit.Assume.assumeTrue;
+- if (++srcsOffset >= srcsEndOffset) {
+- break;
+- }
+- } finally {
+- if (bioWriteCopyBuf != null) {
+- bioWriteCopyBuf.release();
+- }
+- }
+- }
+- } finally {
+- SSL.bioClearByteBuffer(networkBIO);
+- rejectRemoteInitiatedRenegotiation();
+- }
-
--(a)RunWith(Parameterized.class)
--public class JdkOpenSslEngineInteroptTest extends SSLEngineTest {
+- // Check to see if we received a close_notify message from the peer.
+- if (!receivedShutdown && (SSL.getShutdown(ssl) &
SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
+- closeAll();
+- }
-
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
+- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
bytesConsumed, bytesProduced);
- }
-- return params;
- }
-
-- public JdkOpenSslEngineInteroptTest(BufferType type) {
-- super(type);
+- private SSLEngineResult sslReadErrorResult(int error, int stackError, int
bytesConsumed, int bytesProduced)
+- throws SSLException {
+- // Check if we have a pending handshakeException and if so see if we need to
consume all pending data from the
+- // BIO first or can just shutdown and throw it now.
+- // This is needed so we ensure close_notify etc is correctly send to the remote
peer.
+- // See
https://github.com/netty/netty/issues/3900
+- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
+- // we seems to have data left that needs to be transferred and so the user
needs
+- // call wrap(...). Store the error so we can pick it up later.
+- String message = SSL.getErrorString(stackError);
+- SSLException exception = handshakeState == HandshakeState.FINISHED ?
+- new SSLException(message) : new SSLHandshakeException(message);
+- if (pendingException == null) {
+- pendingException = exception;
+- } else {
+- ThrowableUtil.addSuppressed(pendingException, exception);
+- }
+- // We need to clear all errors so we not pick up anything that was left on
the stack on the next
+- // operation. Note that shutdownWithError(...) will cleanup the stack as
well so its only needed here.
+- SSL.clearError();
+- return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced);
+- }
+- throw shutdownWithError("SSL_read", error, stackError);
- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
+- private void closeAll() throws SSLException {
+- receivedShutdown = true;
+- closeOutbound();
+- closeInbound();
- }
-
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.JDK;
+- private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException {
+- // As rejectRemoteInitiatedRenegotiation() is called in a finally block we also
need to check if we shutdown
+- // the engine before as otherwise SSL.getHandshakeCount(ssl) will throw an NPE
if the passed in ssl is 0.
+- // See
https://github.com/netty/netty/issues/7353
+- if (!isDestroyed() && SSL.getHandshakeCount(ssl) > 1 &&
+- // As we may count multiple handshakes when TLSv1.3 is used we should just
ignore this here as
+- // renegotiation is not supported in TLSv1.3 as per spec.
+- !SslUtils.PROTOCOL_TLS_V1_3.equals(session.getProtocol()) &&
handshakeState == HandshakeState.FINISHED) {
+- // TODO: In future versions me may also want to send a fatal_alert to the
client and so notify it
+- // that the renegotiation failed.
+- shutdown();
+- throw new SSLHandshakeException("remote-initiated renegotiation not
allowed");
+- }
- }
-
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.OPENSSL;
+- public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[]
dsts) throws SSLException {
+- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth()
throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth();
+- private ByteBuffer[] singleSrcBuffer(ByteBuffer src) {
+- singleSrcBuffer[0] = src;
+- return singleSrcBuffer;
- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws
Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth();
+- private void resetSingleSrcBuffer() {
+- singleSrcBuffer[0] = null;
- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws
Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth();
+- private ByteBuffer[] singleDstBuffer(ByteBuffer src) {
+- singleDstBuffer[0] = src;
+- return singleDstBuffer;
- }
-
-- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws
Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth();
+- private void resetSingleDstBuffer() {
+- singleDstBuffer[0] = null;
- }
-
- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws
Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth();
+- public final synchronized SSLEngineResult unwrap(
+- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int
length) throws SSLException {
+- try {
+- return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length);
+- } finally {
+- resetSingleSrcBuffer();
+- }
- }
-
- @Override
-- protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) {
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine)
handler.engine();
-- engine.setVerify(SSL_CVERIFY_IGNORED, 1);
+- public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst)
throws SSLException {
+- try {
+- return wrap(singleSrcBuffer(src), dst);
+- } finally {
+- resetSingleSrcBuffer();
+- }
- }
-
- @Override
-- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) {
-- // TODO(scott): work around for a JDK issue. The exception should be
SSLHandshakeException.
-- return super.mySetupMutualAuthServerIsValidClientException(cause) ||
causedBySSLException(cause);
-- }
--}
-diff --git
a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java
b/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java
-deleted file mode 100644
-index 229e853..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java
-+++ /dev/null
-@@ -1,49 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.internal.tcnative.CertificateVerifier;
--import org.junit.Assert;
--import org.junit.Assume;
--import org.junit.BeforeClass;
--import org.junit.Test;
--
--import java.lang.reflect.Field;
--
--public class OpenSslCertificateExceptionTest {
--
-- @BeforeClass
-- public static void assumeOpenSsl() {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- }
--
-- @Test
-- public void testValidErrorCode() throws Exception {
-- Field[] fields = CertificateVerifier.class.getFields();
-- for (Field field : fields) {
-- if (field.isAccessible()) {
-- int errorCode = field.getInt(null);
-- OpenSslCertificateException exception = new
OpenSslCertificateException(errorCode);
-- Assert.assertEquals(errorCode, exception.errorCode());
-- }
+- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst)
throws SSLException {
+- try {
+- return unwrap(singleSrcBuffer(src), singleDstBuffer(dst));
+- } finally {
+- resetSingleSrcBuffer();
+- resetSingleDstBuffer();
- }
- }
-
-- @Test(expected = IllegalArgumentException.class)
-- public void testNonValidErrorCode() {
-- new OpenSslCertificateException(Integer.MIN_VALUE);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java
b/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java
-deleted file mode 100644
-index 6011cf7..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java
-+++ /dev/null
-@@ -1,38 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import org.junit.BeforeClass;
--
--import javax.net.ssl.SSLException;
--import java.io.File;
--
--import static org.junit.Assume.assumeTrue;
--
--public class OpenSslClientContextTest extends SslContextTest {
--
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
-- }
--
- @Override
-- protected SslContext newServerContext(File crtFile, File keyFile, String pass)
throws SSLException {
-- return new OpenSslClientContext(crtFile, InsecureTrustManagerFactory.INSTANCE,
crtFile, keyFile, pass,
-- null, null, IdentityCipherSuiteFilter.INSTANCE,
ApplicationProtocolConfig.DISABLED, 0, 0);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java
b/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java
-deleted file mode 100644
-index 5939b66..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java
-+++ /dev/null
-@@ -1,661 +0,0 @@
--/*
-- * Copyright 2015 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.buffer.UnpooledByteBufAllocator;
--import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.internal.PlatformDependent;
--import org.junit.Assume;
--import org.junit.BeforeClass;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.nio.ByteBuffer;
--import java.security.AlgorithmConstraints;
--import java.security.AlgorithmParameters;
--import java.security.CryptoPrimitive;
--import java.security.Key;
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--import java.util.Set;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLEngineResult;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLParameters;
--
--import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
--import static
io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH;
--import static
io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH;
--import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_PLAINTEXT_LENGTH;
--import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED;
--import static java.lang.Integer.MAX_VALUE;
--import static org.junit.Assert.assertEquals;
--import static org.junit.Assert.assertFalse;
--import static org.junit.Assert.assertNull;
--import static org.junit.Assert.assertSame;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class OpenSslEngineTest extends SSLEngineTest {
-- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL =
"my-protocol-http2";
-- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL =
"my-protocol-http1_1";
--
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
+- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts)
throws SSLException {
+- try {
+- return unwrap(singleSrcBuffer(src), dsts);
+- } finally {
+- resetSingleSrcBuffer();
- }
-- return params;
-- }
--
-- public OpenSslEngineTest(BufferType type) {
-- super(type);
-- }
--
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
- }
-
- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth()
throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth();
+- public final synchronized Runnable getDelegatedTask() {
+- if (isDestroyed()) {
+- return null;
+- }
+- final Runnable task = SSL.getTask(ssl);
+- if (task == null) {
+- return null;
+- }
+- return new Runnable() {
+- @Override
+- public void run() {
+- if (isDestroyed()) {
+- // The engine was destroyed in the meantime, just return.
+- return;
+- }
+- try {
+- task.run();
+- } finally {
+- // The task was run, reset needTask to false so getHandshakeStatus()
returns the correct value.
+- needTask = false;
+- }
+- }
+- };
- }
-
- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws
Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth();
-- }
+- public final synchronized void closeInbound() throws SSLException {
+- if (isInboundDone) {
+- return;
+- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws
Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth();
-- }
+- isInboundDone = true;
-
-- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws
Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth();
-- }
+- if (isOutboundDone()) {
+- // Only call shutdown if there is no outbound data pending.
+- // See
https://github.com/netty/netty/issues/6167
+- shutdown();
+- }
-
-- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws
Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth();
+- if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown)
{
+- throw new SSLException(
+- "Inbound closed before receiving peer's close_notify:
possible truncation attack?");
+- }
- }
-
- @Override
-- @Test
-- public void testClientHostnameValidationSuccess() throws InterruptedException,
SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationSuccess();
+- public final synchronized boolean isInboundDone() {
+- return isInboundDone;
- }
-
- @Override
-- @Test
-- public void testClientHostnameValidationFail() throws InterruptedException,
SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationFail();
-- }
--
-- @Test
-- public void testNpn() throws Exception {
-- ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
-- @Test
-- public void testAlpn() throws Exception {
-- assumeTrue(OpenSsl.isAlpnSupported());
-- ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
-- @Test
-- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
-- assumeTrue(OpenSsl.isAlpnSupported());
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- FALLBACK_APPLICATION_LEVEL_PROTOCOL,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL,
FALLBACK_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(serverApn, clientApn);
-- assertNull(serverException);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
-- @Test
-- public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception {
-- testEnablingAnAlreadyDisabledSslProtocol(new String[]{PROTOCOL_SSL_V2_HELLO},
-- new String[]{PROTOCOL_SSL_V2_HELLO, PROTOCOL_TLS_V1_2});
-- }
-- @Test
-- public void testWrapBuffersNoWritePendingError() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
--
-- ByteBuffer src = allocateBuffer(1024 * 10);
-- byte[] data = new byte[src.capacity()];
-- PlatformDependent.threadLocalRandom().nextBytes(data);
-- src.put(data).flip();
-- ByteBuffer dst = allocateBuffer(1);
-- // Try to wrap multiple times so we are more likely to hit the issue.
-- for (int i = 0; i < 100; i++) {
-- src.position(0);
-- dst.position(0);
-- assertSame(SSLEngineResult.Status.BUFFER_OVERFLOW,
clientEngine.wrap(src, dst).getStatus());
-- }
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
-- }
-- }
--
-- @Test
-- public void testOnlySmallBufferNeededForWrap() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
--
-- // Allocate a buffer which is small enough and set the limit to the capacity
to mark its whole content
-- // as readable.
-- int srcLen = 1024;
-- ByteBuffer src = allocateBuffer(srcLen);
--
-- ByteBuffer dstTooSmall = allocateBuffer(
-- src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH - 1);
-- ByteBuffer dst = allocateBuffer(
-- src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH);
--
-- // Check that we fail to wrap if the dst buffers capacity is not at least
-- // src.capacity() +
ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH
-- SSLEngineResult result = clientEngine.wrap(src, dstTooSmall);
-- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
-- assertEquals(0, result.bytesConsumed());
-- assertEquals(0, result.bytesProduced());
-- assertEquals(src.remaining(), src.capacity());
-- assertEquals(dst.remaining(), dst.capacity());
--
-- // Check that we can wrap with a dst buffer that has the capacity of
-- // src.capacity() +
ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH
-- result = clientEngine.wrap(src, dst);
-- assertEquals(SSLEngineResult.Status.OK, result.getStatus());
-- assertEquals(srcLen, result.bytesConsumed());
-- assertEquals(0, src.remaining());
-- assertTrue(result.bytesProduced() > srcLen);
-- assertEquals(src.capacity() - result.bytesConsumed(), src.remaining());
-- assertEquals(dst.capacity() - result.bytesProduced(), dst.remaining());
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
-- }
-- }
--
-- @Test
-- public void testNeededDstCapacityIsCorrectlyCalculated() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
--
-- ByteBuffer src = allocateBuffer(1024);
-- ByteBuffer src2 = src.duplicate();
--
-- ByteBuffer dst = allocateBuffer(src.capacity()
-- + MAX_TLS_RECORD_OVERHEAD_LENGTH);
--
-- SSLEngineResult result = clientEngine.wrap(new ByteBuffer[] { src, src2 },
dst);
-- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
-- assertEquals(0, src.position());
-- assertEquals(0, src2.position());
-- assertEquals(0, dst.position());
-- assertEquals(0, result.bytesConsumed());
-- assertEquals(0, result.bytesProduced());
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
-- }
-- }
--
-- @Test
-- public void testSrcsLenOverFlowCorrectlyHandled() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
+- public final synchronized void closeOutbound() {
+- if (outboundClosed) {
+- return;
+- }
-
-- ByteBuffer src = allocateBuffer(1024);
-- List<ByteBuffer> srcList = new ArrayList<ByteBuffer>();
-- long srcsLen = 0;
-- long maxLen = ((long) MAX_VALUE) * 2;
+- outboundClosed = true;
-
-- while (srcsLen < maxLen) {
-- ByteBuffer dup = src.duplicate();
-- srcList.add(dup);
-- srcsLen += dup.capacity();
+- if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) {
+- int mode = SSL.getShutdown(ssl);
+- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) {
+- doSSLShutdown();
- }
+- } else {
+- // engine closing before initial handshake
+- shutdown();
+- }
+- }
-
-- ByteBuffer[] srcs = srcList.toArray(new ByteBuffer[srcList.size()]);
--
-- ByteBuffer dst = allocateBuffer(MAX_ENCRYPTED_PACKET_LENGTH - 1);
--
-- SSLEngineResult result = clientEngine.wrap(srcs, dst);
-- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
--
-- for (ByteBuffer buffer : srcs) {
-- assertEquals(0, buffer.position());
+- /**
+- * Attempt to call {@link SSL#shutdownSSL(long)}.
+- * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not
attempted or returned an error.
+- */
+- private boolean doSSLShutdown() {
+- if (SSL.isInInit(ssl) != 0) {
+- // Only try to call SSL_shutdown if we are not in the init state anymore.
+- // Otherwise we will see 'error:140E0197:SSL
routines:SSL_shutdown:shutdown while in init' in our logs.
+- //
+- // See also
http://hg.nginx.org/nginx/rev/062c189fee20
+- return false;
+- }
+- int err = SSL.shutdownSSL(ssl);
+- if (err < 0) {
+- int sslErr = SSL.getError(ssl, err);
+- if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) {
+- if (logger.isDebugEnabled()) {
+- int error = SSL.getLastErrorNumber();
+- logger.debug("SSL_shutdown failed: OpenSSL error: {} {}",
error, SSL.getErrorString(error));
+- }
+- // There was an internal error -- shutdown
+- shutdown();
+- return false;
- }
-- assertEquals(0, dst.position());
-- assertEquals(0, result.bytesConsumed());
-- assertEquals(0, result.bytesProduced());
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
+- SSL.clearError();
- }
+- return true;
- }
-
-- @Test
-- public void testCalculateOutNetBufSizeOverflow() {
-- assertEquals(MAX_ENCRYPTED_PACKET_LENGTH,
-- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_VALUE, 1));
-- }
--
-- @Test
-- public void testCalculateOutNetBufSize0() {
-- assertEquals(MAX_TLS_RECORD_OVERHEAD_LENGTH,
-- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(0, 1));
+- @Override
+- public final synchronized boolean isOutboundDone() {
+- // Check if there is anything left in the outbound buffer.
+- // We need to ensure we only call SSL.pendingWrittenBytesInBIO(...) if the
engine was not destroyed yet.
+- return outboundClosed && (networkBIO == 0 ||
SSL.bioLengthNonApplication(networkBIO) == 0);
- }
-
-- @Test
-- public void testCalculateOutNetBufSizeMaxEncryptedPacketLength() {
-- assertEquals(MAX_ENCRYPTED_PACKET_LENGTH,
--
ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_ENCRYPTED_PACKET_LENGTH + 1,
2));
+- @Override
+- public final String[] getSupportedCipherSuites() {
+- return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[0]);
- }
-
- @Override
-- protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) {
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine)
handler.engine();
-- engine.setVerify(SSL_CVERIFY_IGNORED, 1);
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesTLSv1() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"ECDHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"DHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"DHE-RSA-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"AECDH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1,
"ECDHE-RSA-RC4-SHA");
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesTLSv1_1() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1,
"DES-CBC3-SHA");
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesTLSv1_2() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ECDHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"DHE-RSA-AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"DHE-RSA-AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ECDHE-RSA-AES256-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"AES256-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ECDHE-RSA-AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ECDHE-RSA-AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"DHE-RSA-AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"DHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ADH-AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ADH-AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"DHE-RSA-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"DHE-RSA-AES256-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"AECDH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ECDHE-RSA-AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ADH-AES256-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ADH-AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2,
"ECDHE-RSA-RC4-SHA");
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesSSLv3() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"DHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"DHE-RSA-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"AECDH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3,
"ECDHE-RSA-RC4-SHA");
-- }
--
-- private void testWrapWithDifferentSizes(String protocol, String cipher) throws
Exception {
-- assumeTrue(OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocol));
-- if (!OpenSsl.isCipherSuiteAvailable(cipher)) {
-- return;
+- public final String[] getEnabledCipherSuites() {
+- final String[] extraCiphers;
+- final String[] enabled;
+- synchronized (this) {
+- if (!isDestroyed()) {
+- enabled = SSL.getCiphers(ssl);
+- int opts = SSL.getOptions(ssl);
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, PROTOCOL_TLS_V1_3))
{
+- extraCiphers = OpenSsl.EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
+- } else {
+- extraCiphers = EmptyArrays.EMPTY_STRINGS;
+- }
+- } else {
+- return EmptyArrays.EMPTY_STRINGS;
+- }
- }
--
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- clientEngine.setEnabledCipherSuites(new String[] { cipher });
-- clientEngine.setEnabledProtocols(new String[] { protocol });
-- serverEngine.setEnabledCipherSuites(new String[] { cipher });
-- serverEngine.setEnabledProtocols(new String[] { protocol });
--
-- try {
-- handshake(clientEngine, serverEngine);
-- } catch (SSLException e) {
-- if (e.getMessage().contains("unsupported protocol")) {
-- Assume.assumeNoException(protocol + " not supported with cipher
" + cipher, e);
+- if (enabled == null) {
+- return EmptyArrays.EMPTY_STRINGS;
+- } else {
+- Set<String> enabledSet = new
LinkedHashSet<String>(enabled.length + extraCiphers.length);
+- synchronized (this) {
+- for (int i = 0; i < enabled.length; i++) {
+- String mapped = toJavaCipherSuite(enabled[i]);
+- final String cipher = mapped == null ? enabled[i] : mapped;
+- if (!OpenSsl.isTlsv13Supported() &&
SslUtils.isTLSv13Cipher(cipher)) {
+- continue;
+- }
+- enabledSet.add(cipher);
- }
-- throw e;
+- Collections.addAll(enabledSet, extraCiphers);
- }
--
-- int srcLen = 64;
-- do {
-- testWrapDstBigEnough(clientEngine, srcLen);
-- srcLen += 64;
-- } while (srcLen < MAX_PLAINTEXT_LENGTH);
--
-- testWrapDstBigEnough(clientEngine, MAX_PLAINTEXT_LENGTH);
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
+- return enabledSet.toArray(new String[0]);
- }
- }
-
-- private void testWrapDstBigEnough(SSLEngine engine, int srcLen) throws SSLException
{
-- ByteBuffer src = allocateBuffer(srcLen);
-- ByteBuffer dst = allocateBuffer(srcLen + MAX_TLS_RECORD_OVERHEAD_LENGTH);
--
-- SSLEngineResult result = engine.wrap(src, dst);
-- assertEquals(SSLEngineResult.Status.OK, result.getStatus());
-- int consumed = result.bytesConsumed();
-- int produced = result.bytesProduced();
-- assertEquals(srcLen, consumed);
-- assertTrue(produced > consumed);
+- @Override
+- public final void setEnabledCipherSuites(String[] cipherSuites) {
+- checkNotNull(cipherSuites, "cipherSuites");
-
-- dst.flip();
-- assertEquals(produced, dst.remaining());
-- assertFalse(src.hasRemaining());
-- }
+- final StringBuilder buf = new StringBuilder();
+- final StringBuilder bufTLSv13 = new StringBuilder();
-
-- @Test
-- public void testSNIMatchersDoesNotThrow() throws Exception {
-- assumeTrue(PlatformDependent.javaVersion() >= 8);
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
+- CipherSuiteConverter.convertToCipherStrings(Arrays.asList(cipherSuites), buf,
bufTLSv13, OpenSsl.isBoringSSL());
+- final String cipherSuiteSpec = buf.toString();
+- final String cipherSuiteSpecTLSv13 = bufTLSv13.toString();
-
-- SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- try {
-- SSLParameters parameters = new SSLParameters();
-- Java8SslTestUtils.setSNIMatcher(parameters);
-- engine.setSSLParameters(parameters);
-- } finally {
-- cleanupServerSslEngine(engine);
-- ssc.delete();
+- if (!OpenSsl.isTlsv13Supported() && !cipherSuiteSpecTLSv13.isEmpty()) {
+- throw new IllegalArgumentException("TLSv1.3 is not supported by this
java version.");
- }
-- }
--
-- @Test(expected = IllegalArgumentException.class)
-- public void testAlgorithmConstraintsThrows() throws Exception {
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- try {
-- SSLParameters parameters = new SSLParameters();
-- parameters.setAlgorithmConstraints(new AlgorithmConstraints() {
-- @Override
-- public boolean permits(
-- Set<CryptoPrimitive> primitives, String algorithm,
AlgorithmParameters parameters) {
-- return false;
-- }
+- synchronized (this) {
+- if (!isDestroyed()) {
+- // TODO: Should we also adjust the protocols based on if there are any
ciphers left that can be used
+- // for TLSv1.3 or for previor SSL/TLS versions ?
+- try {
+- // Set non TLSv1.3 ciphers.
+- SSL.setCipherSuites(ssl, cipherSuiteSpec, false);
-
-- @Override
-- public boolean permits(Set<CryptoPrimitive> primitives, Key key)
{
-- return false;
-- }
+- if (OpenSsl.isTlsv13Supported()) {
+- // Set TLSv1.3 ciphers.
+- SSL.setCipherSuites(ssl, cipherSuiteSpecTLSv13, true);
+- }
-
-- @Override
-- public boolean permits(
-- Set<CryptoPrimitive> primitives, String algorithm, Key
key, AlgorithmParameters parameters) {
-- return false;
+- } catch (Exception e) {
+- throw new IllegalStateException("failed to enable cipher
suites: " + cipherSuiteSpec, e);
- }
-- });
-- engine.setSSLParameters(parameters);
-- } finally {
-- cleanupServerSslEngine(engine);
-- ssc.delete();
+- } else {
+- throw new IllegalStateException("failed to enable cipher suites:
" + cipherSuiteSpec);
+- }
- }
- }
-
- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.OPENSSL;
+- public final String[] getSupportedProtocols() {
+- return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[0]);
- }
-
- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.OPENSSL;
-- }
--
-- private static ApplicationProtocolConfig acceptingNegotiator(Protocol protocol,
-- String... supportedProtocols) {
-- return new ApplicationProtocolConfig(protocol,
-- SelectorFailureBehavior.NO_ADVERTISE,
-- SelectedListenerFailureBehavior.ACCEPT,
-- supportedProtocols);
-- }
--}
-diff --git
a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java
b/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java
-deleted file mode 100644
-index f63a16f..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java
-+++ /dev/null
-@@ -1,114 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import org.junit.BeforeClass;
--import org.junit.Ignore;
--import org.junit.Test;
--
--import javax.net.ssl.SSLException;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--
--import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest {
+- public final String[] getEnabledProtocols() {
+- List<String> enabled = new ArrayList<String>(6);
+- // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is
always enabled
+- enabled.add(PROTOCOL_SSL_V2_HELLO);
-
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
+- int opts;
+- synchronized (this) {
+- if (!isDestroyed()) {
+- opts = SSL.getOptions(ssl);
+- } else {
+- return enabled.toArray(new String[0]);
+- }
- }
-- return params;
-- }
--
-- public OpenSslJdkSslEngineInteroptTest(BufferType type) {
-- super(type);
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, PROTOCOL_TLS_V1)) {
+- enabled.add(PROTOCOL_TLS_V1);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, PROTOCOL_TLS_V1_1)) {
+- enabled.add(PROTOCOL_TLS_V1_1);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, PROTOCOL_TLS_V1_2)) {
+- enabled.add(PROTOCOL_TLS_V1_2);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, PROTOCOL_TLS_V1_3)) {
+- enabled.add(PROTOCOL_TLS_V1_3);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, PROTOCOL_SSL_V2)) {
+- enabled.add(PROTOCOL_SSL_V2);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, PROTOCOL_SSL_V3)) {
+- enabled.add(PROTOCOL_SSL_V3);
+- }
+- return enabled.toArray(new String[0]);
- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
+- private static boolean isProtocolEnabled(int opts, int disableMask, String
protocolString) {
+- // We also need to check if the actual protocolString is supported as depending
on the openssl API
+- // implementations it may use a disableMask of 0 (BoringSSL is doing this for
example).
+- return (opts & disableMask) == 0 &&
OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString);
- }
-
+- /**
+- * {@inheritDoc}
+- * TLS doesn't support a way to advertise non-contiguous versions from the
client's perspective, and the client
+- * just advertises the max supported version. The TLS protocol also doesn't
support all different combinations of
+- * discrete protocols, and instead assumes contiguous ranges. OpenSSL has some
unexpected behavior
+- * (e.g. handshake failures) if non-contiguous protocols are used even where there
is a compatible set of protocols
+- * and ciphers. For these reasons this method will determine the minimum protocol
and the maximum protocol and
+- * enabled a contiguous range from [min protocol, max protocol] in OpenSSL.
+- */
- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.OPENSSL;
-- }
+- public final void setEnabledProtocols(String[] protocols) {
+- if (protocols == null) {
+- // This is correct from the API docs
+- throw new IllegalArgumentException();
+- }
+- int minProtocolIndex = OPENSSL_OP_NO_PROTOCOLS.length;
+- int maxProtocolIndex = 0;
+- for (String p: protocols) {
+- if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) {
+- throw new IllegalArgumentException("Protocol " + p + " is
not supported.");
+- }
+- if (p.equals(PROTOCOL_SSL_V2)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
+- }
+- } else if (p.equals(PROTOCOL_SSL_V3)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1_1)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1_2)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1_3)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3;
+- }
+- }
+- }
+- synchronized (this) {
+- if (!isDestroyed()) {
+- // Clear out options which disable protocols
+- SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 |
SSL.SSL_OP_NO_TLSv1 |
+- SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2 |
SSL.SSL_OP_NO_TLSv1_3);
-
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.JDK;
-- }
+- int opts = 0;
+- for (int i = 0; i < minProtocolIndex; ++i) {
+- opts |= OPENSSL_OP_NO_PROTOCOLS[i];
+- }
+- assert maxProtocolIndex != MAX_VALUE;
+- for (int i = maxProtocolIndex + 1; i <
OPENSSL_OP_NO_PROTOCOLS.length; ++i) {
+- opts |= OPENSSL_OP_NO_PROTOCOLS[i];
+- }
-
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
-- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws
Exception {
+- // Disable protocols we do not want
+- SSL.setOptions(ssl, opts);
+- } else {
+- throw new IllegalStateException("failed to enable protocols: "
+ Arrays.asList(protocols));
+- }
+- }
- }
-
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws
Exception {
+- public final SSLSession getSession() {
+- return session;
- }
-
- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth()
throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth();
-- }
+- public final synchronized void beginHandshake() throws SSLException {
+- switch (handshakeState) {
+- case STARTED_IMPLICITLY:
+- checkEngineClosed();
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws
Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth();
-- }
+- // A user did not start handshake by calling this method by
him/herself,
+- // but handshake has been started already by wrap() or unwrap()
implicitly.
+- // Because it's the user's first time to call this method, it is
unfair to
+- // raise an exception. From the user's standpoint, he or she never
asked
+- // for renegotiation.
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws
Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth();
+- handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this
method is invoked by the user,
+- calculateMaxWrapOverhead();
+- // we should raise an exception.
+- break;
+- case STARTED_EXPLICITLY:
+- // Nothing to do as the handshake is not done yet.
+- break;
+- case FINISHED:
+- throw new SSLException("renegotiation unsupported");
+- case NOT_STARTED:
+- handshakeState = HandshakeState.STARTED_EXPLICITLY;
+- if (handshake() == NEED_TASK) {
+- // Set needTask to true so getHandshakeStatus() will return the
correct value.
+- needTask = true;
+- }
+- calculateMaxWrapOverhead();
+- break;
+- default:
+- throw new Error();
+- }
- }
-
-- @Override
-- @Test
-- public void testClientHostnameValidationSuccess() throws InterruptedException,
SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationSuccess();
+- private void checkEngineClosed() throws SSLException {
+- if (isDestroyed()) {
+- throw new SSLException("engine closed");
+- }
- }
-
-- @Override
-- @Test
-- public void testClientHostnameValidationFail() throws InterruptedException,
SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationFail();
+- private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingStatus) {
+- // Depending on if there is something left in the BIO we need to WRAP or UNWRAP
+- return pendingStatus > 0 ? NEED_WRAP : NEED_UNWRAP;
- }
-
-- @Override
-- protected boolean mySetupMutualAuthServerIsValidServerException(Throwable cause) {
-- // TODO(scott): work around for a JDK issue. The exception should be
SSLHandshakeException.
-- return super.mySetupMutualAuthServerIsValidServerException(cause) ||
causedBySSLException(cause);
+- private static boolean isEmpty(Object[] arr) {
+- return arr == null || arr.length == 0;
- }
--}
-diff --git
a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java
b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java
-deleted file mode 100644
-index 3959e64..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java
-+++ /dev/null
-@@ -1,23 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--public class OpenSslRenegotiateSmallBIOTest extends OpenSslRenegotiateTest {
-- @Override
-- protected void initSslServerContext(SslContext context) {
-- ((ReferenceCountedOpenSslContext) context).setBioNonApplicationBufferSize(1);
+- private static boolean isEmpty(byte[] cert) {
+- return cert == null || cert.length == 0;
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java
b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java
-deleted file mode 100644
-index 8f3dfee..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java
-+++ /dev/null
-@@ -1,36 +0,0 @@
--/*
-- * Copyright 2015 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import org.junit.BeforeClass;
+- private SSLEngineResult.HandshakeStatus handshakeException() throws SSLException {
+- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
+- // There is something pending, we need to consume it first via a WRAP so we
don't loose anything.
+- return NEED_WRAP;
+- }
+-
+- Throwable exception = pendingException;
+- assert exception != null;
+- pendingException = null;
+- shutdown();
+- if (exception instanceof SSLHandshakeException) {
+- throw (SSLHandshakeException) exception;
+- }
+- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine
problem");
+- e.initCause(exception);
+- throw e;
+- }
-
--import static org.junit.Assume.assumeFalse;
--import static org.junit.Assume.assumeTrue;
+- /**
+- * Should be called if the handshake will be failed due a callback that throws an
exception.
+- * This cause will then be used to give more details as part of the {@link
SSLHandshakeException}.
+- */
+- final void initHandshakeException(Throwable cause) {
+- if (pendingException == null) {
+- pendingException = cause;
+- } else {
+- ThrowableUtil.addSuppressed(pendingException, cause);
+- }
+- }
-
--public class OpenSslRenegotiateTest extends RenegotiateTest {
+- private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
+- if (needTask) {
+- return NEED_TASK;
+- }
+- if (handshakeState == HandshakeState.FINISHED) {
+- return FINISHED;
+- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
-- // BoringSSL does not support renegotiation intentionally.
-- assumeFalse("BoringSSL".equals(OpenSsl.versionString()));
-- }
+- checkEngineClosed();
-
-- @Override
-- protected SslProvider serverSslProvider() {
-- return SslProvider.OPENSSL;
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java
b/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java
-deleted file mode 100644
-index f22d045..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java
-+++ /dev/null
-@@ -1,39 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
+- if (pendingException != null) {
+- // Let's call SSL.doHandshake(...) again in case there is some async
operation pending that would fill the
+- // outbound buffer.
+- if (SSL.doHandshake(ssl) <= 0) {
+- // Clear any error that was put on the stack by the handshake
+- SSL.clearError();
+- }
+- return handshakeException();
+- }
-
--package io.netty.handler.ssl;
+- // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the
AbstractCertificateVerifier.
+- engineMap.add(this);
+- if (lastAccessed == -1) {
+- lastAccessed = System.currentTimeMillis();
+- }
-
--import org.junit.Assume;
--import org.junit.BeforeClass;
+- int code = SSL.doHandshake(ssl);
+- if (code <= 0) {
+- int sslError = SSL.getError(ssl, code);
+- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError ==
SSL.SSL_ERROR_WANT_WRITE) {
+- return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
+- }
-
--import javax.net.ssl.SSLException;
--import java.io.File;
+- if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
+- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
+- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
+- return NEED_TASK;
+- }
-
--import static org.junit.Assume.assumeTrue;
+- // Check if we have a pending exception that was created during the
handshake and if so throw it after
+- // shutdown the connection.
+- if (pendingException != null) {
+- return handshakeException();
+- }
-
--public class OpenSslServerContextTest extends SslContextTest {
+- // Everything else is considered as error
+- throw shutdownWithError("SSL_do_handshake", sslError);
+- }
+- // We have produced more data as part of the handshake if this is the case the
user should call wrap(...)
+- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
+- return NEED_WRAP;
+- }
+- // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means
the handshake was finished.
+- session.handshakeFinished();
+- return FINISHED;
+- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
+- private SSLEngineResult.HandshakeStatus
mayFinishHandshake(SSLEngineResult.HandshakeStatus status)
+- throws SSLException {
+- if (status == NOT_HANDSHAKING && handshakeState !=
HandshakeState.FINISHED) {
+- // If the status was NOT_HANDSHAKING and we not finished the handshake we
need to call
+- // SSL_do_handshake() again
+- return handshake();
+- }
+- return status;
- }
-
- @Override
-- protected SslContext newServerContext(File crtFile, File keyFile, String pass)
throws SSLException {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- return new OpenSslServerContext(crtFile, keyFile, pass);
+- public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
+- // Check if we are in the initial handshake phase or shutdown phase
+- if (needPendingStatus()) {
+- if (needTask) {
+- // There is a task outstanding
+- return NEED_TASK;
+- }
+- return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
+- }
+- return NOT_HANDSHAKING;
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java
b/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java
-deleted file mode 100644
-index 7882a61..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java
-+++ /dev/null
-@@ -1,27 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import static org.junit.Assume.assumeTrue;
--
--final class OpenSslTestUtils {
-- private OpenSslTestUtils() {
+- private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
+- // Check if we are in the initial handshake phase or shutdown phase
+- if (needPendingStatus()) {
+- if (needTask) {
+- // There is a task outstanding
+- return NEED_TASK;
+- }
+- return pendingStatus(pending);
+- }
+- return NOT_HANDSHAKING;
- }
-
-- static void checkShouldUseKeyManagerFactory() {
-- assumeTrue(OpenSsl.supportsKeyManagerFactory() &&
OpenSsl.useKeyManagerFactory());
+- private boolean needPendingStatus() {
+- return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()
+- && (handshakeState != HandshakeState.FINISHED || isInboundDone()
|| isOutboundDone());
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java
b/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java
-deleted file mode 100644
-index 793f772..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java
-+++ /dev/null
-@@ -1,95 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
-
--package io.netty.handler.ssl;
+- /**
+- * Converts the specified OpenSSL cipher suite to the Java cipher suite.
+- */
+- private String toJavaCipherSuite(String openSslCipherSuite) {
+- if (openSslCipherSuite == null) {
+- return null;
+- }
-
--import static org.junit.Assert.assertEquals;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeFalse;
--import static org.junit.Assume.assumeTrue;
+- String version = SSL.getVersion(ssl);
+- String prefix = toJavaCipherSuitePrefix(version);
+- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix);
+- }
-
--import java.io.ByteArrayOutputStream;
--import java.io.File;
--import java.io.FileInputStream;
+- /**
+- * Converts the protocol version string returned by {@link SSL#getVersion(long)} to
protocol family string.
+- */
+- private static String toJavaCipherSuitePrefix(String protocolVersion) {
+- final char c;
+- if (protocolVersion == null || protocolVersion.isEmpty()) {
+- c = 0;
+- } else {
+- c = protocolVersion.charAt(0);
+- }
-
--import org.junit.Test;
+- switch (c) {
+- case 'T':
+- return "TLS";
+- case 'S':
+- return "SSL";
+- default:
+- return "UNKNOWN";
+- }
+- }
-
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.ReferenceCountUtil;
+- @Override
+- public final void setUseClientMode(boolean clientMode) {
+- if (clientMode != this.clientMode) {
+- throw new UnsupportedOperationException();
+- }
+- }
-
--public class PemEncodedTest {
+- @Override
+- public final boolean getUseClientMode() {
+- return clientMode;
+- }
-
-- @Test
-- public void testPemEncodedOpenSsl() throws Exception {
-- testPemEncoded(SslProvider.OPENSSL);
+- @Override
+- public final void setNeedClientAuth(boolean b) {
+- setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE);
- }
-
-- @Test
-- public void testPemEncodedOpenSslRef() throws Exception {
-- testPemEncoded(SslProvider.OPENSSL_REFCNT);
+- @Override
+- public final boolean getNeedClientAuth() {
+- return clientAuth == ClientAuth.REQUIRE;
- }
-
-- private static void testPemEncoded(SslProvider provider) throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- assumeFalse(OpenSsl.useKeyManagerFactory());
-- PemPrivateKey pemKey;
-- PemX509Certificate pemCert;
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- pemKey = PemPrivateKey.valueOf(toByteArray(ssc.privateKey()));
-- pemCert = PemX509Certificate.valueOf(toByteArray(ssc.certificate()));
-- } finally {
-- ssc.delete();
-- }
+- @Override
+- public final void setWantClientAuth(boolean b) {
+- setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE);
+- }
-
-- SslContext context = SslContextBuilder.forServer(pemKey, pemCert)
-- .sslProvider(provider)
-- .build();
-- assertEquals(1, pemKey.refCnt());
-- assertEquals(1, pemCert.refCnt());
-- try {
-- assertTrue(context instanceof ReferenceCountedOpenSslContext);
-- } finally {
-- ReferenceCountUtil.release(context);
-- assertRelease(pemKey);
-- assertRelease(pemCert);
-- }
+- @Override
+- public final boolean getWantClientAuth() {
+- return clientAuth == ClientAuth.OPTIONAL;
- }
-
-- private static void assertRelease(PemEncoded encoded) {
-- assertTrue(encoded.release());
+- /**
+- * See <a
href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html&...
and
+- * {@link SSL#setVerify(long, int, int)}.
+- */
+- @UnstableApi
+- public final synchronized void setVerify(int verifyMode, int depth) {
+- if (!isDestroyed()) {
+- SSL.setVerify(ssl, verifyMode, depth);
+- }
- }
-
-- private static byte[] toByteArray(File file) throws Exception {
-- FileInputStream in = new FileInputStream(file);
-- try {
-- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-- try {
-- byte[] buf = new byte[1024];
-- int len;
-- while ((len = in.read(buf)) != -1) {
-- baos.write(buf, 0, len);
+- private void setClientAuth(ClientAuth mode) {
+- if (clientMode) {
+- return;
+- }
+- synchronized (this) {
+- if (clientAuth == mode) {
+- // No need to issue any JNI calls if the mode is the same
+- return;
+- }
+- if (!isDestroyed()) {
+- switch (mode) {
+- case NONE:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE,
ReferenceCountedOpenSslContext.VERIFY_DEPTH);
+- break;
+- case REQUIRE:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED,
ReferenceCountedOpenSslContext.VERIFY_DEPTH);
+- break;
+- case OPTIONAL:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL,
ReferenceCountedOpenSslContext.VERIFY_DEPTH);
+- break;
+- default:
+- throw new Error(mode.toString());
- }
-- } finally {
-- baos.close();
- }
+- clientAuth = mode;
+- }
+- }
-
-- return baos.toByteArray();
-- } finally {
-- in.close();
+- @Override
+- public final void setEnableSessionCreation(boolean b) {
+- if (b) {
+- throw new UnsupportedOperationException();
- }
- }
--}
-diff --git
a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java
b/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java
-deleted file mode 100644
-index 6d38940..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java
-+++ /dev/null
-@@ -1,57 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import io.netty.util.ReferenceCountUtil;
+- @Override
+- public final boolean getEnableSessionCreation() {
+- return false;
+- }
-
--import javax.net.ssl.SSLEngine;
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- @Override
+- public final synchronized SSLParameters getSSLParameters() {
+- SSLParameters sslParameters = super.getSSLParameters();
+-
+- int version = PlatformDependent.javaVersion();
+- if (version >= 7) {
+-
sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
+- Java7SslParametersUtils.setAlgorithmConstraints(sslParameters,
algorithmConstraints);
+- if (version >= 8) {
+- if (sniHostNames != null) {
+- Java8SslUtils.setSniHostNames(sslParameters, sniHostNames);
+- }
+- if (!isDestroyed()) {
+- Java8SslUtils.setUseCipherSuitesOrder(
+- sslParameters, (SSL.getOptions(ssl) &
SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0);
+- }
+-
+- Java8SslUtils.setSNIMatchers(sslParameters, matchers);
+- }
+- }
+- return sslParameters;
+- }
-
--public class ReferenceCountedOpenSslEngineTest extends OpenSslEngineTest {
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- @Override
+- public final synchronized void setSSLParameters(SSLParameters sslParameters) {
+- int version = PlatformDependent.javaVersion();
+- if (version >= 7) {
+- if (sslParameters.getAlgorithmConstraints() != null) {
+- throw new IllegalArgumentException("AlgorithmConstraints are not
supported.");
+- }
-
-- public ReferenceCountedOpenSslEngineTest(BufferType type) {
-- super(type);
-- }
+- boolean isDestroyed = isDestroyed();
+- if (version >= 8) {
+- if (!isDestroyed) {
+- if (clientMode) {
+- final List<String> sniHostNames =
Java8SslUtils.getSniHostNames(sslParameters);
+- for (String name: sniHostNames) {
+- SSL.setTlsExtHostName(ssl, name);
+- }
+- this.sniHostNames = sniHostNames;
+- }
+- if (Java8SslUtils.getUseCipherSuitesOrder(sslParameters)) {
+- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
+- } else {
+- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
+- }
+- }
+- matchers = sslParameters.getSNIMatchers();
+- }
-
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.OPENSSL_REFCNT;
+- final String endPointIdentificationAlgorithm =
sslParameters.getEndpointIdentificationAlgorithm();
+- if (!isDestroyed) {
+- // If the user asks for hostname verification we must ensure we verify
the peer.
+- // If the user disables hostname verification we leave it up to the user
to change the mode manually.
+- if (clientMode &&
isEndPointVerificationEnabled(endPointIdentificationAlgorithm)) {
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1);
+- }
+- }
+- this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm;
+- algorithmConstraints = sslParameters.getAlgorithmConstraints();
+- }
+- super.setSSLParameters(sslParameters);
- }
-
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.OPENSSL_REFCNT;
+- private static boolean isEndPointVerificationEnabled(String
endPointIdentificationAlgorithm) {
+- return endPointIdentificationAlgorithm != null &&
!endPointIdentificationAlgorithm.isEmpty();
- }
-
-- @Override
-- protected void cleanupClientSslContext(SslContext ctx) {
-- ReferenceCountUtil.release(ctx);
+- private boolean isDestroyed() {
+- return destroyed;
- }
-
-- @Override
-- protected void cleanupClientSslEngine(SSLEngine engine) {
-- ReferenceCountUtil.release(engine);
+- final boolean checkSniHostnameMatch(byte[] hostname) {
+- return Java8SslUtils.checkSniHostnameMatch(matchers, hostname);
- }
-
- @Override
-- protected void cleanupServerSslContext(SslContext ctx) {
-- ReferenceCountUtil.release(ctx);
+- public String getNegotiatedApplicationProtocol() {
+- return applicationProtocol;
- }
-
-- @Override
-- protected void cleanupServerSslEngine(SSLEngine engine) {
-- ReferenceCountUtil.release(engine);
+- private static long bufferAddress(ByteBuffer b) {
+- assert b.isDirect();
+- if (PlatformDependent.hasUnsafe()) {
+- return PlatformDependent.directBufferAddress(b);
+- }
+- return Buffer.address(b);
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java
b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java
-deleted file mode 100644
-index 3193d20..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java
-+++ /dev/null
-@@ -1,161 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.DefaultEventLoopGroup;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.local.LocalAddress;
--import io.netty.channel.local.LocalChannel;
--import io.netty.channel.local.LocalServerChannel;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.Mapping;
--import io.netty.util.concurrent.Promise;
--import io.netty.util.internal.PlatformDependent;
--import org.junit.Assert;
--import org.junit.Assume;
--import org.junit.Test;
-
--import java.nio.channels.ClosedChannelException;
--
--public class SniClientTest {
--
-- @Test(timeout = 30000)
-- public void testSniClientJdkSslServerJdkSsl() throws Exception {
-- testSniClient(SslProvider.JDK, SslProvider.JDK);
-- }
+- private final class DefaultOpenSslSession implements OpenSslSession {
+- private final OpenSslSessionContext sessionContext;
-
-- @Test(timeout = 30000)
-- public void testSniClientOpenSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL);
-- }
+- // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished()
may be triggered by any
+- // thread.
+- private X509Certificate[] x509PeerCerts;
+- private Certificate[] peerCerts;
-
-- @Test(timeout = 30000)
-- public void testSniClientJdkSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testSniClient(SslProvider.JDK, SslProvider.OPENSSL);
-- }
+- private String protocol;
+- private String cipher;
+- private byte[] id;
+- private long creationTime;
+- private volatile int applicationBufferSize = MAX_PLAINTEXT_LENGTH;
-
-- @Test(timeout = 30000)
-- public void testSniClientOpenSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testSniClient(SslProvider.OPENSSL, SslProvider.JDK);
-- }
+- // lazy init for memory reasons
+- private Map<String, Object> values;
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientJdkSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, true);
-- }
+- DefaultOpenSslSession(OpenSslSessionContext sessionContext) {
+- this.sessionContext = sessionContext;
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientJdkSslServerJdkSsl() throws Exception
{
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, false);
-- }
+- private SSLSessionBindingEvent newSSLSessionBindingEvent(String name) {
+- return new SSLSessionBindingEvent(session, name);
+- }
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientOpenSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL,
true);
-- }
+- @Override
+- public byte[] getId() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (id == null) {
+- return EmptyArrays.EMPTY_BYTES;
+- }
+- return id.clone();
+- }
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientOpenSslServerOpenSsl() throws
Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL,
false);
-- }
+- @Override
+- public SSLSessionContext getSessionContext() {
+- return sessionContext;
+- }
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientJdkSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL,
true);
-- }
+- @Override
+- public long getCreationTime() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (creationTime == 0 && !isDestroyed()) {
+- creationTime = SSL.getTime(ssl) * 1000L;
+- }
+- }
+- return creationTime;
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientJdkSslServerOpenSsl() throws
Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL,
false);
-- }
+- @Override
+- public long getLastAccessedTime() {
+- long lastAccessed = ReferenceCountedOpenSslEngine.this.lastAccessed;
+- // if lastAccessed is -1 we will just return the creation time as the
handshake was not started yet.
+- return lastAccessed == -1 ? getCreationTime() : lastAccessed;
+- }
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientOpenSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK,
true);
-- }
+- @Override
+- public void invalidate() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- SSL.setTimeout(ssl, 0);
+- }
+- }
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientOpenSslServerJdkSsl() throws
Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK,
false);
-- }
+- @Override
+- public boolean isValid() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L)
< (SSL.getTime(ssl) * 1000L);
+- }
+- }
+- return false;
+- }
-
-- private static void testSniClient(SslProvider sslClientProvider, SslProvider
sslServerProvider) throws Exception {
-- final String sniHost = "sni.netty.io";
-- LocalAddress address = new LocalAddress("test");
-- EventLoopGroup group = new DefaultEventLoopGroup(1);
-- Channel sc = null;
-- Channel cc = null;
-- try {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- final SslContext sslServerContext = SslContextBuilder.forServer(cert.key(),
cert.cert())
-- .sslProvider(sslServerProvider).build();
+- @Override
+- public void putValue(String name, Object value) {
+- ObjectUtil.checkNotNull(name, "name");
+- ObjectUtil.checkNotNull(value, "value");
-
-- final Promise<String> promise = group.next().newPromise();
-- ServerBootstrap sb = new ServerBootstrap();
-- sc = sb.group(group).channel(LocalServerChannel.class).childHandler(new
ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addFirst(new SniHandler(new Mapping<String,
SslContext>() {
-- @Override
-- public SslContext map(String input) {
-- promise.setSuccess(input);
-- return sslServerContext;
-- }
-- }));
+- final Object old;
+- synchronized (this) {
+- Map<String, Object> values = this.values;
+- if (values == null) {
+- // Use size of 2 to keep the memory overhead small
+- values = this.values = new HashMap<String, Object>(2);
- }
-- }).bind(address).syncUninterruptibly().channel();
--
-- SslContext sslContext =
SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider).build();
-- Bootstrap cb = new Bootstrap();
-- cc = cb.group(group).channel(LocalChannel.class).handler(new SslHandler(
-- sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost, -1)))
-- .connect(address).syncUninterruptibly().channel();
-- Assert.assertEquals(sniHost, promise.syncUninterruptibly().getNow());
-- } finally {
-- if (cc != null) {
-- cc.close().syncUninterruptibly();
+- old = values.put(name, value);
- }
-- if (sc != null) {
-- sc.close().syncUninterruptibly();
+-
+- if (value instanceof SSLSessionBindingListener) {
+- // Use newSSLSessionBindingEvent so we alway use the wrapper if needed.
+- ((SSLSessionBindingListener)
value).valueBound(newSSLSessionBindingEvent(name));
- }
-- group.shutdownGracefully();
+- notifyUnbound(old, name);
- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java
b/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java
-deleted file mode 100644
-index 07c87c6..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java
-+++ /dev/null
-@@ -1,496 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
-
--package io.netty.handler.ssl;
+- @Override
+- public Object getValue(String name) {
+- ObjectUtil.checkNotNull(name, "name");
+- synchronized (this) {
+- if (values == null) {
+- return null;
+- }
+- return values.get(name);
+- }
+- }
-
--import static org.hamcrest.CoreMatchers.is;
--import static org.hamcrest.CoreMatchers.nullValue;
--import static org.junit.Assert.assertEquals;
--import static org.junit.Assert.assertThat;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeTrue;
+- @Override
+- public void removeValue(String name) {
+- ObjectUtil.checkNotNull(name, "name");
-
--import java.io.File;
--import java.net.InetSocketAddress;
--import java.util.ArrayList;
--import java.util.List;
--import java.util.concurrent.CountDownLatch;
--import java.util.concurrent.TimeUnit;
+- final Object old;
+- synchronized (this) {
+- Map<String, Object> values = this.values;
+- if (values == null) {
+- return;
+- }
+- old = values.remove(name);
+- }
-
--import javax.net.ssl.SSLEngine;
+- notifyUnbound(old, name);
+- }
-
--import org.junit.Test;
+- @Override
+- public String[] getValueNames() {
+- synchronized (this) {
+- Map<String, Object> values = this.values;
+- if (values == null || values.isEmpty()) {
+- return EmptyArrays.EMPTY_STRINGS;
+- }
+- return values.keySet().toArray(new String[0]);
+- }
+- }
-
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.buffer.Unpooled;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelFuture;
--import io.netty.channel.ChannelHandlerContext;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.ChannelPipeline;
--import io.netty.channel.DefaultEventLoopGroup;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.embedded.EmbeddedChannel;
--import io.netty.channel.local.LocalAddress;
--import io.netty.channel.local.LocalChannel;
--import io.netty.channel.local.LocalServerChannel;
--import io.netty.channel.nio.NioEventLoopGroup;
--import io.netty.channel.socket.nio.NioServerSocketChannel;
--import io.netty.channel.socket.nio.NioSocketChannel;
--import io.netty.handler.codec.DecoderException;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.DomainNameMapping;
--import io.netty.util.DomainNameMappingBuilder;
--import io.netty.util.Mapping;
--import io.netty.util.ReferenceCountUtil;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.concurrent.Promise;
--import io.netty.util.internal.ObjectUtil;
--import io.netty.util.internal.StringUtil;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
+- private void notifyUnbound(Object value, String name) {
+- if (value instanceof SSLSessionBindingListener) {
+- // Use newSSLSessionBindingEvent so we alway use the wrapper if needed.
+- ((SSLSessionBindingListener)
value).valueUnbound(newSSLSessionBindingEvent(name));
+- }
+- }
-
--(a)RunWith(Parameterized.class)
--public class SniHandlerTest {
+- /**
+- * Finish the handshake and so init everything in the {@link OpenSslSession}
that should be accessible by
+- * the user.
+- */
+- @Override
+- public void handshakeFinished() throws SSLException {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- id = SSL.getSessionId(ssl);
+- cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
+- protocol = SSL.getVersion(ssl);
-
-- private static ApplicationProtocolConfig newApnConfig() {
-- return new ApplicationProtocolConfig(
-- ApplicationProtocolConfig.Protocol.ALPN,
-- // NO_ADVERTISE is currently the only mode supported by both OpenSsl and
JDK providers.
-- ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
-- // ACCEPT is currently the only mode supported by both OpenSsl and JDK
providers.
-- ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
-- "myprotocol");
-- }
+- initPeerCerts();
+- selectApplicationProtocol();
+- calculateMaxWrapOverhead();
-
-- private static void assumeApnSupported(SslProvider provider) {
-- switch (provider) {
-- case OPENSSL:
-- case OPENSSL_REFCNT:
-- assumeTrue(OpenSsl.isAlpnSupported());
-- break;
-- case JDK:
-- assumeTrue(JettyAlpnSslEngine.isAvailable());
-- break;
-- default:
-- throw new Error();
+- handshakeState = HandshakeState.FINISHED;
+- } else {
+- throw new SSLException("Already closed");
+- }
+- }
- }
-- }
-
-- private static SslContext makeSslContext(SslProvider provider, boolean apn) throws
Exception {
-- if (apn) {
-- assumeApnSupported(provider);
+- /**
+- * Init peer certificates that can be obtained via {@link
#getPeerCertificateChain()}
+- * and {@link #getPeerCertificates()}.
+- */
+- private void initPeerCerts() {
+- // Return the full chain from the JNI layer.
+- byte[][] chain = SSL.getPeerCertChain(ssl);
+- if (clientMode) {
+- if (isEmpty(chain)) {
+- peerCerts = EmptyArrays.EMPTY_CERTIFICATES;
+- x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
+- } else {
+- peerCerts = new Certificate[chain.length];
+- x509PeerCerts = new X509Certificate[chain.length];
+- initCerts(chain, 0);
+- }
+- } else {
+- // if used on the server side SSL_get_peer_cert_chain(...) will not
include the remote peer
+- // certificate. We use SSL_get_peer_certificate to get it in this case
and add it to our
+- // array later.
+- //
+- // See
https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
+- byte[] clientCert = SSL.getPeerCertificate(ssl);
+- if (isEmpty(clientCert)) {
+- peerCerts = EmptyArrays.EMPTY_CERTIFICATES;
+- x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
+- } else {
+- if (isEmpty(chain)) {
+- peerCerts = new Certificate[] {new
OpenSslX509Certificate(clientCert)};
+- x509PeerCerts = new X509Certificate[] {new
OpenSslJavaxX509Certificate(clientCert)};
+- } else {
+- peerCerts = new Certificate[chain.length + 1];
+- x509PeerCerts = new X509Certificate[chain.length + 1];
+- peerCerts[0] = new OpenSslX509Certificate(clientCert);
+- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert);
+- initCerts(chain, 1);
+- }
+- }
+- }
- }
-
-- File keyFile = new
File(SniHandlerTest.class.getResource("test_encrypted.pem").getFile());
-- File crtFile = new
File(SniHandlerTest.class.getResource("test.crt").getFile());
--
-- SslContextBuilder sslCtxBuilder = SslContextBuilder.forServer(crtFile, keyFile,
"12345")
-- .sslProvider(provider);
-- if (apn) {
-- sslCtxBuilder.applicationProtocolConfig(newApnConfig());
+- private void initCerts(byte[][] chain, int startPos) {
+- for (int i = 0; i < chain.length; i++) {
+- int certPos = startPos + i;
+- peerCerts[certPos] = new OpenSslX509Certificate(chain[i]);
+- x509PeerCerts[certPos] = new OpenSslJavaxX509Certificate(chain[i]);
+- }
- }
-- return sslCtxBuilder.build();
-- }
-
-- private static SslContext makeSslClientContext(SslProvider provider, boolean apn)
throws Exception {
-- if (apn) {
-- assumeApnSupported(provider);
+- /**
+- * Select the application protocol used.
+- */
+- private void selectApplicationProtocol() throws SSLException {
+- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior =
apn.selectedListenerFailureBehavior();
+- List<String> protocols = apn.protocols();
+- String applicationProtocol;
+- switch (apn.protocol()) {
+- case NONE:
+- break;
+- // We always need to check for applicationProtocol == null as the remote
peer may not support
+- // the TLS extension or may have returned an empty selection.
+- case ALPN:
+- applicationProtocol = SSL.getAlpnSelected(ssl);
+- if (applicationProtocol != null) {
+- ReferenceCountedOpenSslEngine.this.applicationProtocol =
selectApplicationProtocol(
+- protocols, behavior, applicationProtocol);
+- }
+- break;
+- case NPN:
+- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
+- if (applicationProtocol != null) {
+- ReferenceCountedOpenSslEngine.this.applicationProtocol =
selectApplicationProtocol(
+- protocols, behavior, applicationProtocol);
+- }
+- break;
+- case NPN_AND_ALPN:
+- applicationProtocol = SSL.getAlpnSelected(ssl);
+- if (applicationProtocol == null) {
+- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
+- }
+- if (applicationProtocol != null) {
+- ReferenceCountedOpenSslEngine.this.applicationProtocol =
selectApplicationProtocol(
+- protocols, behavior, applicationProtocol);
+- }
+- break;
+- default:
+- throw new Error();
+- }
- }
-
-- File crtFile = new
File(SniHandlerTest.class.getResource("test.crt").getFile());
--
-- SslContextBuilder sslCtxBuilder =
SslContextBuilder.forClient().trustManager(crtFile).sslProvider(provider);
-- if (apn) {
-- sslCtxBuilder.applicationProtocolConfig(newApnConfig());
+- private String selectApplicationProtocol(List<String> protocols,
+-
ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior,
+- String applicationProtocol) throws
SSLException {
+- if (behavior ==
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) {
+- return applicationProtocol;
+- } else {
+- int size = protocols.size();
+- assert size > 0;
+- if (protocols.contains(applicationProtocol)) {
+- return applicationProtocol;
+- } else {
+- if (behavior ==
ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) {
+- return protocols.get(size - 1);
+- } else {
+- throw new SSLException("unknown protocol " +
applicationProtocol);
+- }
+- }
+- }
- }
-- return sslCtxBuilder.build();
-- }
-
-- @Parameterized.Parameters(name = "{index}: sslProvider={0}")
-- public static Iterable<?> data() {
-- List<SslProvider> params = new ArrayList<SslProvider>(3);
-- if (OpenSsl.isAvailable()) {
-- params.add(SslProvider.OPENSSL);
-- params.add(SslProvider.OPENSSL_REFCNT);
+- @Override
+- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (isEmpty(peerCerts)) {
+- throw new SSLPeerUnverifiedException("peer not
verified");
+- }
+- return peerCerts.clone();
+- }
- }
-- params.add(SslProvider.JDK);
-- return params;
-- }
--
-- private final SslProvider provider;
-
-- public SniHandlerTest(SslProvider provider) {
-- this.provider = provider;
-- }
--
-- @Test
-- public void testServerNameParsing() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, false);
-- SslContext leanContext = makeSslContext(provider, false);
-- SslContext leanContext2 = makeSslContext(provider, false);
--
-- try {
-- DomainNameMapping<SslContext> mapping = new
DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- // input with custom cases
-- .add("*.LEANCLOUD.CN", leanContext)
-- // a hostname conflict with previous one, since we are using
order-sensitive config,
-- // the engine won't be used with the handler.
-- .add("chat4.leancloud.cn", leanContext2)
-- .build();
--
-- SniHandler handler = new SniHandler(mapping);
-- EmbeddedChannel ch = new EmbeddedChannel(handler);
--
-- try {
-- // hex dump of a client hello packet, which contains hostname
"CHAT4.LEANCLOUD.CN"
-- String tlsHandshakeMessageHex1 = "16030100";
-- // part 2
-- String tlsHandshakeMessageHex =
"c6010000c20303bb0855d66532c05a0ef784f7c384feeafa68b3" +
--
"b655ac7288650d5eed4aa3fb52000038c02cc030009fcca9cca8ccaac02b" +
--
"c02f009ec024c028006bc023c0270067c00ac0140039c009c0130033009d" +
--
"009c003d003c0035002f00ff010000610000001700150000124348415434" +
--
"2e4c45414e434c4f55442e434e000b000403000102000a000a0008001d00" +
--
"170019001800230000000d0020001e060106020603050105020503040104" +
-- "0204030301030203030201020202030016000000170000";
--
--
ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1)));
--
ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex)));
--
-- // This should produce an alert
-- assertTrue(ch.finish());
--
-- assertThat(handler.hostname(), is("chat4.leancloud.cn"));
-- assertThat(handler.sslContext(), is(leanContext));
-- } finally {
-- ch.finishAndReleaseAll();
+- @Override
+- public Certificate[] getLocalCertificates() {
+- Certificate[] localCerts =
ReferenceCountedOpenSslEngine.this.localCertificateChain;
+- if (localCerts == null) {
+- return null;
- }
-- } finally {
-- releaseAll(leanContext, leanContext2, nettyContext);
+- return localCerts.clone();
- }
-- }
--
-- @Test(expected = DecoderException.class)
-- public void testNonAsciiServerNameParsing() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, false);
-- SslContext leanContext = makeSslContext(provider, false);
-- SslContext leanContext2 = makeSslContext(provider, false);
-
-- try {
-- DomainNameMapping<SslContext> mapping = new
DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- // input with custom cases
-- .add("*.LEANCLOUD.CN", leanContext)
-- // a hostname conflict with previous one, since we are using
order-sensitive config,
-- // the engine won't be used with the handler.
-- .add("chat4.leancloud.cn", leanContext2)
-- .build();
--
-- SniHandler handler = new SniHandler(mapping);
-- EmbeddedChannel ch = new EmbeddedChannel(handler);
--
-- try {
-- // hex dump of a client hello packet, which contains an invalid hostname
"CHAT4。LEANCLOUD。CN"
-- String tlsHandshakeMessageHex1 = "16030100";
-- // part 2
-- String tlsHandshakeMessageHex =
"bd010000b90303a74225676d1814ba57faff3b366" +
--
"3656ed05ee9dbb2a4dbb1bb1c32d2ea5fc39e0000000100008c0000001700150000164348" +
--
"415434E380824C45414E434C4F5544E38082434E000b000403000102000a00340032000e0" +
--
"00d0019000b000c00180009000a0016001700080006000700140015000400050012001300" +
--
"0100020003000f0010001100230000000d0020001e0601060206030501050205030401040" +
-- "20403030103020303020102020203000f00010133740000";
--
-- // Push the handshake message.
-- // Decode should fail because of the badly encoded "HostName"
string in the SNI extension
-- // that isn't ASCII as per RFC 6066 -
https://tools.ietf.org/html/rfc6066#page-6
--
ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1)));
--
ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex)));
-- } finally {
-- ch.finishAndReleaseAll();
+- @Override
+- public X509Certificate[] getPeerCertificateChain() throws
SSLPeerUnverifiedException {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (isEmpty(x509PeerCerts)) {
+- throw new SSLPeerUnverifiedException("peer not
verified");
+- }
+- return x509PeerCerts.clone();
- }
-- } finally {
-- releaseAll(leanContext, leanContext2, nettyContext);
- }
-- }
--
-- @Test
-- public void testFallbackToDefaultContext() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, false);
-- SslContext leanContext = makeSslContext(provider, false);
-- SslContext leanContext2 = makeSslContext(provider, false);
--
-- try {
-- DomainNameMapping<SslContext> mapping = new
DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- // input with custom cases
-- .add("*.LEANCLOUD.CN", leanContext)
-- // a hostname conflict with previous one, since we are using
order-sensitive config,
-- // the engine won't be used with the handler.
-- .add("chat4.leancloud.cn", leanContext2)
-- .build();
-
-- SniHandler handler = new SniHandler(mapping);
-- EmbeddedChannel ch = new EmbeddedChannel(handler);
--
-- // invalid
-- byte[] message = {22, 3, 1, 0, 0};
+- @Override
+- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+- Certificate[] peer = getPeerCertificates();
+- // No need for null or length > 0 is needed as this is done in
getPeerCertificates()
+- // already.
+- return ((java.security.cert.X509Certificate)
peer[0]).getSubjectX500Principal();
+- }
-
-- try {
-- // Push the handshake message.
-- ch.writeInbound(Unpooled.wrappedBuffer(message));
-- } catch (Exception e) {
-- // expected
+- @Override
+- public Principal getLocalPrincipal() {
+- Certificate[] local =
ReferenceCountedOpenSslEngine.this.localCertificateChain;
+- if (local == null || local.length == 0) {
+- return null;
- }
--
-- assertThat(ch.finish(), is(false));
-- assertThat(handler.hostname(), nullValue());
-- assertThat(handler.sslContext(), is(nettyContext));
-- } finally {
-- releaseAll(leanContext, leanContext2, nettyContext);
+- return ((java.security.cert.X509Certificate)
local[0]).getIssuerX500Principal();
- }
-- }
--
-- @Test
-- public void testSniWithApnHandler() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, true);
-- SslContext sniContext = makeSslContext(provider, true);
-- final SslContext clientContext = makeSslClientContext(provider, true);
-- try {
-- final CountDownLatch serverApnDoneLatch = new CountDownLatch(1);
-- final CountDownLatch clientApnDoneLatch = new CountDownLatch(1);
--
-- final DomainNameMapping<SslContext> mapping = new
DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- .add("sni.fake.site", sniContext).build();
-- final SniHandler handler = new SniHandler(mapping);
-- EventLoopGroup group = new NioEventLoopGroup(2);
-- Channel serverChannel = null;
-- Channel clientChannel = null;
-- try {
-- ServerBootstrap sb = new ServerBootstrap();
-- sb.group(group);
-- sb.channel(NioServerSocketChannel.class);
-- sb.childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ChannelPipeline p = ch.pipeline();
-- // Server side SNI.
-- p.addLast(handler);
-- // Catch the notification event that APN has completed
successfully.
-- p.addLast(new
ApplicationProtocolNegotiationHandler("foo") {
-- @Override
-- protected void configurePipeline(ChannelHandlerContext ctx,
String protocol) {
-- serverApnDoneLatch.countDown();
-- }
-- });
-- }
-- });
--
-- Bootstrap cb = new Bootstrap();
-- cb.group(group);
-- cb.channel(NioSocketChannel.class);
-- cb.handler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addLast(new SslHandler(clientContext.newEngine(
-- ch.alloc(), "sni.fake.site", -1)));
-- // Catch the notification event that APN has completed
successfully.
-- ch.pipeline().addLast(new
ApplicationProtocolNegotiationHandler("foo") {
-- @Override
-- protected void configurePipeline(ChannelHandlerContext ctx,
String protocol) {
-- clientApnDoneLatch.countDown();
-- }
-- });
-- }
-- });
--
-- serverChannel = sb.bind(new InetSocketAddress(0)).sync().channel();
-
-- ChannelFuture ccf = cb.connect(serverChannel.localAddress());
-- assertTrue(ccf.awaitUninterruptibly().isSuccess());
-- clientChannel = ccf.channel();
--
-- assertTrue(serverApnDoneLatch.await(5, TimeUnit.SECONDS));
-- assertTrue(clientApnDoneLatch.await(5, TimeUnit.SECONDS));
-- assertThat(handler.hostname(), is("sni.fake.site"));
-- assertThat(handler.sslContext(), is(sniContext));
-- } finally {
-- if (serverChannel != null) {
-- serverChannel.close().sync();
-- }
-- if (clientChannel != null) {
-- clientChannel.close().sync();
+- @Override
+- public String getCipherSuite() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (cipher == null) {
+- return SslUtils.INVALID_CIPHER;
- }
-- group.shutdownGracefully(0, 0, TimeUnit.MICROSECONDS);
+- return cipher;
- }
-- } finally {
-- releaseAll(clientContext, nettyContext, sniContext);
- }
-- }
--
-- @Test(timeout = 30000)
-- public void testReplaceHandler() throws Exception {
-- switch (provider) {
-- case OPENSSL:
-- case OPENSSL_REFCNT:
-- final String sniHost = "sni.netty.io";
-- LocalAddress address = new LocalAddress("testReplaceHandler-"
+ Math.random());
-- EventLoopGroup group = new DefaultEventLoopGroup(1);
-- Channel sc = null;
-- Channel cc = null;
-- SslContext sslContext = null;
--
-- SelfSignedCertificate cert = new SelfSignedCertificate();
--
-- try {
-- final SslContext sslServerContext = SslContextBuilder
-- .forServer(cert.key(), cert.cert())
-- .sslProvider(provider)
-- .build();
--
-- final Mapping<String, SslContext> mapping = new
Mapping<String, SslContext>() {
-- @Override
-- public SslContext map(String input) {
-- return sslServerContext;
-- }
-- };
--
-- final Promise<Void> releasePromise =
group.next().newPromise();
--
-- final SniHandler handler = new SniHandler(mapping) {
-- @Override
-- protected void replaceHandler(ChannelHandlerContext ctx,
-- String hostname, final SslContext
sslContext)
-- throws Exception {
--
-- boolean success = false;
-- try {
-- // The SniHandler's replaceHandler() method allows
us to implement custom behavior.
-- // As an example, we want to release() the SslContext
upon channelInactive() or rather
-- // when the SslHandler closes it's SslEngine. If you
take a close look at SslHandler
-- // you'll see that it's doing it in the
#handlerRemoved0() method.
--
-- SSLEngine sslEngine =
sslContext.newEngine(ctx.alloc());
-- try {
-- SslHandler customSslHandler = new
CustomSslHandler(sslContext, sslEngine) {
-- @Override
-- public void
handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
-- try {
-- super.handlerRemoved0(ctx);
-- } finally {
-- releasePromise.trySuccess(null);
-- }
-- }
-- };
-- ctx.pipeline().replace(this,
CustomSslHandler.class.getName(), customSslHandler);
-- success = true;
-- } finally {
-- if (!success) {
-- ReferenceCountUtil.safeRelease(sslEngine);
-- }
-- }
-- } finally {
-- if (!success) {
-- ReferenceCountUtil.safeRelease(sslContext);
-- releasePromise.cancel(true);
-- }
-- }
-- }
-- };
--
-- ServerBootstrap sb = new ServerBootstrap();
-- sc = sb.group(group).channel(LocalServerChannel.class)
-- .childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addFirst(handler);
-- }
-- }).bind(address).syncUninterruptibly().channel();
--
-- sslContext = SslContextBuilder.forClient().sslProvider(provider)
--
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
--
-- Bootstrap cb = new Bootstrap();
-- cc = cb.group(group).channel(LocalChannel.class).handler(new
SslHandler(
-- sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost,
-1)))
-- .connect(address).syncUninterruptibly().channel();
--
-- cc.writeAndFlush(Unpooled.wrappedBuffer("Hello,
World!".getBytes()))
-- .syncUninterruptibly();
--
-- // Notice how the server's SslContext refCnt is 1
-- assertEquals(1, ((ReferenceCounted) sslServerContext).refCnt());
--
-- // The client disconnects
-- cc.close().syncUninterruptibly();
-- if (!releasePromise.awaitUninterruptibly(10L, TimeUnit.SECONDS)) {
-- throw new IllegalStateException("It doesn't seem
#replaceHandler() got called.");
-- }
-
-- // We should have successfully release() the SslContext
-- assertEquals(0, ((ReferenceCounted) sslServerContext).refCnt());
-- } finally {
-- if (cc != null) {
-- cc.close().syncUninterruptibly();
-- }
-- if (sc != null) {
-- sc.close().syncUninterruptibly();
-- }
-- if (sslContext != null) {
-- ReferenceCountUtil.release(sslContext);
+- @Override
+- public String getProtocol() {
+- String protocol = this.protocol;
+- if (protocol == null) {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- protocol = SSL.getVersion(ssl);
+- } else {
+- protocol = StringUtil.EMPTY_STRING;
- }
-- group.shutdownGracefully();
--
-- cert.delete();
- }
-- case JDK:
-- return;
-- default:
-- throw new Error();
+- }
+- return protocol;
- }
-- }
--
-- /**
-- * This is a {@link SslHandler} that will call {@code release()} on the {@link
SslContext} when
-- * the client disconnects.
-- *
-- * @see SniHandlerTest#testReplaceHandler()
-- */
-- private static class CustomSslHandler extends SslHandler {
-- private final SslContext sslContext;
-
-- public CustomSslHandler(SslContext sslContext, SSLEngine sslEngine) {
-- super(sslEngine);
-- this.sslContext = ObjectUtil.checkNotNull(sslContext,
"sslContext");
+- @Override
+- public String getPeerHost() {
+- return ReferenceCountedOpenSslEngine.this.getPeerHost();
- }
-
- @Override
-- public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
-- super.handlerRemoved0(ctx);
-- ReferenceCountUtil.release(sslContext);
+- public int getPeerPort() {
+- return ReferenceCountedOpenSslEngine.this.getPeerPort();
- }
-- }
-
-- private static void releaseAll(SslContext... contexts) {
-- for (SslContext ctx: contexts) {
-- ReferenceCountUtil.release(ctx);
+- @Override
+- public int getPacketBufferSize() {
+- return maxEncryptedPacketLength();
- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java
b/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java
-deleted file mode 100644
-index 752424c..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java
-+++ /dev/null
-@@ -1,132 +0,0 @@
--/*
-- * Copyright 2015 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in
compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- *
http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static org.junit.Assert.assertFalse;
--import static org.junit.Assert.assertTrue;
-
--import io.netty.buffer.UnpooledByteBufAllocator;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import org.junit.Assume;
--import org.junit.Test;
--
--import javax.net.ssl.SSLEngine;
+- @Override
+- public int getApplicationBufferSize() {
+- return applicationBufferSize;
+- }
-
--public class SslContextBuilderTest {
--
-- @Test
-- public void testClientContextFromFileJdk() throws Exception {
-- testClientContextFromFile(SslProvider.JDK);
-- }
--
-- @Test
-- public void testClientContextFromFileOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testClientContextFromFile(SslProvider.OPENSSL);
-- }
--
-- @Test
-- public void testClientContextJdk() throws Exception {
-- testClientContext(SslProvider.JDK);
-- }
--
-- @Test
-- public void testClientContextOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testClientContext(SslProvider.OPENSSL);
-- }
--
-- @Test
-- public void testServerContextFromFileJdk() throws Exception {
-- testServerContextFromFile(SslProvider.JDK);
-- }
--
-- @Test
-- public void testServerContextFromFileOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testServerContextFromFile(SslProvider.OPENSSL);
-- }
--
-- @Test
-- public void testServerContextJdk() throws Exception {
-- testServerContext(SslProvider.JDK);
-- }
--
-- @Test
-- public void testServerContextOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testServerContext(SslProvider.OPENSSL);
-- }
--
-- private static void testClientContextFromFile(SslProvider provider) throws Exception
{
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forClient()
-- .sslProvider(provider)
-- .keyManager(cert.certificate(),
-- cert.privateKey())
-- .trustManager(cert.certificate())
-- .clientAuth(ClientAuth.OPTIONAL);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertFalse(engine.getWantClientAuth());
-- assertFalse(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
-- }
--
-- private static void testClientContext(SslProvider provider) throws Exception {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forClient()
-- .sslProvider(provider)
-- .keyManager(cert.key(),
cert.cert())
-- .trustManager(cert.cert())
-- .clientAuth(ClientAuth.OPTIONAL);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertFalse(engine.getWantClientAuth());
-- assertFalse(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
-- }
--
-- private static void testServerContextFromFile(SslProvider provider) throws Exception
{
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forServer(cert.certificate(),
cert.privateKey())
-- .sslProvider(provider)
-- .trustManager(cert.certificate())
-- .clientAuth(ClientAuth.OPTIONAL);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertTrue(engine.getWantClientAuth());
-- assertFalse(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
-- }
--
-- private static void testServerContext(SslProvider provider) throws Exception {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forServer(cert.key(),
cert.cert())
-- .sslProvider(provider)
-- .trustManager(cert.cert())
-- .clientAuth(ClientAuth.REQUIRE);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertFalse(engine.getWantClientAuth());
-- assertTrue(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
+- @Override
+- public void tryExpandApplicationBufferSize(int packetLengthDataOnly) {
+- if (packetLengthDataOnly > MAX_PLAINTEXT_LENGTH &&
applicationBufferSize != MAX_RECORD_SIZE) {
+- applicationBufferSize = MAX_RECORD_SIZE;
+- }
+- }
- }
-}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java
b/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java
+diff --git
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
deleted file mode 100644
-index aacdb69..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java
+index bac027a3b4..0000000000
+---
a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
+++ /dev/null
-@@ -1,255 +0,0 @@
+@@ -1,286 +0,0 @@
-/*
- * Copyright 2016 The Netty Project
- *
@@ -8134,351 +8008,449 @@ index aacdb69..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelHandlerContext;
--import io.netty.channel.ChannelInboundHandlerAdapter;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.nio.NioEventLoopGroup;
--import io.netty.channel.socket.nio.NioServerSocketChannel;
--import io.netty.channel.socket.nio.NioSocketChannel;
--import io.netty.handler.logging.LogLevel;
--import io.netty.handler.logging.LoggingHandler;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.handler.ssl.util.SimpleTrustManagerFactory;
--import io.netty.util.ReferenceCountUtil;
--import io.netty.util.concurrent.Promise;
--import io.netty.util.internal.EmptyArrays;
--import org.junit.Assume;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.internal.tcnative.CertificateCallback;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.internal.tcnative.SniHostNameMatcher;
+-import io.netty.util.CharsetUtil;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
--import javax.net.ssl.ManagerFactoryParameters;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.TrustManager;
--import javax.net.ssl.X509TrustManager;
--import javax.security.auth.x500.X500Principal;
--import java.io.File;
-import java.security.KeyStore;
--import java.security.cert.CRLReason;
--import java.security.cert.CertPathValidatorException;
--import java.security.cert.CertificateException;
--import java.security.cert.CertificateExpiredException;
--import java.security.cert.CertificateNotYetValidException;
--import java.security.cert.CertificateRevokedException;
--import java.security.cert.Extension;
+-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.Collections;
--import java.util.Date;
--import java.util.List;
--import java.util.Locale;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.TrustManagerFactory;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509TrustManager;
-
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
-
--(a)RunWith(Parameterized.class)
--public class SslErrorTest {
+-/**
+- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * <p>Instances of this class must be {@link #release() released} or else native
memory will leak!
+- *
+- * <p>Instances of this class <strong>must not</strong> be released
before any {@link ReferenceCountedOpenSslEngine}
+- * which depends upon the instance of this class is released. Otherwise if any method
of
+- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI
resources the JVM may crash.
+- */
+-public final class ReferenceCountedOpenSslServerContext extends
ReferenceCountedOpenSslContext {
+- private static final InternalLogger logger =
+-
InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class);
+- private static final byte[] ID = {'n', 'e', 't',
't', 'y'};
+- private final OpenSslServerSessionContext sessionContext;
-
-- @Parameterized.Parameters(name = "{index}: serverProvider = {0}, clientProvider
= {1}, exception = {2}")
-- public static Collection<Object[]> data() {
-- List<SslProvider> serverProviders = new ArrayList<SslProvider>(2);
-- List<SslProvider> clientProviders = new ArrayList<SslProvider>(3);
+- private static final boolean ENABLE_SESSION_TICKET =
+-
SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension",
false);
-
-- if (OpenSsl.isAvailable()) {
-- serverProviders.add(SslProvider.OPENSSL);
-- serverProviders.add(SslProvider.OPENSSL_REFCNT);
-- clientProviders.add(SslProvider.OPENSSL);
-- clientProviders.add(SslProvider.OPENSSL_REFCNT);
-- }
-- // We not test with SslProvider.JDK on the server side as the JDK implementation
currently just send the same
-- // alert all the time, sigh.....
-- clientProviders.add(SslProvider.JDK);
--
-- List<CertificateException> exceptions = new
ArrayList<CertificateException>(6);
-- exceptions.add(new CertificateExpiredException());
-- exceptions.add(new CertificateNotYetValidException());
-- exceptions.add(new CertificateRevokedException(
-- new Date(), CRLReason.AA_COMPROMISE, new X500Principal(""),
-- Collections.<String, Extension>emptyMap()));
--
-- // Also use wrapped exceptions as this is what the JDK implementation of
X509TrustManagerFactory is doing.
--
exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.EXPIRED));
--
exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.NOT_YET_VALID));
--
exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.REVOKED));
--
-- List<Object[]> params = new ArrayList<Object[]>();
-- for (SslProvider serverProvider: serverProviders) {
-- for (SslProvider clientProvider: clientProviders) {
-- for (CertificateException exception: exceptions) {
-- params.add(new Object[] { serverProvider, clientProvider,
exception});
-- }
+- ReferenceCountedOpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory
trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[]
protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers,
+- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout,
clientAuth, protocols, startTls,
+- enableOcsp, keyStore);
+- }
+-
+- ReferenceCountedOpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory
trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[]
protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
SSL.SSL_MODE_SERVER, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp, true);
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- sessionContext = newSessionContext(this, ctx, engineMap,
trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword,
keyManagerFactory, keyStore);
+- if (ENABLE_SESSION_TICKET) {
+- sessionContext.setTicketKeys();
+- }
+- success = true;
+- } finally {
+- if (!success) {
+- release();
- }
- }
-- return params;
- }
-
-- private static CertificateException
newCertificateException(CertPathValidatorException.Reason reason) {
-- return new TestCertificateException(
-- new CertPathValidatorException("x", null, null, -1, reason));
+- @Override
+- public OpenSslServerSessionContext sessionContext() {
+- return sessionContext;
- }
-
-- private final SslProvider serverProvider;
-- private final SslProvider clientProvider;
-- private final CertificateException exception;
+- static OpenSslServerSessionContext newSessionContext(ReferenceCountedOpenSslContext
thiz, long ctx,
+- OpenSslEngineMap engineMap,
+- X509Certificate[]
trustCertCollection,
+- TrustManagerFactory
trustManagerFactory,
+- X509Certificate[] keyCertChain,
PrivateKey key,
+- String keyPassword,
KeyManagerFactory keyManagerFactory,
+- String keyStore)
+- throws SSLException {
+- OpenSslKeyMaterialProvider keyMaterialProvider = null;
+- try {
+- try {
+- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
+- if (!OpenSsl.useKeyManagerFactory()) {
+- if (keyManagerFactory != null) {
+- throw new IllegalArgumentException(
+- "KeyManagerFactory not supported");
+- }
+- checkNotNull(keyCertChain, "keyCertChain");
-
-- public SslErrorTest(SslProvider serverProvider, SslProvider clientProvider,
CertificateException exception) {
-- this.serverProvider = serverProvider;
-- this.clientProvider = clientProvider;
-- this.exception = exception;
-- }
+- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
+- } else {
+- // javadocs state that keyManagerFactory has precedent over
keyCertChain, and we must have a
+- // keyManagerFactory for the server so build one if it is not
specified.
+- if (keyManagerFactory == null) {
+- char[] keyPasswordChars = keyStorePassword(keyPassword);
+- KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars,
keyStore);
+- if (ks.aliases().hasMoreElements()) {
+- keyManagerFactory = new OpenSslX509KeyManagerFactory();
+- } else {
+- keyManagerFactory = new
OpenSslCachingX509KeyManagerFactory(
+-
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
+- }
+- keyManagerFactory.init(ks, keyPasswordChars);
+- }
+- keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
-
-- @Test(timeout = 30000)
-- public void testCorrectAlert() throws Exception {
-- // As this only works correctly at the moment when OpenSslEngine is used on the
server-side there is
-- // no need to run it if there is no openssl is available at all.
-- Assume.assumeTrue(OpenSsl.isAvailable());
+- SSLContext.setCertificateCallback(ctx, new
OpenSslServerCertificateCallback(
+- engineMap, new
OpenSslKeyMaterialManager(keyMaterialProvider)));
+- }
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate and key",
e);
+- }
+- try {
+- if (trustCertCollection != null) {
+- trustManagerFactory = buildTrustManagerFactory(trustCertCollection,
trustManagerFactory, keyStore);
+- } else if (trustManagerFactory == null) {
+- // Mimic the way SSLContext.getInstance(KeyManager[], null, null)
works
+- trustManagerFactory = TrustManagerFactory.getInstance(
+- TrustManagerFactory.getDefaultAlgorithm());
+- trustManagerFactory.init((KeyStore) null);
+- }
-
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- final SslContext sslServerCtx = SslContextBuilder.forServer(ssc.certificate(),
ssc.privateKey())
-- .sslProvider(serverProvider)
-- .trustManager(new SimpleTrustManagerFactory() {
-- @Override
-- protected void engineInit(KeyStore keyStore) { }
-- @Override
-- protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
{ }
+- final X509TrustManager manager =
chooseTrustManager(trustManagerFactory.getTrustManagers());
-
-- @Override
-- protected TrustManager[] engineGetTrustManagers() {
-- return new TrustManager[] { new X509TrustManager() {
+- // IMPORTANT: The callbacks set for verification must be static to
prevent memory leak as
+- // otherwise the context can never be collected. This is
because the JNI code holds
+- // a global reference to the callbacks.
+- //
+- // See
https://github.com/netty/netty/issues/5372
-
-- @Override
-- public void checkClientTrusted(X509Certificate[] x509Certificates,
String s)
-- throws CertificateException {
-- throw exception;
-- }
+- setVerifyCallback(ctx, engineMap, manager);
-
-- @Override
-- public void checkServerTrusted(X509Certificate[] x509Certificates,
String s)
-- throws CertificateException {
-- // NOOP
+- X509Certificate[] issuers = manager.getAcceptedIssuers();
+- if (issuers != null && issuers.length > 0) {
+- long bio = 0;
+- try {
+- bio = toBIO(ByteBufAllocator.DEFAULT, issuers);
+- if (!SSLContext.setCACertificateBio(ctx, bio)) {
+- throw new SSLException("unable to setup accepted
issuers for trustmanager " + manager);
+- }
+- } finally {
+- freeBio(bio);
- }
+- }
-
-- @Override
-- public X509Certificate[] getAcceptedIssuers() {
-- return EmptyArrays.EMPTY_X509_CERTIFICATES;
-- }
-- } };
+- if (PlatformDependent.javaVersion() >= 8) {
+- // Only do on Java8+ as SNIMatcher is not supported in earlier
releases.
+- // IMPORTANT: The callbacks set for hostname matching must be static
to prevent memory leak as
+- // otherwise the context can never be collected. This is
because the JNI code holds
+- // a global reference to the matcher.
+- SSLContext.setSniHostnameMatcher(ctx, new
OpenSslSniHostnameMatcher(engineMap));
+- }
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("unable to setup trustmanager", e);
- }
-- }).clientAuth(ClientAuth.REQUIRE).build();
-
-- final SslContext sslClientCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .keyManager(new
File(getClass().getResource("test.crt").getFile()),
-- new
File(getClass().getResource("test_unencrypted.pem").getFile()))
-- .sslProvider(clientProvider).build();
+- OpenSslServerSessionContext sessionContext = new
OpenSslServerSessionContext(thiz, keyMaterialProvider);
+- sessionContext.setSessionIdContext(ID);
-
-- Channel serverChannel = null;
-- Channel clientChannel = null;
-- EventLoopGroup group = new NioEventLoopGroup();
-- try {
-- serverChannel = new ServerBootstrap().group(group)
-- .channel(NioServerSocketChannel.class)
-- .handler(new LoggingHandler(LogLevel.INFO))
-- .childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addLast(sslServerCtx.newHandler(ch.alloc()));
-- ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
--
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) {
-- ctx.close();
-- }
-- });
-- }
-- }).bind(0).sync().channel();
--
-- final Promise<Void> promise = group.next().newPromise();
--
-- clientChannel = new Bootstrap().group(group)
-- .channel(NioSocketChannel.class)
-- .handler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addLast(sslClientCtx.newHandler(ch.alloc()));
-- ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) {
-- // Unwrap as its wrapped by a DecoderException
-- Throwable unwrappedCause = cause.getCause();
-- if (unwrappedCause instanceof SSLException) {
-- if (exception instanceof
TestCertificateException) {
-- CertPathValidatorException.Reason reason =
-- ((CertPathValidatorException)
exception.getCause()).getReason();
-- if (reason ==
CertPathValidatorException.BasicReason.EXPIRED) {
-- verifyException(unwrappedCause,
"expired", promise);
-- } else if (reason ==
CertPathValidatorException.BasicReason.NOT_YET_VALID) {
-- verifyException(unwrappedCause,
"bad", promise);
-- } else if (reason ==
CertPathValidatorException.BasicReason.REVOKED) {
-- verifyException(unwrappedCause,
"revoked", promise);
-- }
-- } else if (exception instanceof
CertificateExpiredException) {
-- verifyException(unwrappedCause,
"expired", promise);
-- } else if (exception instanceof
CertificateNotYetValidException) {
-- verifyException(unwrappedCause,
"bad", promise);
-- } else if (exception instanceof
CertificateRevokedException) {
-- verifyException(unwrappedCause,
"revoked", promise);
-- }
-- }
-- }
-- });
-- }
--
}).connect(serverChannel.localAddress()).syncUninterruptibly().channel();
-- // Block until we received the correct exception
-- promise.syncUninterruptibly();
+- keyMaterialProvider = null;
+-
+- return sessionContext;
- } finally {
-- if (clientChannel != null) {
-- clientChannel.close().syncUninterruptibly();
-- }
-- if (serverChannel != null) {
-- serverChannel.close().syncUninterruptibly();
+- if (keyMaterialProvider != null) {
+- keyMaterialProvider.destroy();
- }
-- group.shutdownGracefully();
--
-- ReferenceCountUtil.release(sslServerCtx);
-- ReferenceCountUtil.release(sslClientCtx);
- }
- }
-
-- // Its a bit hacky to verify against the message that is part of the exception but
there is no other way
-- // at the moment as there are no different exceptions for the different alerts.
-- private static void verifyException(Throwable cause, String messagePart,
Promise<Void> promise) {
-- String message = cause.getMessage();
-- if (message.toLowerCase(Locale.UK).contains(messagePart.toLowerCase(Locale.UK)))
{
-- promise.setSuccess(null);
+- @SuppressJava6Requirement(reason = "Guarded by java version check")
+- private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap,
X509TrustManager manager) {
+- // Use this to prevent an error when running on java < 7
+- if (useExtendedTrustManager(manager)) {
+- SSLContext.setCertVerifyCallback(ctx, new
ExtendedTrustManagerVerifyCallback(
+- engineMap, (X509ExtendedTrustManager) manager));
- } else {
-- promise.setFailure(new AssertionError("message not contains '"
+ messagePart + "': " + message));
+- SSLContext.setCertVerifyCallback(ctx, new
TrustManagerVerifyCallback(engineMap, manager));
- }
- }
-
-- private static final class TestCertificateException extends CertificateException {
+- private static final class OpenSslServerCertificateCallback implements
CertificateCallback {
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslKeyMaterialManager keyManagerHolder;
-
-- public TestCertificateException(Throwable cause) {
-- super(cause);
+- OpenSslServerCertificateCallback(OpenSslEngineMap engineMap,
OpenSslKeyMaterialManager keyManagerHolder) {
+- this.engineMap = engineMap;
+- this.keyManagerHolder = keyManagerHolder;
- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java
b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java
-index 5ef43de..52c4d22 100644
---- a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java
-@@ -121,35 +121,6 @@ public class SslHandlerTest {
- }
- }
-
-- @Test
-- public void testReleaseSslEngine() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- try {
-- SslContext sslContext = SslContextBuilder.forServer(cert.certificate(),
cert.privateKey())
-- .sslProvider(SslProvider.OPENSSL)
-- .build();
+- @Override
+- public void handle(long ssl, byte[] keyTypeBytes, byte[][]
asn1DerEncodedPrincipals) throws Exception {
+- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine == null) {
+- // Maybe null if destroyed in the meantime.
+- return;
+- }
- try {
-- SSLEngine sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT);
-- EmbeddedChannel ch = new EmbeddedChannel(new SslHandler(sslEngine));
+- // For now we just ignore the asn1DerEncodedPrincipals as this is kind
of inline with what the
+- // OpenJDK SSLEngineImpl does.
+- keyManagerHolder.setKeyMaterialServerSide(engine);
+- } catch (Throwable cause) {
+- logger.debug("Failed to set the server-side key material",
cause);
+- engine.initHandshakeException(cause);
+- }
+- }
+- }
-
-- assertEquals(1, ((ReferenceCounted) sslContext).refCnt());
-- assertEquals(1, ((ReferenceCounted) sslEngine).refCnt());
+- private static final class TrustManagerVerifyCallback extends
AbstractCertificateVerifier {
+- private final X509TrustManager manager;
-
-- assertTrue(ch.finishAndReleaseAll());
-- ch.close().syncUninterruptibly();
+- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager)
{
+- super(engineMap);
+- this.manager = manager;
+- }
-
-- assertEquals(1, ((ReferenceCounted) sslContext).refCnt());
-- assertEquals(0, ((ReferenceCounted) sslEngine).refCnt());
-- } finally {
-- ReferenceCountUtil.release(sslContext);
-- }
-- } finally {
-- cert.delete();
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
String auth)
+- throws Exception {
+- manager.checkClientTrusted(peerCerts, auth);
- }
- }
-
- private static final class TlsReadTest extends ChannelOutboundHandlerAdapter {
- private volatile boolean readIssued;
-
-@@ -279,13 +250,6 @@ public class SslHandlerTest {
- testAlertProducedAndSend(SslProvider.JDK);
- }
-
-- @Test(timeout = 30000)
-- public void testAlertProducedAndSendOpenSsl() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testAlertProducedAndSend(SslProvider.OPENSSL);
-- testAlertProducedAndSend(SslProvider.OPENSSL_REFCNT);
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- private static final class ExtendedTrustManagerVerifyCallback extends
AbstractCertificateVerifier {
+- private final X509ExtendedTrustManager manager;
+-
+- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap,
X509ExtendedTrustManager manager) {
+- super(engineMap);
+- this.manager = OpenSslTlsv13X509ExtendedTrustManager.wrap(manager);
+- }
+-
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
String auth)
+- throws Exception {
+- manager.checkClientTrusted(peerCerts, auth, engine);
+- }
- }
-
- private void testAlertProducedAndSend(SslProvider provider) throws Exception {
- SelfSignedCertificate ssc = new SelfSignedCertificate();
-
-@@ -425,12 +389,6 @@ public class SslHandlerTest {
- testCloseNotify(SslProvider.JDK, 5000, false);
- }
-
-- @Test(timeout = 30000)
-- public void testCloseNotifyReceivedOpenSsl() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testCloseNotify(SslProvider.OPENSSL, 5000, false);
-- testCloseNotify(SslProvider.OPENSSL_REFCNT, 5000, false);
+- private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher
{
+- private final OpenSslEngineMap engineMap;
+-
+- OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) {
+- this.engineMap = engineMap;
+- }
+-
+- @Override
+- public boolean match(long ssl, String hostname) {
+- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine != null) {
+- // TODO: In the next release of tcnative we should pass the byte[]
directly in and not use a String.
+- return
engine.checkSniHostnameMatch(hostname.getBytes(CharsetUtil.UTF_8));
+- }
+- logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer:
{}", ssl);
+- return false;
+- }
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java
b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
+index fef2702cfb..eb5110d145 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
+@@ -120,11 +120,7 @@ public abstract class SslContext {
+ }
- @Test(timeout = 30000)
- public void testCloseNotifyReceivedJdkTimeout() throws Exception {
-@@ -438,24 +396,10 @@ public class SslHandlerTest {
+ private static SslProvider defaultProvider() {
+- if (OpenSsl.isAvailable()) {
+- return SslProvider.OPENSSL;
+- } else {
+- return SslProvider.JDK;
+- }
++ return SslProvider.JDK;
}
- @Test(timeout = 30000)
-- public void testCloseNotifyReceivedOpenSslTimeout() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testCloseNotify(SslProvider.OPENSSL, 100, true);
-- testCloseNotify(SslProvider.OPENSSL_REFCNT, 100, true);
-- }
+ /**
+@@ -466,18 +462,6 @@ public abstract class SslContext {
+ trustCertCollection, trustManagerFactory, keyCertChain, key,
keyPassword,
+ keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize,
sessionTimeout,
+ clientAuth, protocols, startTls, keyStoreType);
+- case OPENSSL:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new OpenSslServerContext(
+- trustCertCollection, trustManagerFactory, keyCertChain, key,
keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize,
sessionTimeout,
+- clientAuth, protocols, startTls, enableOcsp, keyStoreType);
+- case OPENSSL_REFCNT:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new ReferenceCountedOpenSslServerContext(
+- trustCertCollection, trustManagerFactory, keyCertChain, key,
keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize,
sessionTimeout,
+- clientAuth, protocols, startTls, enableOcsp, keyStoreType);
+ default:
+ throw new Error(provider.toString());
+ }
+@@ -822,18 +806,6 @@ public abstract class SslContext {
+ trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
+ keyManagerFactory, ciphers, cipherFilter, apn, protocols,
sessionCacheSize,
+ sessionTimeout, keyStoreType);
+- case OPENSSL:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new OpenSslClientContext(
+- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, protocols,
sessionCacheSize, sessionTimeout,
+- enableOcsp, keyStoreType);
+- case OPENSSL_REFCNT:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new ReferenceCountedOpenSslClientContext(
+- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, protocols,
sessionCacheSize, sessionTimeout,
+- enableOcsp, keyStoreType);
+ default:
+ throw new Error(provider.toString());
+ }
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+index 8e11bbf4cc..56be212b09 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+@@ -181,53 +181,6 @@ public class SslHandler extends ByteToMessageDecoder implements
ChannelOutboundH
+ private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024;
+
+ private enum SslEngineType {
+- TCNATIVE(true, COMPOSITE_CUMULATOR) {
+- @Override
+- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int
len, ByteBuf out)
+- throws SSLException {
+- int nioBufferCount = in.nioBufferCount();
+- int writerIndex = out.writerIndex();
+- final SSLEngineResult result;
+- if (nioBufferCount > 1) {
+- /*
+- * If {@link OpenSslEngine} is in use,
+- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[],
ByteBuffer[])} method
+- * that accepts multiple {@link ByteBuffer}s without additional
memory copies.
+- */
+- ReferenceCountedOpenSslEngine opensslEngine =
(ReferenceCountedOpenSslEngine) handler.engine;
+- try {
+- handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
+- out.writableBytes());
+- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len),
handler.singleBuffer);
+- } finally {
+- handler.singleBuffer[0] = null;
+- }
+- } else {
+- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
+- toByteBuffer(out, writerIndex, out.writableBytes()));
+- }
+- out.writerIndex(writerIndex + result.bytesProduced());
+- return result;
+- }
-
-- @Test(timeout = 30000)
- public void testCloseNotifyNotWaitForResponseJdk() throws Exception {
- testCloseNotify(SslProvider.JDK, 0, false);
- }
+- @Override
+- ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
+- int pendingBytes, int numComponents) {
+- return allocator.directBuffer(((ReferenceCountedOpenSslEngine)
handler.engine)
+- .calculateMaxLengthForWrap(pendingBytes, numComponents));
+- }
+-
+- @Override
+- int calculatePendingData(SslHandler handler, int guess) {
+- int sslPending = ((ReferenceCountedOpenSslEngine)
handler.engine).sslPending();
+- return sslPending > 0 ? sslPending : guess;
+- }
+-
+- @Override
+- boolean jdkCompatibilityMode(SSLEngine engine) {
+- return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
+- }
+- },
+ JDK(false, MERGE_CUMULATOR) {
+ @Override
+ SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int
len, ByteBuf out)
+@@ -280,7 +233,7 @@ public class SslHandler extends ByteToMessageDecoder implements
ChannelOutboundH
+ };
+
+ static SslEngineType forEngine(SSLEngine engine) {
+- return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : JDK;
++ return JDK;
+ }
+
+ SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
b/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
+index b1c710c841..44ef0456ed 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
+@@ -138,9 +138,6 @@ public abstract class SslMasterKeyHandler extends
ChannelInboundHandlerAdapter {
+ "via reflection.", e);
+ }
+ accept(secretKey, sslSession);
+- } else if (OpenSsl.isAvailable() && engine instanceof
ReferenceCountedOpenSslEngine) {
+- SecretKeySpec secretKey = ((ReferenceCountedOpenSslEngine)
engine).masterKey();
+- accept(secretKey, sslSession);
+ }
+ }
+ }
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
b/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
+index e72cfed8d9..5263314e7c 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
+@@ -26,16 +26,7 @@ public enum SslProvider {
+ /**
+ * JDK's default implementation.
+ */
+- JDK,
+- /**
+- * OpenSSL-based implementation.
+- */
+- OPENSSL,
+- /**
+- * OpenSSL-based implementation which does not have finalizers and instead
implements {@link ReferenceCounted}.
+- */
+- @UnstableApi
+- OPENSSL_REFCNT;
++ JDK;
-- @Test(timeout = 30000)
-- public void testCloseNotifyNotWaitForResponseOpenSsl() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testCloseNotify(SslProvider.OPENSSL, 0, false);
-- testCloseNotify(SslProvider.OPENSSL_REFCNT, 0, false);
-- }
--
- private static void testCloseNotify(SslProvider provider, final long
closeNotifyReadTimeout, final boolean timeout)
- throws Exception {
- SelfSignedCertificate ssc = new SelfSignedCertificate();
-@@ -720,7 +664,7 @@ public class SslHandlerTest {
+ /**
+ * Returns {@code true} if the specified {@link SslProvider} supports
+@@ -45,9 +36,6 @@ public enum SslProvider {
switch (provider) {
- case OPENSSL:
- case OPENSSL_REFCNT:
-- return OpenSsl.isAvailable();
-+ return false;
+ case JDK:
+ return JdkAlpnApplicationProtocolNegotiator.isAlpnSupported();
+- case OPENSSL:
+- case OPENSSL_REFCNT:
+- return OpenSsl.isAlpnSupported();
default:
- return true;
+ throw new Error("Unknown SslProvider: " + provider);
}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
b/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
b/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
deleted file mode 100644
-index 4aecc74..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
+index c45c50e1e3..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
+++ /dev/null
-@@ -1,501 +0,0 @@
+@@ -1,61 +0,0 @@
-/*
- * Copyright 2017 The Netty Project
- *
@@ -8494,492 +8466,102 @@ index 4aecc74..0000000
- * License for the specific language governing permissions and limitations
- * under the License.
- */
--
-package io.netty.handler.ssl.ocsp;
-
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.buffer.Unpooled;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.ChannelPipeline;
--import io.netty.channel.DefaultEventLoopGroup;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.local.LocalAddress;
--import io.netty.channel.local.LocalChannel;
--import io.netty.channel.local.LocalServerChannel;
--import io.netty.handler.ssl.OpenSsl;
+-import io.netty.handler.ssl.ReferenceCountedOpenSslContext;
-import io.netty.handler.ssl.ReferenceCountedOpenSslEngine;
--import io.netty.handler.ssl.SslContext;
--import io.netty.handler.ssl.SslContextBuilder;
--import io.netty.handler.ssl.SslHandler;
--import io.netty.handler.ssl.SslProvider;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.CharsetUtil;
--import io.netty.util.ReferenceCountUtil;
--
--import java.net.SocketAddress;
--import java.util.concurrent.CountDownLatch;
--import java.util.concurrent.TimeUnit;
--import java.util.concurrent.TimeoutException;
--import java.util.concurrent.atomic.AtomicReference;
+-import io.netty.handler.ssl.SslHandshakeCompletionEvent;
+-import io.netty.util.internal.ObjectUtil;
+-import io.netty.util.internal.UnstableApi;
-
-import javax.net.ssl.SSLHandshakeException;
-
--import org.junit.BeforeClass;
--import org.junit.Test;
--
--import static org.junit.Assert.assertArrayEquals;
--import static org.junit.Assert.assertNotNull;
--import static org.junit.Assert.assertNotSame;
--import static org.junit.Assert.assertNull;
--import static org.junit.Assert.assertSame;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeTrue;
--
--public class OcspTest {
--
-- @BeforeClass
-- public static void checkOcspSupported() {
-- assumeTrue(OpenSsl.isOcspSupported());
-- }
--
-- @Test(expected = IllegalArgumentException.class)
-- public void testJdkClientEnableOcsp() throws Exception {
-- SslContextBuilder.forClient()
-- .sslProvider(SslProvider.JDK)
-- .enableOcsp(true)
-- .build();
-- }
--
-- @Test(expected = IllegalArgumentException.class)
-- public void testJdkServerEnableOcsp() throws Exception {
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(SslProvider.JDK)
-- .enableOcsp(true)
-- .build();
-- } finally {
-- ssc.delete();
-- }
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testClientOcspNotEnabledOpenSsl() throws Exception {
-- testClientOcspNotEnabled(SslProvider.OPENSSL);
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testClientOcspNotEnabledOpenSslRefCnt() throws Exception {
-- testClientOcspNotEnabled(SslProvider.OPENSSL_REFCNT);
-- }
--
-- private void testClientOcspNotEnabled(SslProvider sslProvider) throws Exception {
-- SslContext context = SslContextBuilder.forClient()
-- .sslProvider(sslProvider)
-- .build();
-- try {
-- SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT);
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine)
sslHandler.engine();
-- try {
-- engine.getOcspResponse();
-- } finally {
-- engine.release();
-- }
-- } finally {
-- ReferenceCountUtil.release(context);
-- }
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testServerOcspNotEnabledOpenSsl() throws Exception {
-- testServerOcspNotEnabled(SslProvider.OPENSSL);
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testServerOcspNotEnabledOpenSslRefCnt() throws Exception {
-- testServerOcspNotEnabled(SslProvider.OPENSSL_REFCNT);
-- }
--
-- private void testServerOcspNotEnabled(SslProvider sslProvider) throws Exception {
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- SslContext context = SslContextBuilder.forServer(ssc.certificate(),
ssc.privateKey())
-- .sslProvider(sslProvider)
-- .build();
-- try {
-- SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT);
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine)
sslHandler.engine();
-- try {
-- engine.setOcspResponse(new byte[] { 1, 2, 3 });
-- } finally {
-- engine.release();
-- }
-- } finally {
-- ReferenceCountUtil.release(context);
-- }
-- } finally {
-- ssc.delete();
-- }
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientAcceptingOcspStapleOpenSsl() throws Exception {
-- testClientAcceptingOcspStaple(SslProvider.OPENSSL);
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientAcceptingOcspStapleOpenSslRefCnt() throws Exception {
-- testClientAcceptingOcspStaple(SslProvider.OPENSSL_REFCNT);
-- }
--
-- /**
-- * The Server provides an OCSP staple and the Client accepts it.
-- */
-- private void testClientAcceptingOcspStaple(SslProvider sslProvider) throws Exception
{
-- final CountDownLatch latch = new CountDownLatch(1);
-- ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter()
{
-- @Override
-- public void channelActive(ChannelHandlerContext ctx) throws Exception {
-- ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello,
World!".getBytes()));
-- ctx.fireChannelActive();
-- }
-- };
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter()
{
-- @Override
-- public void channelRead(ChannelHandlerContext ctx, Object msg) throws
Exception {
-- try {
-- ReferenceCountUtil.release(msg);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- byte[] response = newOcspResponse();
-- TestClientOcspContext callback = new TestClientOcspContext(true);
--
-- handshake(sslProvider, latch, serverHandler, response, clientHandler,
callback);
--
-- byte[] actual = callback.response();
--
-- assertNotNull(actual);
-- assertNotSame(response, actual);
-- assertArrayEquals(response, actual);
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientRejectingOcspStapleOpenSsl() throws Exception {
-- testClientRejectingOcspStaple(SslProvider.OPENSSL);
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientRejectingOcspStapleOpenSslRefCnt() throws Exception {
-- testClientRejectingOcspStaple(SslProvider.OPENSSL_REFCNT);
-- }
--
-- /**
-- * The Server provides an OCSP staple and the Client rejects it.
-- */
-- private void testClientRejectingOcspStaple(SslProvider sslProvider) throws Exception
{
-- final AtomicReference<Throwable> causeRef = new
AtomicReference<Throwable>();
-- final CountDownLatch latch = new CountDownLatch(1);
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter()
{
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
-- try {
-- causeRef.set(cause);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- byte[] response = newOcspResponse();
-- TestClientOcspContext callback = new TestClientOcspContext(false);
--
-- handshake(sslProvider, latch, null, response, clientHandler, callback);
--
-- byte[] actual = callback.response();
--
-- assertNotNull(actual);
-- assertNotSame(response, actual);
-- assertArrayEquals(response, actual);
--
-- Throwable cause = causeRef.get();
-- assertTrue("" + cause, cause instanceof SSLHandshakeException);
-- }
--
-- @Test(timeout = 10000L)
-- public void testServerHasNoStapleOpenSsl() throws Exception {
-- testServerHasNoStaple(SslProvider.OPENSSL);
-- }
--
-- @Test(timeout = 10000L)
-- public void testServerHasNoStapleOpenSslRefCnt() throws Exception {
-- testServerHasNoStaple(SslProvider.OPENSSL_REFCNT);
-- }
--
-- /**
-- * The server has OCSP stapling enabled but doesn't provide a staple.
-- */
-- private void testServerHasNoStaple(SslProvider sslProvider) throws Exception {
-- final CountDownLatch latch = new CountDownLatch(1);
-- ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter()
{
-- @Override
-- public void channelActive(ChannelHandlerContext ctx) throws Exception {
-- ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello,
World!".getBytes()));
-- ctx.fireChannelActive();
-- }
-- };
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter()
{
-- @Override
-- public void channelRead(ChannelHandlerContext ctx, Object msg) throws
Exception {
-- try {
-- ReferenceCountUtil.release(msg);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- byte[] response = null;
-- TestClientOcspContext callback = new TestClientOcspContext(true);
--
-- handshake(sslProvider, latch, serverHandler, response, clientHandler,
callback);
--
-- byte[] actual = callback.response();
--
-- assertNull(response);
-- assertNull(actual);
-- }
+-/**
+- * A handler for SSL clients to handle and act upon stapled OCSP responses.
+- *
+- * @see ReferenceCountedOpenSslContext#enableOcsp()
+- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
+- */
+-@UnstableApi
+-public abstract class OcspClientHandler extends ChannelInboundHandlerAdapter {
-
-- @Test(timeout = 10000L)
-- public void testClientExceptionOpenSsl() throws Exception {
-- testClientException(SslProvider.OPENSSL);
-- }
+- private final ReferenceCountedOpenSslEngine engine;
-
-- @Test(timeout = 10000L)
-- public void testClientExceptionOpenSslRefCnt() throws Exception {
-- testClientException(SslProvider.OPENSSL_REFCNT);
+- protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) {
+- this.engine = ObjectUtil.checkNotNull(engine, "engine");
- }
-
- /**
-- * Testing what happens if the {@link OcspClientCallback} throws an {@link
Exception}.
-- *
-- * The exception should bubble up on the client side and the connection should get
closed.
+- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
- */
-- private void testClientException(SslProvider sslProvider) throws Exception {
-- final AtomicReference<Throwable> causeRef = new
AtomicReference<Throwable>();
-- final CountDownLatch latch = new CountDownLatch(1);
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter()
{
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
-- try {
-- causeRef.set(cause);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- final OcspTestException clientException = new
OcspTestException("testClientException");
-- byte[] response = newOcspResponse();
-- OcspClientCallback callback = new OcspClientCallback() {
-- @Override
-- public boolean verify(byte[] response) throws Exception {
-- throw clientException;
-- }
-- };
--
-- handshake(sslProvider, latch, null, response, clientHandler, callback);
--
-- assertSame(clientException, causeRef.get());
-- }
--
-- private static void handshake(SslProvider sslProvider, CountDownLatch latch,
ChannelHandler serverHandler,
-- byte[] response, ChannelHandler clientHandler, OcspClientCallback callback)
throws Exception {
--
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- SslContext serverSslContext = SslContextBuilder.forServer(ssc.certificate(),
ssc.privateKey())
-- .sslProvider(sslProvider)
-- .enableOcsp(true)
-- .build();
--
-- try {
-- SslContext clientSslContext = SslContextBuilder.forClient()
-- .sslProvider(sslProvider)
-- .enableOcsp(true)
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .build();
--
-- try {
-- EventLoopGroup group = new DefaultEventLoopGroup();
-- try {
-- LocalAddress address = new LocalAddress("handshake-" +
Math.random());
-- Channel server = newServer(group, address, serverSslContext,
response, serverHandler);
-- Channel client = newClient(group, address, clientSslContext,
callback, clientHandler);
-- try {
-- assertTrue("Something went wrong.",
latch.await(10L, TimeUnit.SECONDS));
-- } finally {
-- client.close().syncUninterruptibly();
-- server.close().syncUninterruptibly();
-- }
-- } finally {
-- group.shutdownGracefully(1L, 1L, TimeUnit.SECONDS);
-- }
-- } finally {
-- ReferenceCountUtil.release(clientSslContext);
-- }
-- } finally {
-- ReferenceCountUtil.release(serverSslContext);
-- }
-- } finally {
-- ssc.delete();
-- }
-- }
--
-- private static Channel newServer(EventLoopGroup group, SocketAddress address,
-- SslContext context, byte[] response, ChannelHandler handler) {
--
-- ServerBootstrap bootstrap = new ServerBootstrap()
-- .channel(LocalServerChannel.class)
-- .group(group)
-- .childHandler(newServerHandler(context, response, handler));
--
-- return bootstrap.bind(address)
-- .syncUninterruptibly()
-- .channel();
-- }
--
-- private static Channel newClient(EventLoopGroup group, SocketAddress address,
-- SslContext context, OcspClientCallback callback, ChannelHandler handler) {
--
-- Bootstrap bootstrap = new Bootstrap()
-- .channel(LocalChannel.class)
-- .group(group)
-- .handler(newClientHandler(context, callback, handler));
--
-- return bootstrap.connect(address)
-- .syncUninterruptibly()
-- .channel();
-- }
--
-- private static ChannelHandler newServerHandler(final SslContext context,
-- final byte[] response, final ChannelHandler handler) {
-- return new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ChannelPipeline pipeline = ch.pipeline();
-- SslHandler sslHandler = context.newHandler(ch.alloc());
--
-- if (response != null) {
-- ReferenceCountedOpenSslEngine engine =
(ReferenceCountedOpenSslEngine) sslHandler.engine();
-- engine.setOcspResponse(response);
-- }
--
-- pipeline.addLast(sslHandler);
--
-- if (handler != null) {
-- pipeline.addLast(handler);
-- }
-- }
-- };
-- }
--
-- private static ChannelHandler newClientHandler(final SslContext context,
-- final OcspClientCallback callback, final ChannelHandler handler) {
-- return new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ChannelPipeline pipeline = ch.pipeline();
--
-- SslHandler sslHandler = context.newHandler(ch.alloc());
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine)
sslHandler.engine();
+- protected abstract boolean verify(ChannelHandlerContext ctx,
ReferenceCountedOpenSslEngine engine) throws Exception;
-
-- pipeline.addLast(sslHandler);
-- pipeline.addLast(new OcspClientCallbackHandler(engine, callback));
+- @Override
+- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws
Exception {
+- if (evt instanceof SslHandshakeCompletionEvent) {
+- ctx.pipeline().remove(this);
-
-- if (handler != null) {
-- pipeline.addLast(handler);
-- }
+- SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt;
+- if (event.isSuccess() && !verify(ctx, engine)) {
+- throw new SSLHandshakeException("Bad OCSP response");
- }
-- };
-- }
--
-- private static byte[] newOcspResponse() {
-- // Assume we got the OCSP staple from somewhere. Using a bogus byte[]
-- // in the test because getting a true staple from the CA is quite involved.
-- // It requires HttpCodec and Bouncycastle and the test may be very unreliable
-- // because the OCSP responder servers are basically being DDoS'd by the
-- // Internet.
--
-- return "I am a bogus OCSP staple. OpenSSL does not care about the format of
the byte[]!"
-- .getBytes(CharsetUtil.US_ASCII);
-- }
--
-- private interface OcspClientCallback {
-- boolean verify(byte[] staple) throws Exception;
-- }
--
-- private static final class TestClientOcspContext implements OcspClientCallback {
--
-- private final CountDownLatch latch = new CountDownLatch(1);
-- private final boolean valid;
--
-- private volatile byte[] response;
--
-- public TestClientOcspContext(boolean valid) {
-- this.valid = valid;
-- }
--
-- public byte[] response() throws InterruptedException, TimeoutException {
-- assertTrue(latch.await(10L, TimeUnit.SECONDS));
-- return response;
-- }
--
-- @Override
-- public boolean verify(byte[] response) throws Exception {
-- this.response = response;
-- latch.countDown();
--
-- return valid;
-- }
-- }
--
-- private static final class OcspClientCallbackHandler extends OcspClientHandler {
--
-- private final OcspClientCallback callback;
--
-- public OcspClientCallbackHandler(ReferenceCountedOpenSslEngine engine,
OcspClientCallback callback) {
-- super(engine);
-- this.callback = callback;
-- }
--
-- @Override
-- protected boolean verify(ChannelHandlerContext ctx,
ReferenceCountedOpenSslEngine engine) throws Exception {
-- byte[] response = engine.getOcspResponse();
-- return callback.verify(response);
- }
-- }
-
-- private static final class OcspTestException extends IllegalStateException {
-- public OcspTestException(String message) {
-- super(message);
-- }
+- ctx.fireUserEventTriggered(evt);
- }
-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
b/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
+deleted file mode 100644
+index 2883ff48cf..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/*
+- * Copyright 2017 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-/**
+- * <a
href="https://en.wikipedia.org/wiki/OCSP_stapling">OCSP
stapling</a>,
+- * formally known as the TLS Certificate Status Request extension, is an
+- * alternative approach to the Online Certificate Status Protocol (OCSP)
+- * for checking the revocation status of X.509 digital certificates.
+- */
+-package io.netty.handler.ssl.ocsp;
+diff --git a/pom.xml b/pom.xml
+index bedd6d6903..75a2da328a 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -465,16 +465,6 @@
+ <version>3.0.0-alpha-5</version>
+ </dependency>
+
+- <!-- Our own Tomcat Native fork - completely optional, used for accelerating
SSL with OpenSSL. -->
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>${tcnative.artifactId}</artifactId>
+- <version>${tcnative.version}</version>
+- <classifier>${tcnative.classifier}</classifier>
+- <scope>compile</scope>
+- <optional>true</optional>
+- </dependency>
+-
+ <!--
+ Bouncy Castle - completely optional, only needed when:
+ - you generate a temporary self-signed certificate using SelfSignedCertificate,
and
--
-2.9.4
+2.26.2
diff --git a/0005-Remove-optional-dep-log4j.patch b/0005-Remove-optional-dep-log4j.patch
new file mode 100644
index 0000000..9dcd6e7
--- /dev/null
+++ b/0005-Remove-optional-dep-log4j.patch
@@ -0,0 +1,911 @@
+From 1762f36e7ed797747ae692ea2c78001d45b35449 Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 14:29:44 +0100
+Subject: [PATCH 5/5] Remove optional dep log4j
+
+---
+ common/pom.xml | 15 -
+ .../logging/InternalLoggerFactory.java | 14 +-
+ .../util/internal/logging/Log4J2Logger.java | 143 -----
+ .../internal/logging/Log4J2LoggerFactory.java | 35 -
+ .../util/internal/logging/Log4JLogger.java | 597 ------------------
+ .../internal/logging/Log4JLoggerFactory.java | 40 --
+ 6 files changed, 2 insertions(+), 842 deletions(-)
+ delete mode 100644
common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java
+ delete mode 100644
common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java
+ delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java
+ delete mode 100644
common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java
+
+diff --git a/common/pom.xml b/common/pom.xml
+index abc73161eb..60693fb81a 100644
+--- a/common/pom.xml
++++ b/common/pom.xml
+@@ -63,21 +63,6 @@
+ <artifactId>commons-logging</artifactId>
+ <optional>true</optional>
+ </dependency>
+- <dependency>
+- <groupId>log4j</groupId>
+- <artifactId>log4j</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>org.apache.logging.log4j</groupId>
+- <artifactId>log4j-api</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>org.apache.logging.log4j</groupId>
+- <artifactId>log4j-core</artifactId>
+- <scope>test</scope>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git
a/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java
b/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java
+index 508f571820..98eb4e4f4d 100644
+--- a/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java
++++ b/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java
+@@ -44,18 +44,8 @@ public abstract class InternalLoggerFactory {
+ f = new Slf4JLoggerFactory(true);
+ f.newInstance(name).debug("Using SLF4J as the default logging
framework");
+ } catch (Throwable ignore1) {
+- try {
+- f = Log4J2LoggerFactory.INSTANCE;
+- f.newInstance(name).debug("Using Log4J2 as the default logging
framework");
+- } catch (Throwable ignore2) {
+- try {
+- f = Log4JLoggerFactory.INSTANCE;
+- f.newInstance(name).debug("Using Log4J as the default logging
framework");
+- } catch (Throwable ignore3) {
+- f = JdkLoggerFactory.INSTANCE;
+- f.newInstance(name).debug("Using java.util.logging as the
default logging framework");
+- }
+- }
++ f = JdkLoggerFactory.INSTANCE;
++ f.newInstance(name).debug("Using java.util.logging as the default
logging framework");
+ }
+ return f;
+ }
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java
b/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java
+deleted file mode 100644
+index 5c3593f203..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java
++++ /dev/null
+@@ -1,143 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal.logging;
+-
+-
+-import org.apache.logging.log4j.Level;
+-import org.apache.logging.log4j.Logger;
+-import org.apache.logging.log4j.spi.ExtendedLogger;
+-import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;
+-
+-import java.security.AccessController;
+-import java.security.PrivilegedAction;
+-
+-import static io.netty.util.internal.logging.AbstractInternalLogger.EXCEPTION_MESSAGE;
+-
+-class Log4J2Logger extends ExtendedLoggerWrapper implements InternalLogger {
+-
+- private static final long serialVersionUID = 5485418394879791397L;
+- private static final boolean VARARGS_ONLY;
+-
+- static {
+- // Older Log4J2 versions have only log methods that takes the format + varargs.
So we should not use
+- // Log4J2 if the version is too old.
+- // See
https://github.com/netty/netty/issues/8217
+- VARARGS_ONLY = AccessController.doPrivileged(new
PrivilegedAction<Boolean>() {
+- @Override
+- public Boolean run() {
+- try {
+- Logger.class.getMethod("debug", String.class,
Object.class);
+- return false;
+- } catch (NoSuchMethodException ignore) {
+- // Log4J2 version too old.
+- return true;
+- } catch (SecurityException ignore) {
+- // We could not detect the version so we will use Log4J2 if its on
the classpath.
+- return false;
+- }
+- }
+- });
+- }
+-
+- Log4J2Logger(Logger logger) {
+- super((ExtendedLogger) logger, logger.getName(), logger.getMessageFactory());
+- if (VARARGS_ONLY) {
+- throw new UnsupportedOperationException("Log4J2 version
mismatch");
+- }
+- }
+-
+- @Override
+- public String name() {
+- return getName();
+- }
+-
+- @Override
+- public void trace(Throwable t) {
+- log(Level.TRACE, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void debug(Throwable t) {
+- log(Level.DEBUG, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void info(Throwable t) {
+- log(Level.INFO, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void warn(Throwable t) {
+- log(Level.WARN, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void error(Throwable t) {
+- log(Level.ERROR, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public boolean isEnabled(InternalLogLevel level) {
+- return isEnabled(toLevel(level));
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String msg) {
+- log(toLevel(level), msg);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String format, Object arg) {
+- log(toLevel(level), format, arg);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String format, Object argA, Object argB) {
+- log(toLevel(level), format, argA, argB);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String format, Object... arguments) {
+- log(toLevel(level), format, arguments);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String msg, Throwable t) {
+- log(toLevel(level), msg, t);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, Throwable t) {
+- log(toLevel(level), EXCEPTION_MESSAGE, t);
+- }
+-
+- private static Level toLevel(InternalLogLevel level) {
+- switch (level) {
+- case INFO:
+- return Level.INFO;
+- case DEBUG:
+- return Level.DEBUG;
+- case WARN:
+- return Level.WARN;
+- case ERROR:
+- return Level.ERROR;
+- case TRACE:
+- return Level.TRACE;
+- default:
+- throw new Error();
+- }
+- }
+-}
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java
b/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java
+deleted file mode 100644
+index 8b895fbc07..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal.logging;
+-
+-import org.apache.logging.log4j.LogManager;
+-
+-public final class Log4J2LoggerFactory extends InternalLoggerFactory {
+-
+- public static final InternalLoggerFactory INSTANCE = new Log4J2LoggerFactory();
+-
+- /**
+- * @deprecated Use {@link #INSTANCE} instead.
+- */
+- @Deprecated
+- public Log4J2LoggerFactory() {
+- }
+-
+- @Override
+- public InternalLogger newInstance(String name) {
+- return new Log4J2Logger(LogManager.getLogger(name));
+- }
+-}
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java
b/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java
+deleted file mode 100644
+index 27b9130a08..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java
++++ /dev/null
+@@ -1,597 +0,0 @@
+-/*
+- * Copyright 2012 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-/**
+- * Copyright (c) 2004-2011 QOS.ch
+- * All rights reserved.
+- *
+- * Permission is hereby granted, free of charge, to any person obtaining
+- * a copy of this software and associated documentation files (the
+- * "Software"), to deal in the Software without restriction, including
+- * without limitation the rights to use, copy, modify, merge, publish,
+- * distribute, sublicense, and/or sell copies of the Software, and to
+- * permit persons to whom the Software is furnished to do so, subject to
+- * the following conditions:
+- *
+- * The above copyright notice and this permission notice shall be
+- * included in all copies or substantial portions of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+- *
+- */
+-package io.netty.util.internal.logging;
+-
+-import org.apache.log4j.Level;
+-import org.apache.log4j.Logger;
+-
+-/**
+- * <a
href="http://logging.apache.org/log4j/1.2/index.html">Apache
Log4J</a>
+- * logger.
+- */
+-class Log4JLogger extends AbstractInternalLogger {
+-
+- private static final long serialVersionUID = 2851357342488183058L;
+-
+- final transient Logger logger;
+-
+- /**
+- * Following the pattern discussed in pages 162 through 168 of "The complete
+- * log4j manual".
+- */
+- static final String FQCN = Log4JLogger.class.getName();
+-
+- // Does the log4j version in use recognize the TRACE level?
+- // The trace level was introduced in log4j 1.2.12.
+- final boolean traceCapable;
+-
+- Log4JLogger(Logger logger) {
+- super(logger.getName());
+- this.logger = logger;
+- traceCapable = isTraceCapable();
+- }
+-
+- private boolean isTraceCapable() {
+- try {
+- logger.isTraceEnabled();
+- return true;
+- } catch (NoSuchMethodError ignored) {
+- return false;
+- }
+- }
+-
+- /**
+- * Is this logger instance enabled for the TRACE level?
+- *
+- * @return True if this Logger is enabled for level TRACE, false otherwise.
+- */
+- @Override
+- public boolean isTraceEnabled() {
+- if (traceCapable) {
+- return logger.isTraceEnabled();
+- } else {
+- return logger.isDebugEnabled();
+- }
+- }
+-
+- /**
+- * Log a message object at level TRACE.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void trace(String msg) {
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, null);
+- }
+-
+- /**
+- * Log a message at level TRACE according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for level TRACE.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void trace(String format, Object arg) {
+- if (isTraceEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft
+- .getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level TRACE according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the TRACE level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void trace(String format, Object argA, Object argB) {
+- if (isTraceEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft
+- .getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level TRACE according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the TRACE level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arguments
+- * an array of arguments
+- */
+- @Override
+- public void trace(String format, Object... arguments) {
+- if (isTraceEnabled()) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft
+- .getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at level TRACE with an accompanying message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void trace(String msg, Throwable t) {
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for the DEBUG level?
+- *
+- * @return True if this Logger is enabled for level DEBUG, false otherwise.
+- */
+- @Override
+- public boolean isDebugEnabled() {
+- return logger.isDebugEnabled();
+- }
+-
+- /**
+- * Log a message object at level DEBUG.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void debug(String msg) {
+- logger.log(FQCN, Level.DEBUG, msg, null);
+- }
+-
+- /**
+- * Log a message at level DEBUG according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for level DEBUG.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void debug(String format, Object arg) {
+- if (logger.isDebugEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level DEBUG according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the DEBUG level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void debug(String format, Object argA, Object argB) {
+- if (logger.isDebugEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level DEBUG according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the DEBUG level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arguments an array of arguments
+- */
+- @Override
+- public void debug(String format, Object... arguments) {
+- if (logger.isDebugEnabled()) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
+- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at level DEBUG with an accompanying message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void debug(String msg, Throwable t) {
+- logger.log(FQCN, Level.DEBUG, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for the INFO level?
+- *
+- * @return True if this Logger is enabled for the INFO level, false otherwise.
+- */
+- @Override
+- public boolean isInfoEnabled() {
+- return logger.isInfoEnabled();
+- }
+-
+- /**
+- * Log a message object at the INFO level.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void info(String msg) {
+- logger.log(FQCN, Level.INFO, msg, null);
+- }
+-
+- /**
+- * Log a message at level INFO according to the specified format and argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the INFO level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void info(String format, Object arg) {
+- if (logger.isInfoEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at the INFO level according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the INFO level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void info(String format, Object argA, Object argB) {
+- if (logger.isInfoEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level INFO according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the INFO level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argArray
+- * an array of arguments
+- */
+- @Override
+- public void info(String format, Object... argArray) {
+- if (logger.isInfoEnabled()) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
+- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at the INFO level with an accompanying
+- * message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void info(String msg, Throwable t) {
+- logger.log(FQCN, Level.INFO, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for the WARN level?
+- *
+- * @return True if this Logger is enabled for the WARN level, false otherwise.
+- */
+- @Override
+- public boolean isWarnEnabled() {
+- return logger.isEnabledFor(Level.WARN);
+- }
+-
+- /**
+- * Log a message object at the WARN level.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void warn(String msg) {
+- logger.log(FQCN, Level.WARN, msg, null);
+- }
+-
+- /**
+- * Log a message at the WARN level according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the WARN level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void warn(String format, Object arg) {
+- if (logger.isEnabledFor(Level.WARN)) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at the WARN level according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the WARN level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void warn(String format, Object argA, Object argB) {
+- if (logger.isEnabledFor(Level.WARN)) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level WARN according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the WARN level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argArray
+- * an array of arguments
+- */
+- @Override
+- public void warn(String format, Object... argArray) {
+- if (logger.isEnabledFor(Level.WARN)) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
+- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at the WARN level with an accompanying
+- * message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void warn(String msg, Throwable t) {
+- logger.log(FQCN, Level.WARN, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for level ERROR?
+- *
+- * @return True if this Logger is enabled for level ERROR, false otherwise.
+- */
+- @Override
+- public boolean isErrorEnabled() {
+- return logger.isEnabledFor(Level.ERROR);
+- }
+-
+- /**
+- * Log a message object at the ERROR level.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void error(String msg) {
+- logger.log(FQCN, Level.ERROR, msg, null);
+- }
+-
+- /**
+- * Log a message at the ERROR level according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the ERROR level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void error(String format, Object arg) {
+- if (logger.isEnabledFor(Level.ERROR)) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at the ERROR level according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the ERROR level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void error(String format, Object argA, Object argB) {
+- if (logger.isEnabledFor(Level.ERROR)) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level ERROR according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the ERROR level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argArray
+- * an array of arguments
+- */
+- @Override
+- public void error(String format, Object... argArray) {
+- if (logger.isEnabledFor(Level.ERROR)) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
+- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at the ERROR level with an accompanying
+- * message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void error(String msg, Throwable t) {
+- logger.log(FQCN, Level.ERROR, msg, t);
+- }
+-}
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java
b/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java
+deleted file mode 100644
+index 399a279df3..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java
++++ /dev/null
+@@ -1,40 +0,0 @@
+-/*
+- * Copyright 2012 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in
compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- *
http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal.logging;
+-
+-import org.apache.log4j.Logger;
+-
+-/**
+- * Logger factory which creates an
+- * <a
href="http://logging.apache.org/log4j/1.2/index.html">Apache
Log4J</a>
+- * logger.
+- */
+-public class Log4JLoggerFactory extends InternalLoggerFactory {
+-
+- public static final InternalLoggerFactory INSTANCE = new Log4JLoggerFactory();
+-
+- /**
+- * @deprecated Use {@link #INSTANCE} instead.
+- */
+- @Deprecated
+- public Log4JLoggerFactory() {
+- }
+-
+- @Override
+- public InternalLogger newInstance(String name) {
+- return new Log4JLogger(Logger.getLogger(name));
+- }
+-}
+--
+2.26.2
+
diff --git a/netty.spec b/netty.spec
index 5a630f0..90e1234 100644
--- a/netty.spec
+++ b/netty.spec
@@ -1,13 +1,9 @@
-# Disable generation of debuginfo package
-%global debug_package %{nil}
%global namedreltag .Final
%global namedversion %{version}%{?namedreltag}
-%bcond_without jp_minimal
-
Name: netty
-Version: 4.1.13
-Release: 19%{?dist}
+Version: 4.1.51
+Release: 1%{?dist}
Summary: An asynchronous event-driven network application framework and tools for
Java
License: ASL 2.0
URL:
https://netty.io/
@@ -16,42 +12,25 @@ Source0:
https://github.com/netty/netty/archive/netty-%{namedversion}.tar
# We don't have the plugin and want to avoid groovy dependency
# This script is written in bash+sed and performs the same task
Source1: codegen.bash
-Patch0: 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch
-Patch1: 0002-Remove-NPN.patch
-Patch2: 0003-Remove-conscrypt-ALPN.patch
-Patch3: 0004-Remove-jetty-ALPN.patch
+Patch0: 0001-Remove-optional-dep-Blockhound.patch
+Patch1: 0002-Remove-optional-dep-conscrypt.patch
+Patch2: 0003-Remove-optional-deps-jetty-alpn-and-npn.patch
+Patch3: 0004-Remove-optional-dep-tcnative.patch
+Patch4: 0005-Remove-optional-dep-log4j.patch
BuildRequires: maven-local
-BuildRequires: mvn(ant-contrib:ant-contrib)
BuildRequires: mvn(com.jcraft:jzlib)
BuildRequires: mvn(commons-logging:commons-logging)
BuildRequires: mvn(kr.motd.maven:os-maven-plugin)
-BuildRequires: mvn(log4j:log4j:1.2.17)
BuildRequires: mvn(org.apache.felix:maven-bundle-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-antrun-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-dependency-plugin)
BuildRequires: mvn(org.apache.maven.plugins:maven-remote-resources-plugin)
+BuildRequires: mvn(org.bouncycastle:bcpkix-jdk15on)
BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin)
BuildRequires: mvn(org.codehaus.mojo:exec-maven-plugin)
-BuildRequires: mvn(org.fusesource.hawtjni:maven-hawtjni-plugin)
BuildRequires: mvn(org.jctools:jctools-core)
BuildRequires: mvn(org.slf4j:slf4j-api)
-%if %{without jp_minimal}
-BuildRequires: mvn(com.fasterxml:aalto-xml)
-BuildRequires: mvn(com.github.jponge:lzma-java)
-BuildRequires: mvn(com.ning:compress-lzf)
-BuildRequires: mvn(net.jpountz.lz4:lz4)
-BuildRequires: mvn(org.apache.logging.log4j:log4j-api)
-BuildRequires: mvn(org.bouncycastle:bcpkix-jdk15on)
-BuildRequires: mvn(org.jboss.marshalling:jboss-marshalling)
-BuildRequires: mvn(org.eclipse.jetty.alpn:alpn-api)
-%endif
-%ifarch %{arm}
-# Speed up builds on 32bit arm
-# Disable temporarily due to
https://bugzilla.redhat.com/show_bug.cgi?id=1818078
-#BuildRequires: java-1.8.0-openjdk-aarch32-devel
-%endif
+BuildArch: noarch
%description
Netty is a NIO client server framework which enables quick and easy
@@ -79,9 +58,8 @@ Summary: API documentation for %{name}
%patch0 -p1
%patch1 -p1
%patch2 -p1
-%if %{with jp_minimal}
%patch3 -p1
-%endif
+%patch4 -p1
# remove unnecessary dependency on parent POM
%pom_remove_parent . bom dev-tools
@@ -89,15 +67,8 @@ Summary: API documentation for %{name}
# Disable all in one jar
%pom_disable_module all
-# Missing Mavenized rxtx
-%pom_disable_module "transport-rxtx"
-# Missing com.barchart.udt:barchart-udt-bundle:jar:2.3.0
-%pom_disable_module "transport-udt"
-# Not needed
+# Not needed for RPM builds
%pom_disable_module "example"
-%pom_disable_module "testsuite"
-%pom_disable_module "testsuite-autobahn"
-%pom_disable_module "testsuite-osgi"
%pom_disable_module "tarball"
%pom_disable_module "microbench"
@@ -112,7 +83,6 @@ Summary: API documentation for %{name}
%pom_remove_plugin :maven-antrun-plugin
%pom_remove_plugin :maven-dependency-plugin
-# style checker
%pom_remove_plugin :xml-maven-plugin
%pom_remove_plugin -r :maven-checkstyle-plugin
%pom_remove_plugin -r :animal-sniffer-maven-plugin
@@ -143,6 +113,10 @@ cp %{SOURCE1} common/codegen.bash
'
%pom_remove_plugin :groovy-maven-plugin common
+# We don't have com.oracle.substratevm
+%pom_remove_dep "com.oracle.substratevm:" common
+rm common/src/main/java/io/netty/util/internal/svm/*
+
# The protobuf-javanano API was discontinued upstream and obsoleted in Fedora
# so disable support for protobuf in the codecs module
%pom_remove_dep -r "com.google.protobuf:protobuf-java"
@@ -150,31 +124,41 @@ cp %{SOURCE1} common/codegen.bash
rm codec/src/main/java/io/netty/handler/codec/protobuf/*
sed -i '/import.*protobuf/d'
codec/src/main/java/io/netty/handler/codec/DatagramPacket*.java
-%if %{with jp_minimal}
+# JBoss marshalling not available in Fedora
%pom_remove_dep -r "org.jboss.marshalling:jboss-marshalling"
rm codec/src/main/java/io/netty/handler/codec/marshalling/*
-%pom_remove_dep -r org.bouncycastle
-rm
handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java
-sed -i '/BouncyCastleSelfSignedCertGenerator/s/.*/throw new
UnsupportedOperationException();/' \
- handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java
-%pom_remove_dep -r com.fasterxml:aalto-xml
-%pom_disable_module codec-xml
+
+# Various compression codecs not available in Fedora
%pom_remove_dep -r com.github.jponge:lzma-java
rm codec/src/*/java/io/netty/handler/codec/compression/Lzma*.java
%pom_remove_dep -r com.ning:compress-lzf
rm codec/src/*/java/io/netty/handler/codec/compression/Lzf*.java
%pom_remove_dep -r net.jpountz.lz4:lz4
rm codec/src/*/java/io/netty/handler/codec/compression/Lz4*.java
-%pom_remove_dep -r org.apache.logging.log4j:
-rm common/*/main/java/io/netty/util/internal/logging/Log4J2*.java
-# Disable rarely needed native artifacts
+# Disable other codecs with extra dependencies
+%pom_remove_dep -r com.fasterxml:aalto-xml
+%pom_disable_module codec-xml
+
+# Disable unneeded transport artifacts
%pom_disable_module transport-native-epoll
%pom_disable_module transport-native-kqueue
-
-%endif
-
-%pom_xpath_inject "pom:execution[pom:id =
'build-native-lib']/pom:configuration"
'<verbose>true</verbose>' transport-native-epoll/pom.xml
+%pom_disable_module transport-native-unix-common
+%pom_disable_module transport-rxtx
+%pom_disable_module transport-sctp
+%pom_disable_module transport-udt
+
+# Disable macos native bit
+%pom_disable_module resolver-dns-native-macos
+
+# Disable test suites
+%pom_disable_module testsuite
+%pom_disable_module testsuite-autobahn
+%pom_disable_module testsuite-http2
+%pom_disable_module testsuite-native-image
+%pom_disable_module testsuite-osgi
+%pom_disable_module testsuite-shading
+%pom_disable_module transport-native-unix-common-tests
# Upstream has jctools bundled.
%pom_xpath_remove "pom:build/pom:plugins/pom:plugin[pom:artifactId =
'maven-bundle-plugin']/pom:executions/pom:execution[pom:id =
'generate-manifest']/pom:configuration/pom:instructions/pom:Import-Package"
common/pom.xml
@@ -184,11 +168,7 @@ rm common/*/main/java/io/netty/util/internal/logging/Log4J2*.java
# the linux classifier.
%mvn_package ":::linux*:"
-%mvn_package ':*-tests' __noinstall
-
%build
-export JAVA_HOME=%{_jvmdir}/java
-
# Ensure we use distro compile flags
export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS"
@@ -204,6 +184,10 @@ export CFLAGS="$RPM_OPT_FLAGS"
LDFLAGS="$RPM_LD_FLAGS"
%license LICENSE.txt NOTICE.txt
%changelog
+* Mon Sep 07 2020 Mat Booth <mat.booth(a)redhat.com> - 4.1.51-1
+- Update to latest upstream version
+- Native bits were not used by anything, so package is now noarch
+
* Tue Jul 28 2020 Fedora Release Engineering <releng(a)fedoraproject.org> -
4.1.13-19
- Rebuilt for
https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
diff --git a/sources b/sources
index 39533ac..a39ea3d 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (netty-4.1.13.Final.tar.gz) =
f0a269adf5b6552eb2f0f12614c2093e0ccfd5a5bb38521dcf39c3827160c8983adcfe1bbcf93a24e71506e323ae723a837621046657fec0df50c59a07aee54c
+SHA512 (netty-4.1.51.Final.tar.gz) =
3b6e00b48710ada4e2c3fbcd71a2c82804dded30c8fa99f10dc609e063642ab5351fe0c26183b03a429439d2351b51ca4cfe803e68dfc5929156faafb1a47800