From efe27e0775367e57921f7946b51bc9a7bd486bf8 Mon Sep 17 00:00:00 2001
From: Mat Booth <mat.booth@redhat.com>
Date: Mon, 7 Sep 2020 13:41:44 +0100
Subject: [PATCH 4/7] Remove optional dep tcnative

---
 handler/pom.xml                               |   11 -
 .../handler/ssl/CipherSuiteConverter.java     |  496 ----
 .../ssl/DefaultOpenSslKeyMaterial.java        |  126 -
 .../java/io/netty/handler/ssl/OpenSsl.java    |  726 -----
 .../ssl/OpenSslAsyncPrivateKeyMethod.java     |   58 -
 .../OpenSslCachingKeyMaterialProvider.java    |   79 -
 .../OpenSslCachingX509KeyManagerFactory.java  |   80 -
 .../ssl/OpenSslCertificateException.java      |   81 -
 .../handler/ssl/OpenSslClientContext.java     |  211 --
 .../io/netty/handler/ssl/OpenSslContext.java  |   60 -
 .../handler/ssl/OpenSslContextOption.java     |   71 -
 .../io/netty/handler/ssl/OpenSslEngine.java   |   41 -
 .../netty/handler/ssl/OpenSslEngineMap.java   |   35 -
 .../ssl/OpenSslKeyMaterialManager.java        |  138 -
 .../ssl/OpenSslKeyMaterialProvider.java       |  154 -
 .../netty/handler/ssl/OpenSslPrivateKey.java  |  191 --
 .../handler/ssl/OpenSslPrivateKeyMethod.java  |   62 -
 .../handler/ssl/OpenSslServerContext.java     |  371 ---
 .../ssl/OpenSslServerSessionContext.java      |   50 -
 .../handler/ssl/OpenSslSessionContext.java    |  229 --
 .../handler/ssl/OpenSslSessionStats.java      |  253 --
 .../handler/ssl/OpenSslSessionTicketKey.java  |   78 -
 .../ssl/OpenSslX509KeyManagerFactory.java     |  416 ---
 .../ReferenceCountedOpenSslClientContext.java |  319 --
 .../ssl/ReferenceCountedOpenSslContext.java   | 1129 -------
 .../ssl/ReferenceCountedOpenSslEngine.java    | 2641 -----------------
 .../ReferenceCountedOpenSslServerContext.java |  298 --
 .../java/io/netty/handler/ssl/SslContext.java |   32 +-
 .../java/io/netty/handler/ssl/SslHandler.java |   47 +-
 .../handler/ssl/SslMasterKeyHandler.java      |    3 -
 .../io/netty/handler/ssl/SslProvider.java     |   20 +-
 .../handler/ssl/ocsp/OcspClientHandler.java   |   61 -
 .../netty/handler/ssl/ocsp/package-info.java  |   23 -
 pom.xml                                       |   17 -
 34 files changed, 3 insertions(+), 8604 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/OpenSslAsyncPrivateKeyMethod.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/OpenSslContextOption.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
 delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java

diff --git a/handler/pom.xml b/handler/pom.xml
index 95480a5f81..87920a8656 100644
--- a/handler/pom.xml
+++ b/handler/pom.xml
@@ -60,17 +60,6 @@
       <artifactId>netty-codec</artifactId>
       <version>${project.version}</version>
     </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>netty-tcnative-classes</artifactId>
-      <optional>true</optional>
-    </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>
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 a9ac8307c1..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-package io.netty.handler.ssl;
-
-import io.netty.util.internal.PlatformDependent;
-import io.netty.util.internal.UnstableApi;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static java.util.Collections.singletonMap;
-
-/**
- * Converts a Java cipher suite string to an OpenSSL cipher suite string and vice versa.
- *
- * @see <a href="https://en.wikipedia.org/wiki/Cipher_suite">Wikipedia page about cipher suite</a>
- */
-@UnstableApi
-public final class CipherSuiteConverter {
-
-    private static final InternalLogger logger = InternalLoggerFactory.getInstance(CipherSuiteConverter.class);
-
-    /**
-     * A_B_WITH_C_D, where:
-     *
-     * A - TLS or SSL (protocol)
-     * B - handshake algorithm (key exchange and authentication algorithms to be precise)
-     * C - bulk cipher
-     * D - HMAC algorithm
-     *
-     * This regular expression assumes that:
-     *
-     * 1) A is always TLS or SSL, and
-     * 2) D is always a single word.
-     */
-    private static final Pattern JAVA_CIPHERSUITE_PATTERN =
-            Pattern.compile("^(?:TLS|SSL)_((?:(?!_WITH_).)+)_WITH_(.*)_(.*)$");
-
-    /**
-     * A-B-C, where:
-     *
-     * A - handshake algorithm (key exchange and authentication algorithms to be precise)
-     * B - bulk cipher
-     * C - HMAC algorithm
-     *
-     * This regular expression assumes that:
-     *
-     * 1) A has some deterministic pattern as shown below, and
-     * 2) C is always a single word
-     */
-    private static final Pattern OPENSSL_CIPHERSUITE_PATTERN =
-            // Be very careful not to break the indentation while editing.
-            Pattern.compile(
-                    "^(?:(" + // BEGIN handshake algorithm
-                        "(?:(?:EXP-)?" +
-                            "(?:" +
-                                "(?:DHE|EDH|ECDH|ECDHE|SRP|RSA)-(?:DSS|RSA|ECDSA|PSK)|" +
-                                "(?:ADH|AECDH|KRB5|PSK|SRP)" +
-                            ')' +
-                        ")|" +
-                        "EXP" +
-                    ")-)?" +  // END handshake algorithm
-                    "(.*)-(.*)$");
-
-    private static final Pattern JAVA_AES_CBC_PATTERN = Pattern.compile("^(AES)_([0-9]+)_CBC$");
-    private static final Pattern JAVA_AES_PATTERN = Pattern.compile("^(AES)_([0-9]+)_(.*)$");
-    private static final Pattern OPENSSL_AES_CBC_PATTERN = Pattern.compile("^(AES)([0-9]+)$");
-    private static final Pattern OPENSSL_AES_PATTERN = Pattern.compile("^(AES)([0-9]+)-(.*)$");
-
-    /**
-     * Java-to-OpenSSL cipher suite conversion map
-     * Note that the Java cipher suite has the protocol prefix (TLS_, SSL_)
-     */
-    private static final ConcurrentMap<String, String> j2o = PlatformDependent.newConcurrentHashMap();
-
-    /**
-     * OpenSSL-to-Java cipher suite conversion map.
-     * Note that one OpenSSL cipher suite can be converted to more than one Java cipher suites because
-     * a Java cipher suite has the protocol name prefix (TLS_, SSL_)
-     */
-    private static final ConcurrentMap<String, Map<String, String>> o2j = PlatformDependent.newConcurrentHashMap();
-
-    private static final Map<String, String> j2oTls13;
-    private static final Map<String, Map<String, String>> o2jTls13;
-
-    static {
-        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);
-    }
-
-    /**
-     * 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));
-        }
-    }
-
-    /**
-     * Converts the specified Java cipher suite to its corresponding OpenSSL cipher suite name.
-     *
-     * @return {@code null} if the conversion has failed
-     */
-    public static String toOpenSsl(String javaCipherSuite, boolean boringSSL) {
-        String converted = j2o.get(javaCipherSuite);
-        if (converted != null) {
-            return converted;
-        }
-        return cacheFromJava(javaCipherSuite, boringSSL);
-    }
-
-    private static String cacheFromJava(String javaCipherSuite, boolean boringSSL) {
-        String converted = j2oTls13.get(javaCipherSuite);
-        if (converted != null) {
-            return boringSSL ? converted : javaCipherSuite;
-        }
-
-        String openSslCipherSuite = toOpenSslUncached(javaCipherSuite, boringSSL);
-        if (openSslCipherSuite == null) {
-            return null;
-        }
-
-        // Cache the mapping.
-        j2o.putIfAbsent(javaCipherSuite, openSslCipherSuite);
-
-        // Cache the reverse mapping after stripping the protocol prefix (TLS_ or SSL_)
-        final String javaCipherSuiteSuffix = javaCipherSuite.substring(4);
-        Map<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);
-
-        logger.debug("Cipher suite mapping: {} => {}", javaCipherSuite, openSslCipherSuite);
-
-        return openSslCipherSuite;
-    }
-
-    static String toOpenSslUncached(String javaCipherSuite, boolean boringSSL) {
-        String converted = j2oTls13.get(javaCipherSuite);
-        if (converted != null) {
-            return boringSSL ? converted : javaCipherSuite;
-        }
-
-        Matcher m = JAVA_CIPHERSUITE_PATTERN.matcher(javaCipherSuite);
-        if (!m.matches()) {
-            return null;
-        }
-
-        String handshakeAlgo = toOpenSslHandshakeAlgo(m.group(1));
-        String bulkCipher = toOpenSslBulkCipher(m.group(2));
-        String hmacAlgo = toOpenSslHmacAlgo(m.group(3));
-        if (handshakeAlgo.isEmpty()) {
-            return bulkCipher + '-' + hmacAlgo;
-        } else if (bulkCipher.contains("CHACHA20")) {
-            return handshakeAlgo + '-' + bulkCipher;
-        } else {
-            return handshakeAlgo + '-' + bulkCipher + '-' + hmacAlgo;
-        }
-    }
-
-    private static String toOpenSslHandshakeAlgo(String handshakeAlgo) {
-        final boolean export = handshakeAlgo.endsWith("_EXPORT");
-        if (export) {
-            handshakeAlgo = handshakeAlgo.substring(0, handshakeAlgo.length() - 7);
-        }
-
-        if ("RSA".equals(handshakeAlgo)) {
-            handshakeAlgo = "";
-        } else if (handshakeAlgo.endsWith("_anon")) {
-            handshakeAlgo = 'A' + handshakeAlgo.substring(0, handshakeAlgo.length() - 5);
-        }
-
-        if (export) {
-            if (handshakeAlgo.isEmpty()) {
-                handshakeAlgo = "EXP";
-            } else {
-                handshakeAlgo = "EXP-" + handshakeAlgo;
-            }
-        }
-
-        return handshakeAlgo.replace('_', '-');
-    }
-
-    private static String toOpenSslBulkCipher(String bulkCipher) {
-        if (bulkCipher.startsWith("AES_")) {
-            Matcher m = JAVA_AES_CBC_PATTERN.matcher(bulkCipher);
-            if (m.matches()) {
-                return m.replaceFirst("$1$2");
-            }
-
-            m = JAVA_AES_PATTERN.matcher(bulkCipher);
-            if (m.matches()) {
-                return m.replaceFirst("$1$2-$3");
-            }
-        }
-
-        if ("3DES_EDE_CBC".equals(bulkCipher)) {
-            return "DES-CBC3";
-        }
-
-        if ("RC4_128".equals(bulkCipher) || "RC4_40".equals(bulkCipher)) {
-            return "RC4";
-        }
-
-        if ("DES40_CBC".equals(bulkCipher) || "DES_CBC_40".equals(bulkCipher)) {
-            return "DES-CBC";
-        }
-
-        if ("RC2_CBC_40".equals(bulkCipher)) {
-            return "RC2-CBC";
-        }
-
-        return bulkCipher.replace('_', '-');
-    }
-
-    private static String toOpenSslHmacAlgo(String hmacAlgo) {
-        // Java and OpenSSL use the same algorithm names for:
-        //
-        //   * SHA
-        //   * SHA256
-        //   * MD5
-        //
-        return hmacAlgo;
-    }
-
-    /**
-     * Convert from OpenSSL cipher suite name convention to java cipher suite name convention.
-     * @param openSslCipherSuite An OpenSSL cipher suite name.
-     * @param protocol The cryptographic protocol (i.e. SSL, TLS, ...).
-     * @return The translated cipher suite name according to java conventions. This will not be {@code null}.
-     */
-    public 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;
-    }
-
-    private static Map<String, String> cacheFromOpenSsl(String openSslCipherSuite) {
-        Map<String, String> converted = o2jTls13.get(openSslCipherSuite);
-        if (converted != null) {
-            return converted;
-        }
-
-        String javaCipherSuiteSuffix = toJavaUncached0(openSslCipherSuite, false);
-        if (javaCipherSuiteSuffix == null) {
-            return null;
-        }
-
-        final String javaCipherSuiteSsl = "SSL_" + javaCipherSuiteSuffix;
-        final String javaCipherSuiteTls = "TLS_" + javaCipherSuiteSuffix;
-
-        // Cache the mapping.
-        final Map<String, String> p2j = new HashMap<String, String>(4);
-        p2j.put("", javaCipherSuiteSuffix);
-        p2j.put("SSL", javaCipherSuiteSsl);
-        p2j.put("TLS", javaCipherSuiteTls);
-        o2j.putIfAbsent(openSslCipherSuite, p2j);
-
-        // Cache the reverse mapping after adding the protocol prefix (TLS_ or SSL_)
-        j2o.putIfAbsent(javaCipherSuiteTls, openSslCipherSuite);
-        j2o.putIfAbsent(javaCipherSuiteSsl, openSslCipherSuite);
-
-        logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteTls, openSslCipherSuite);
-        logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteSsl, openSslCipherSuite);
-
-        return p2j;
-    }
-
-    static String toJavaUncached(String openSslCipherSuite) {
-        return toJavaUncached0(openSslCipherSuite, true);
-    }
-
-    private static String toJavaUncached0(String openSslCipherSuite, boolean checkTls13) {
-        if (checkTls13) {
-            Map<String, String> converted = o2jTls13.get(openSslCipherSuite);
-            if (converted != null) {
-                return converted.get("TLS");
-            }
-        }
-
-        Matcher m = OPENSSL_CIPHERSUITE_PATTERN.matcher(openSslCipherSuite);
-        if (!m.matches()) {
-            return null;
-        }
-
-        String handshakeAlgo = m.group(1);
-        final boolean export;
-        if (handshakeAlgo == null) {
-            handshakeAlgo = "";
-            export = false;
-        } else if (handshakeAlgo.startsWith("EXP-")) {
-            handshakeAlgo = handshakeAlgo.substring(4);
-            export = true;
-        } else if ("EXP".equals(handshakeAlgo)) {
-            handshakeAlgo = "";
-            export = true;
-        } else {
-            export = false;
-        }
-
-        handshakeAlgo = toJavaHandshakeAlgo(handshakeAlgo, export);
-        String bulkCipher = toJavaBulkCipher(m.group(2), export);
-        String hmacAlgo = toJavaHmacAlgo(m.group(3));
-
-        String javaCipherSuite = handshakeAlgo + "_WITH_" + bulkCipher + '_' + hmacAlgo;
-        // For historical reasons the CHACHA20 ciphers do not follow OpenSSL's custom naming convention and omits the
-        // HMAC algorithm portion of the name. There is currently no way to derive this information because it is
-        // omitted from the OpenSSL cipher name, but they currently all use SHA256 for HMAC [1].
-        // [1] https://www.openssl.org/docs/man1.1.0/apps/ciphers.html
-        return bulkCipher.contains("CHACHA20") ? javaCipherSuite + "_SHA256" : javaCipherSuite;
-    }
-
-    private static String toJavaHandshakeAlgo(String handshakeAlgo, boolean export) {
-        if (handshakeAlgo.isEmpty()) {
-            handshakeAlgo = "RSA";
-        } else if ("ADH".equals(handshakeAlgo)) {
-            handshakeAlgo = "DH_anon";
-        } else if ("AECDH".equals(handshakeAlgo)) {
-            handshakeAlgo = "ECDH_anon";
-        }
-
-        handshakeAlgo = handshakeAlgo.replace('-', '_');
-        if (export) {
-            return handshakeAlgo + "_EXPORT";
-        } else {
-            return handshakeAlgo;
-        }
-    }
-
-    private static String toJavaBulkCipher(String bulkCipher, boolean export) {
-        if (bulkCipher.startsWith("AES")) {
-            Matcher m = OPENSSL_AES_CBC_PATTERN.matcher(bulkCipher);
-            if (m.matches()) {
-                return m.replaceFirst("$1_$2_CBC");
-            }
-
-            m = OPENSSL_AES_PATTERN.matcher(bulkCipher);
-            if (m.matches()) {
-                return m.replaceFirst("$1_$2_$3");
-            }
-        }
-
-        if ("DES-CBC3".equals(bulkCipher)) {
-            return "3DES_EDE_CBC";
-        }
-
-        if ("RC4".equals(bulkCipher)) {
-            if (export) {
-                return "RC4_40";
-            } else {
-                return "RC4_128";
-            }
-        }
-
-        if ("DES-CBC".equals(bulkCipher)) {
-            if (export) {
-                return "DES_CBC_40";
-            } else {
-                return "DES_CBC";
-            }
-        }
-
-        if ("RC2-CBC".equals(bulkCipher)) {
-            if (export) {
-                return "RC2_CBC_40";
-            } else {
-                return "RC2_CBC";
-            }
-        }
-
-        return bulkCipher.replace('-', '_');
-    }
-
-    private static String toJavaHmacAlgo(String hmacAlgo) {
-        // Java and OpenSSL use the same algorithm names for:
-        //
-        //   * SHA
-        //   * SHA256
-        //   * MD5
-        //
-        return hmacAlgo;
-    }
-
-    /**
-     * Convert the given ciphers if needed to OpenSSL format and append them to the correct {@link StringBuilder}
-     * depending on if its a TLSv1.3 cipher or not. If this methods returns without throwing an exception its
-     * guaranteed that at least one of the {@link StringBuilder}s contain some ciphers that can be used to configure
-     * OpenSSL.
-     */
-    static void convertToCipherStrings(Iterable<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 (cipherBuilder.length() == 0 && cipherTLSv13Builder.length() == 0) {
-            throw new IllegalArgumentException("empty cipher suites");
-        }
-        if (cipherBuilder.length() > 0) {
-            cipherBuilder.setLength(cipherBuilder.length() - 1);
-        }
-        if (cipherTLSv13Builder.length() > 0) {
-            cipherTLSv13Builder.setLength(cipherTLSv13Builder.length() - 1);
-        }
-    }
-
-    private CipherSuiteConverter() { }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java b/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
deleted file mode 100644
index 6673044eb0..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.SSL;
-import io.netty.util.AbstractReferenceCounted;
-import io.netty.util.IllegalReferenceCountException;
-import io.netty.util.ResourceLeakDetector;
-import io.netty.util.ResourceLeakDetectorFactory;
-import io.netty.util.ResourceLeakTracker;
-
-import java.security.cert.X509Certificate;
-
-final class DefaultOpenSslKeyMaterial extends AbstractReferenceCounted implements OpenSslKeyMaterial {
-
-    private static final ResourceLeakDetector<DefaultOpenSslKeyMaterial> leakDetector =
-            ResourceLeakDetectorFactory.instance().newResourceLeakDetector(DefaultOpenSslKeyMaterial.class);
-    private final ResourceLeakTracker<DefaultOpenSslKeyMaterial> leak;
-    private final X509Certificate[] x509CertificateChain;
-    private long chain;
-    private long privateKey;
-
-    DefaultOpenSslKeyMaterial(long chain, long privateKey, X509Certificate[] x509CertificateChain) {
-        this.chain = chain;
-        this.privateKey = privateKey;
-        this.x509CertificateChain = x509CertificateChain;
-        leak = leakDetector.track(this);
-    }
-
-    @Override
-    public X509Certificate[] certificateChain() {
-        return x509CertificateChain.clone();
-    }
-
-    @Override
-    public long certificateChainAddress() {
-        if (refCnt() <= 0) {
-            throw new IllegalReferenceCountException();
-        }
-        return chain;
-    }
-
-    @Override
-    public long privateKeyAddress() {
-        if (refCnt() <= 0) {
-            throw new IllegalReferenceCountException();
-        }
-        return privateKey;
-    }
-
-    @Override
-    protected void deallocate() {
-        SSL.freeX509Chain(chain);
-        chain = 0;
-        SSL.freePrivateKey(privateKey);
-        privateKey = 0;
-        if (leak != null) {
-            boolean closed = leak.close(this);
-            assert closed;
-        }
-    }
-
-    @Override
-    public DefaultOpenSslKeyMaterial retain() {
-        if (leak != null) {
-            leak.record();
-        }
-        super.retain();
-        return this;
-    }
-
-    @Override
-    public DefaultOpenSslKeyMaterial retain(int increment) {
-        if (leak != null) {
-            leak.record();
-        }
-        super.retain(increment);
-        return this;
-    }
-
-    @Override
-    public DefaultOpenSslKeyMaterial touch() {
-        if (leak != null) {
-            leak.record();
-        }
-        super.touch();
-        return this;
-    }
-
-    @Override
-    public DefaultOpenSslKeyMaterial touch(Object hint) {
-        if (leak != null) {
-            leak.record(hint);
-        }
-        return this;
-    }
-
-    @Override
-    public boolean release() {
-        if (leak != null) {
-            leak.record();
-        }
-        return super.release();
-    }
-
-    @Override
-    public boolean release(int decrement) {
-        if (leak != null) {
-            leak.record();
-        }
-        return super.release(decrement);
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
deleted file mode 100644
index acf4eb65e6..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+++ /dev/null
@@ -1,726 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-package io.netty.handler.ssl;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufAllocator;
-import io.netty.buffer.UnpooledByteBufAllocator;
-import io.netty.internal.tcnative.Buffer;
-import io.netty.internal.tcnative.Library;
-import io.netty.internal.tcnative.SSL;
-import io.netty.internal.tcnative.SSLContext;
-import io.netty.util.CharsetUtil;
-import io.netty.util.ReferenceCountUtil;
-import io.netty.util.ReferenceCounted;
-import io.netty.util.internal.EmptyArrays;
-import io.netty.util.internal.NativeLibraryLoader;
-import io.netty.util.internal.PlatformDependent;
-import io.netty.util.internal.StringUtil;
-import io.netty.util.internal.SystemPropertyUtil;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-import java.io.ByteArrayInputStream;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-import static io.netty.handler.ssl.SslUtils.*;
-
-/**
- * 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 OpenSsl {
-
-    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;
-    static final String EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING;
-    static final String[] NAMED_GROUPS;
-
-    // Use default that is supported in java 11 and earlier and also in OpenSSL / BoringSSL.
-    // See https://github.com/netty/netty-tcnative/issues/567
-    // See https://www.java.com/en/configure_crypto.html for ordering
-    private static final String[] DEFAULT_NAMED_GROUPS = { "x25519", "secp256r1", "secp384r1", "secp521r1" };
-
-    // 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,
-                        PlatformDependent.getClassLoader(OpenSsl.class));
-            } 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;
-            String[] namedGroups = DEFAULT_NAMED_GROUPS;
-            String[] defaultConvertedNamedGroups = new String[namedGroups.length];
-            for (int i = 0; i < namedGroups.length; i++) {
-                defaultConvertedNamedGroups[i] = GroupsConverter.toOpenSsl(namedGroups[i]);
-            }
-
-            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" };
-
-                StringBuilder ciphersBuilder = new StringBuilder(128);
-                for (String cipher: EXTRA_SUPPORTED_TLS_1_3_CIPHERS) {
-                    ciphersBuilder.append(cipher).append(":");
-                }
-                ciphersBuilder.setLength(ciphersBuilder.length() - 1);
-                EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING = ciphersBuilder.toString();
-            }  else {
-                EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
-                EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING = StringUtil.EMPTY_STRING;
-            }
-
-            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 {
-                    // As we delegate to the KeyManager / TrustManager of the JDK we need to ensure it can actually
-                    // handle TLSv13 as otherwise we may see runtime exceptions
-                    if (SslProvider.isTlsv13Supported(SslProvider.JDK)) {
-                        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);
-                        }
-                    }
-
-                    String groups = SystemPropertyUtil.get("jdk.tls.namedGroups", null);
-                    if (groups != null) {
-                        String[] nGroups = groups.split(",");
-                        Set<String> supportedNamedGroups = new LinkedHashSet<String>(nGroups.length);
-                        Set<String> supportedConvertedNamedGroups = new LinkedHashSet<String>(nGroups.length);
-
-                        Set<String> unsupportedNamedGroups = new LinkedHashSet<String>();
-                        for (String namedGroup : nGroups) {
-                            String converted = GroupsConverter.toOpenSsl(namedGroup);
-                            if (SSLContext.setCurvesList(sslCtx, converted)) {
-                                supportedConvertedNamedGroups.add(converted);
-                                supportedNamedGroups.add(namedGroup);
-                            } else {
-                                unsupportedNamedGroups.add(namedGroup);
-                            }
-                        }
-
-                        if (supportedNamedGroups.isEmpty()) {
-                            namedGroups = defaultConvertedNamedGroups;
-                            logger.info("All configured namedGroups are not supported: {}. Use default: {}.",
-                                    Arrays.toString(unsupportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS)),
-                                    Arrays.toString(DEFAULT_NAMED_GROUPS));
-                        } else {
-                            String[] groupArray = supportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS);
-                            if (unsupportedNamedGroups.isEmpty()) {
-                                logger.info("Using configured namedGroups -D 'jdk.tls.namedGroup': {} ",
-                                        Arrays.toString(groupArray));
-                            } else {
-                                logger.info("Using supported configured namedGroups: {}. Unsupported namedGroups: {}. ",
-                                        Arrays.toString(groupArray),
-                                        Arrays.toString(unsupportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS)));
-                            }
-                            namedGroups =  supportedConvertedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS);
-                        }
-                    } else {
-                        namedGroups = defaultConvertedNamedGroups;
-                    }
-                } finally {
-                    SSLContext.free(sslCtx);
-                }
-            } catch (Exception e) {
-                logger.warn("Failed to get the list of available OpenSSL cipher suites.", e);
-            }
-            NAMED_GROUPS = namedGroups;
-            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);
-            // Also handle the extra supported ciphers as these will contain some more stuff on BoringSSL.
-            addIfSupported(availableJavaCipherSuites, defaultCiphers, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
-
-            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(SslProtocols.SSL_v2_HELLO);
-            if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2, SSL.SSL_OP_NO_SSLv2)) {
-                protocols.add(SslProtocols.SSL_v2);
-            }
-            if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3, SSL.SSL_OP_NO_SSLv3)) {
-                protocols.add(SslProtocols.SSL_v3);
-            }
-            if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1, SSL.SSL_OP_NO_TLSv1)) {
-                protocols.add(SslProtocols.TLS_v1);
-            }
-            if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1, SSL.SSL_OP_NO_TLSv1_1)) {
-                protocols.add(SslProtocols.TLS_v1_1);
-            }
-            if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_OP_NO_TLSv1_2)) {
-                protocols.add(SslProtocols.TLS_v1_2);
-            }
-
-            // This is only supported by java8u272 and later.
-            if (tlsv13Supported && doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_3, SSL.SSL_OP_NO_TLSv1_3)) {
-                protocols.add(SslProtocols.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;
-            EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING = StringUtil.EMPTY_STRING;
-            NAMED_GROUPS = DEFAULT_NAMED_GROUPS;
-        }
-    }
-
-    static String checkTls13Ciphers(InternalLogger logger, String ciphers) {
-        if (IS_BORINGSSL && !ciphers.isEmpty()) {
-            assert EXTRA_SUPPORTED_TLS_1_3_CIPHERS.length > 0;
-            Set<String> boringsslTlsv13Ciphers = new HashSet<String>(EXTRA_SUPPORTED_TLS_1_3_CIPHERS.length);
-            Collections.addAll(boringsslTlsv13Ciphers, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
-            boolean ciphersNotMatch = false;
-            for (String cipher: ciphers.split(":")) {
-                if (boringsslTlsv13Ciphers.isEmpty()) {
-                    ciphersNotMatch = true;
-                    break;
-                }
-                if (!boringsslTlsv13Ciphers.remove(cipher) &&
-                        !boringsslTlsv13Ciphers.remove(CipherSuiteConverter.toJava(cipher, "TLS"))) {
-                    ciphersNotMatch = true;
-                    break;
-                }
-            }
-
-            // Also check if there are ciphers left.
-            ciphersNotMatch |= !boringsslTlsv13Ciphers.isEmpty();
-
-            if (ciphersNotMatch) {
-                if (logger.isInfoEnabled()) {
-                    StringBuilder javaCiphers = new StringBuilder(128);
-                    for (String cipher : ciphers.split(":")) {
-                        javaCiphers.append(CipherSuiteConverter.toJava(cipher, "TLS")).append(":");
-                    }
-                    javaCiphers.setLength(javaCiphers.length() - 1);
-                    logger.info(
-                            "BoringSSL doesn't allow to enable or disable TLSv1.3 ciphers explicitly." +
-                                    " Provided TLSv1.3 ciphers: '{}', default TLSv1.3 ciphers that will be used: '{}'.",
-                            javaCiphers, EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING);
-                }
-                return EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING;
-            }
-        }
-        return ciphers;
-    }
-
-    static boolean isSessionCacheSupported() {
-        return version() >= 0x10100000L;
-    }
-
-    /**
-     * Returns a self-signed {@link X509Certificate} for {@code netty.io}.
-     */
-    static X509Certificate selfSignedCertificate() throws CertificateException {
-        return (X509Certificate) SslContext.X509_CERT_FACTORY.generateCertificate(
-                new ByteArrayInputStream(CERT.getBytes(CharsetUtil.US_ASCII))
-        );
-    }
-
-    private static boolean doesSupportOcsp() {
-        boolean supportsOcsp = false;
-        if (version() >= 0x10002000L) {
-            long sslCtx = -1;
-            try {
-                sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_MODE_SERVER);
-                SSLContext.enableOcsp(sslCtx, false);
-                supportsOcsp = true;
-            } catch (Exception ignore) {
-                // ignore
-            } finally {
-                if (sslCtx != -1) {
-                    SSLContext.free(sslCtx);
-                }
-            }
-        }
-        return supportsOcsp;
-    }
-    private static boolean doesSupportProtocol(int protocol, int opt) {
-        if (opt == 0) {
-            // If the opt is 0 the protocol is not supported. This is for example the case with BoringSSL and SSLv2.
-            return false;
-        }
-        long sslCtx = -1;
-        try {
-            sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED);
-            return true;
-        } catch (Exception ignore) {
-            return false;
-        } finally {
-            if (sslCtx != -1) {
-                SSLContext.free(sslCtx);
-            }
-        }
-    }
-
-    /**
-     * Returns {@code true} if and only if
-     * <a href="https://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;
-    }
-
-    /**
-     * Returns {@code true} if the used version of openssl supports
-     * <a href="https://tools.ietf.org/html/rfc7301">ALPN</a>.
-     *
-     * @deprecated use {@link SslProvider#isAlpnSupported(SslProvider)} with {@link SslProvider#OPENSSL}.
-     */
-    @Deprecated
-    public static boolean isAlpnSupported() {
-        return version() >= 0x10002000L;
-    }
-
-    /**
-     * Returns {@code true} if the used version of OpenSSL supports OCSP stapling.
-     */
-    public static boolean isOcspSupported() {
-      return SUPPORTS_OCSP;
-    }
-
-    /**
-     * Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()}
-     * returns {@code false}.
-     */
-    public static int version() {
-        return isAvailable() ? SSL.version() : -1;
-    }
-
-    /**
-     * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()}
-     * returns {@code false}.
-     */
-    public static String versionString() {
-        return isAvailable() ? SSL.versionString() : null;
-    }
-
-    /**
-     * Ensure that <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 static Set<String> availableCipherSuites() {
-        return availableOpenSslCipherSuites();
-    }
-
-    /**
-     * Returns all the available OpenSSL cipher suites.
-     * Please note that the returned array may include the cipher suites that are insecure or non-functional.
-     */
-    public static Set<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 static boolean supportsHostnameValidation() {
-        return isAvailable();
-    }
-
-    static boolean useKeyManagerFactory() {
-        return USE_KEYMANAGER_FACTORY;
-    }
-
-    static long memoryAddress(ByteBuf buf) {
-        assert buf.isDirect();
-        return buf.hasMemoryAddress() ? buf.memoryAddress() :
-                // Use internalNioBuffer to reduce object creation.
-                Buffer.address(buf.internalNioBuffer(0, buf.readableBytes()));
-    }
-
-    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".equals(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(PlatformDependent.getClassLoader(SSLContext.class),
-            libNames.toArray(new String[0]));
-    }
-
-    private static boolean initializeTcNative(String engine) throws Exception {
-        return Library.initialize("provided", engine);
-    }
-
-    static void releaseIfNeeded(ReferenceCounted counted) {
-        if (counted.refCnt() > 0) {
-            ReferenceCountUtil.safeRelease(counted);
-        }
-    }
-
-    static boolean isTlsv13Supported() {
-        return TLSV13_SUPPORTED;
-    }
-
-    static boolean isBoringSSL() {
-        return IS_BORINGSSL;
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslAsyncPrivateKeyMethod.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslAsyncPrivateKeyMethod.java
deleted file mode 100644
index 27edaa629f..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslAsyncPrivateKeyMethod.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2021 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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.SSLPrivateKeyMethod;
-import io.netty.util.concurrent.Future;
-
-import javax.net.ssl.SSLEngine;
-
-public interface OpenSslAsyncPrivateKeyMethod {
-    int SSL_SIGN_RSA_PKCS1_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA1;
-    int SSL_SIGN_RSA_PKCS1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA256;
-    int SSL_SIGN_RSA_PKCS1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA384;
-    int SSL_SIGN_RSA_PKCS1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA512;
-    int SSL_SIGN_ECDSA_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SHA1;
-    int SSL_SIGN_ECDSA_SECP256R1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP256R1_SHA256;
-    int SSL_SIGN_ECDSA_SECP384R1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP384R1_SHA384;
-    int SSL_SIGN_ECDSA_SECP521R1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP521R1_SHA512;
-    int SSL_SIGN_RSA_PSS_RSAE_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA256;
-    int SSL_SIGN_RSA_PSS_RSAE_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA384;
-    int SSL_SIGN_RSA_PSS_RSAE_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA512;
-    int SSL_SIGN_ED25519 = SSLPrivateKeyMethod.SSL_SIGN_ED25519;
-    int SSL_SIGN_RSA_PKCS1_MD5_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_MD5_SHA1;
-
-    /**
-     * Signs the input with the given key and notifies the returned {@link Future} with the signed bytes.
-     *
-     * @param engine                the {@link SSLEngine}
-     * @param signatureAlgorithm    the algorithm to use for signing
-     * @param input                 the digest itself
-     * @return                      the {@link Future} that will be notified with the signed data
-     *                              (must not be {@code null}) when the operation completes.
-     */
-    Future<byte[]> sign(SSLEngine engine, int signatureAlgorithm, byte[] input);
-
-    /**
-     * Decrypts the input with the given key and notifies the returned {@link Future} with the decrypted bytes.
-     *
-     * @param engine                the {@link SSLEngine}
-     * @param input                 the input which should be decrypted
-     * @return                      the {@link Future} that will be notified with the decrypted data
-     *                              (must not be {@code null}) when the operation completes.
-     */
-    Future<byte[]> decrypt(SSLEngine engine, byte[] input);
-}
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 a55007dfdb..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.buffer.ByteBufAllocator;
-
-import javax.net.ssl.X509KeyManager;
-import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * {@link OpenSslKeyMaterialProvider} that will cache the {@link OpenSslKeyMaterial} to reduce the overhead
- * of parsing the chain and the key for generation of the material.
- */
-final class OpenSslCachingKeyMaterialProvider extends OpenSslKeyMaterialProvider {
-
-    private final int maxCachedEntries;
-    private volatile boolean full;
-    private final ConcurrentMap<String, OpenSslKeyMaterial> cache = new ConcurrentHashMap<String, OpenSslKeyMaterial>();
-
-    OpenSslCachingKeyMaterialProvider(X509KeyManager keyManager, String password, int maxCachedEntries) {
-        super(keyManager, password);
-        this.maxCachedEntries = maxCachedEntries;
-    }
-
-    @Override
-    OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
-        OpenSslKeyMaterial material = cache.get(alias);
-        if (material == null) {
-            material = super.chooseKeyMaterial(allocator, alias);
-            if (material == null) {
-                // No keymaterial should be used.
-                return null;
-            }
-
-            if (full) {
-                return material;
-            }
-            if (cache.size() > maxCachedEntries) {
-                full = true;
-                // Do not cache...
-                return material;
-            }
-            OpenSslKeyMaterial old = cache.putIfAbsent(alias, material);
-            if (old != null) {
-                material.release();
-                material = old;
-            }
-        }
-        // We need to call retain() as we want to always have at least a refCnt() of 1 before destroy() was called.
-        return material.retain();
-    }
-
-    @Override
-    void destroy() {
-        // Remove and release all entries.
-        do  {
-            Iterator<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/OpenSslCachingX509KeyManagerFactory.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
deleted file mode 100644
index 7f644e2151..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
+++ /dev/null
@@ -1,80 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.util.internal.ObjectUtil;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.KeyManagerFactorySpi;
-import javax.net.ssl.ManagerFactoryParameters;
-import javax.net.ssl.X509KeyManager;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.X509Certificate;
-
-/**
- * Wraps another {@link KeyManagerFactory} and caches its chains / certs for an alias for better performance when using
- * {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT}.
- *
- * Because of the caching its important that the wrapped {@link KeyManagerFactory}s {@link X509KeyManager}s always
- * return the same {@link X509Certificate} chain and {@link PrivateKey} for the same alias.
- */
-public final class OpenSslCachingX509KeyManagerFactory extends KeyManagerFactory {
-
-    private final int maxCachedEntries;
-
-    public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory) {
-        this(factory, 1024);
-    }
-
-    public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory, int maxCachedEntries) {
-        super(new KeyManagerFactorySpi() {
-            @Override
-            protected void engineInit(KeyStore keyStore, char[] chars)
-                    throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
-                factory.init(keyStore, chars);
-            }
-
-            @Override
-            protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
-                    throws InvalidAlgorithmParameterException {
-                factory.init(managerFactoryParameters);
-            }
-
-            @Override
-            protected KeyManager[] engineGetKeyManagers() {
-                return factory.getKeyManagers();
-            }
-        }, factory.getProvider(), factory.getAlgorithm());
-        this.maxCachedEntries = ObjectUtil.checkPositive(maxCachedEntries, "maxCachedEntries");
-    }
-
-    OpenSslKeyMaterialProvider newProvider(String password) {
-        X509KeyManager keyManager = ReferenceCountedOpenSslContext.chooseX509KeyManager(getKeyManagers());
-        if ("sun.security.ssl.X509KeyManagerImpl".equals(keyManager.getClass().getName())) {
-            // Don't do caching if X509KeyManagerImpl is used as the returned aliases are not stable and will change
-            // between invocations.
-            return new OpenSslKeyMaterialProvider(keyManager, password);
-        }
-        return new OpenSslCachingKeyMaterialProvider(
-                ReferenceCountedOpenSslContext.chooseX509KeyManager(getKeyManagers()), password, maxCachedEntries);
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
deleted file mode 100644
index 39fddf2664..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2016 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.CertificateVerifier;
-
-import java.security.cert.CertificateException;
-
-/**
- * A special {@link CertificateException} which allows to specify which error code is included in the
- * SSL Record. This only work when {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT} is used.
- */
-public final class OpenSslCertificateException extends CertificateException {
-    private static final long serialVersionUID = 5542675253797129798L;
-
-    private final int errorCode;
-
-    /**
-     * Construct a new exception with the
-     * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a>.
-     */
-    public OpenSslCertificateException(int errorCode) {
-        this((String) null, errorCode);
-    }
-
-    /**
-     * Construct a new exception with the msg and
-     * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
-     */
-    public OpenSslCertificateException(String msg, int errorCode) {
-        super(msg);
-        this.errorCode = checkErrorCode(errorCode);
-    }
-
-    /**
-     * Construct a new exception with the msg, cause and
-     * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
-     */
-    public OpenSslCertificateException(String message, Throwable cause, int errorCode) {
-        super(message, cause);
-        this.errorCode = checkErrorCode(errorCode);
-    }
-
-    /**
-     * Construct a new exception with the cause and
-     * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
-     */
-    public OpenSslCertificateException(Throwable cause, int errorCode) {
-        this(null, cause, errorCode);
-    }
-
-    /**
-     * Return the <a href="https://www.openssl.org/docs/man1.0.2/apps/verify.html">error code</a> to use.
-     */
-    public int errorCode() {
-        return errorCode;
-    }
-
-    private static int checkErrorCode(int errorCode) {
-        // Call OpenSsl.isAvailable() to ensure we try to load the native lib as CertificateVerifier.isValid(...)
-        // will depend on it. If loading fails we will just skip the validation.
-        if (OpenSsl.isAvailable() && !CertificateVerifier.isValid(errorCode)) {
-            throw new IllegalArgumentException("errorCode '" + errorCode +
-                    "' invalid, see https://www.openssl.org/docs/man1.0.2/apps/verify.html.");
-        }
-        return errorCode;
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
deleted file mode 100644
index 3648b71af9..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+++ /dev/null
@@ -1,211 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.SSL;
-
-import java.io.File;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.Map;
-
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-
-import static io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext;
-
-/**
- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
- * <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}.
- */
-public final class OpenSslClientContext extends OpenSslContext {
-    private final OpenSslSessionContext sessionContext;
-
-    /**
-     * Creates a new instance.
-     * @deprecated use {@link SslContextBuilder}
-     */
-    @Deprecated
-    public OpenSslClientContext() throws SSLException {
-        this(null, null, null, null, null, null, null, IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
-    }
-
-    /**
-     * Creates a new instance.
-     *
-     * @param certChainFile an X.509 certificate chain file in PEM format.
-     *                      {@code null} to use the system default
-     * @deprecated use {@link SslContextBuilder}
-     */
-    @Deprecated
-    public OpenSslClientContext(File certChainFile) throws SSLException {
-        this(certChainFile, null);
-    }
-
-    /**
-     * Creates a new instance.
-     *
-     * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-     *                            that verifies the certificates sent from servers.
-     *                            {@code null} to use the default.
-     * @deprecated use {@link SslContextBuilder}
-     */
-    @Deprecated
-    public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws SSLException {
-        this(null, trustManagerFactory);
-    }
-
-    /**
-     * Creates a new instance.
-     *
-     * @param certChainFile an X.509 certificate chain file in PEM format.
-     *                      {@code null} to use the system default
-     * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-     *                            that verifies the certificates sent from servers.
-     *                            {@code null} to use the default.
-     * @deprecated use {@link SslContextBuilder}
-     */
-    @Deprecated
-    public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
-        this(certChainFile, trustManagerFactory, null, null, null, null, null,
-             IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
-    }
-
-    /**
-     * Creates a new instance.
-     *
-     * @param certChainFile an X.509 certificate chain file in PEM format
-     * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-     *                            that verifies the certificates sent from servers.
-     *                            {@code null} to use the default..
-     * @param ciphers the cipher suites to enable, in the order of preference.
-     *                {@code null} to use the default cipher suites.
-     * @param apn Provides a means to configure parameters related to application protocol negotiation.
-     * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-     *                         {@code 0} to use the default value.
-     * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-     *                       {@code 0} to use the default value.
-     * @deprecated use {@link SslContextBuilder}
-     */
-    @Deprecated
-    public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<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 trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-     *                            that verifies the certificates sent from servers.
-     *                            {@code null} to use the default..
-     * @param ciphers the cipher suites to enable, in the order of preference.
-     *                {@code null} to use the default cipher suites.
-     * @param cipherFilter a filter to apply over the supplied list of ciphers
-     * @param apn Provides a means to configure parameters related to application protocol negotiation.
-     * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-     *                         {@code 0} to use the default value.
-     * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-     *                       {@code 0} to use the default value.
-     * @deprecated use {@link SslContextBuilder}
-     */
-    @Deprecated
-    public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<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.
-     *                      {@code null} to use the system default
-     * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-     *                            that verifies the certificates sent from servers.
-     *                            {@code null} to use the default or the results of parsing
-     *                            {@code trustCertCollectionFile}
-     * @param keyCertChainFile an X.509 certificate chain file in PEM format.
-     *                      This provides the public key for mutual authentication.
-     *                      {@code null} to use the system default
-     * @param keyFile a PKCS#8 private key file in PEM format.
-     *                      This provides the private key for mutual authentication.
-     *                      {@code null} for no mutual authentication.
-     * @param keyPassword the password of the {@code keyFile}.
-     *                    {@code null} if it's not password-protected.
-     *                    Ignored if {@code keyFile} is {@code null}.
-     * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link javax.net.ssl.KeyManager}s
-     *                          that is used to encrypt data being sent to servers.
-     *                          {@code null} to use the default or the results of parsing
-     *                          {@code keyCertChainFile} and {@code keyFile}.
-     * @param ciphers the cipher suites to enable, in the order of preference.
-     *                {@code null} to use the default cipher suites.
-     * @param cipherFilter a filter to apply over the supplied list of ciphers
-     * @param apn Application Protocol Negotiator object.
-     * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-     *                         {@code 0} to use the default value.
-     * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-     *                       {@code 0} to use the default value.
-     * @deprecated use {@link SslContextBuilder}
-     */
-    @Deprecated
-    public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
-                                File keyCertChainFile, File keyFile, String keyPassword,
-                                KeyManagerFactory keyManagerFactory, Iterable<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, KeyStore.getDefaultType());
-    }
-
-    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,
-                         Map.Entry<SslContextOption<?>, Object>... options)
-            throws SSLException {
-        super(ciphers, cipherFilter, apn, SSL.SSL_MODE_CLIENT, keyCertChain,
-                ClientAuth.NONE, protocols, false, enableOcsp, options);
-        boolean success = false;
-        try {
-            OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword);
-            sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-                                               keyCertChain, key, keyPassword, keyManagerFactory, keyStore,
-                                               sessionCacheSize, sessionTimeout);
-            success = true;
-        } finally {
-            if (!success) {
-                release();
-            }
-        }
-    }
-
-    @Override
-    public OpenSslSessionContext sessionContext() {
-        return sessionContext;
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
deleted file mode 100644
index e50108cf35..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+++ /dev/null
@@ -1,60 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.buffer.ByteBufAllocator;
-
-import java.security.cert.Certificate;
-import java.util.Map;
-
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLException;
-
-/**
- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
- * and manually release the native memory see {@link ReferenceCountedOpenSslContext}.
- */
-public abstract class OpenSslContext extends ReferenceCountedOpenSslContext {
-    OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg,
-                   int mode, Certificate[] keyCertChain,
-                   ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp,
-                   Map.Entry<SslContextOption<?>, Object>... options)
-            throws SSLException {
-        super(ciphers, cipherFilter, toNegotiator(apnCfg), mode, keyCertChain,
-                clientAuth, protocols, startTls, enableOcsp, false, options);
-    }
-
-    OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
-                   int mode, Certificate[] keyCertChain,
-                   ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp,
-                   Map.Entry<SslContextOption<?>, Object>... options)
-            throws SSLException {
-        super(ciphers, cipherFilter, apn, mode, keyCertChain,
-                clientAuth, protocols, startTls, enableOcsp, false, options);
-    }
-
-    @Override
-    final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) {
-        return new OpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode);
-    }
-
-    @Override
-    @SuppressWarnings("FinalizeDeclaration")
-    protected final void finalize() throws Throwable {
-        super.finalize();
-        OpenSsl.releaseIfNeeded(this);
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContextOption.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContextOption.java
deleted file mode 100644
index 0d7de98745..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContextOption.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2021 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:
- *
- *   https://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;
-
-/**
- * {@link SslContextOption}s that are specific to the {@link SslProvider#OPENSSL} / {@link SslProvider#OPENSSL_REFCNT}.
- *
- * @param <T>   the type of the value.
- */
-public final class OpenSslContextOption<T> extends SslContextOption<T> {
-
-    private OpenSslContextOption(String name) {
-        super(name);
-    }
-
-    /**
-     * If enabled heavy-operations may be offloaded from the {@link io.netty.channel.EventLoop} if possible.
-     */
-    public static final OpenSslContextOption<Boolean> USE_TASKS =
-            new OpenSslContextOption<Boolean>("USE_TASKS");
-    /**
-     * If enabled <a href="https://tools.ietf.org/html/rfc7918">TLS false start</a> will be enabled if supported.
-     * When TLS false start is enabled the flow of {@link SslHandshakeCompletionEvent}s may be different compared when,
-     * not enabled.
-     *
-     * This is currently only supported when {@code BoringSSL} and ALPN is used.
-     */
-    public static final OpenSslContextOption<Boolean> TLS_FALSE_START =
-            new OpenSslContextOption<Boolean>("TLS_FALSE_START");
-
-    /**
-     * Set the {@link OpenSslPrivateKeyMethod} to use. This allows to offload private-key operations
-     * if needed.
-     *
-     * This is currently only supported when {@code BoringSSL} is used.
-     */
-    public static final OpenSslContextOption<OpenSslPrivateKeyMethod> PRIVATE_KEY_METHOD =
-            new OpenSslContextOption<OpenSslPrivateKeyMethod>("PRIVATE_KEY_METHOD");
-
-    /**
-     * Set the {@link OpenSslAsyncPrivateKeyMethod} to use. This allows to offload private-key operations
-     * if needed.
-     *
-     * This is currently only supported when {@code BoringSSL} is used.
-     */
-    public static final OpenSslContextOption<OpenSslAsyncPrivateKeyMethod> ASYNC_PRIVATE_KEY_METHOD =
-            new OpenSslContextOption<OpenSslAsyncPrivateKeyMethod>("ASYNC_PRIVATE_KEY_METHOD");
-
-    /**
-     * Set the {@link OpenSslCertificateCompressionConfig} to use. This allows for the configuration of certificate
-     * compression algorithms which should be used, the priority of those algorithms and the directions in which
-     * they should be used.
-     *
-     * This is currently only supported when {@code BoringSSL} is used.
-     */
-    public static final OpenSslContextOption<OpenSslCertificateCompressionConfig> CERTIFICATE_COMPRESSION_ALGORITHMS =
-            new OpenSslContextOption<OpenSslCertificateCompressionConfig>("CERTIFICATE_COMPRESSION_ALGORITHMS");
-}
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 a5464adb87..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.buffer.ByteBufAllocator;
-
-import javax.net.ssl.SSLEngine;
-
-/**
- * Implements a {@link SSLEngine} using
- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
- * <p>
- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
- * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}.
- */
-public final class OpenSslEngine extends ReferenceCountedOpenSslEngine {
-    OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int peerPort,
-                  boolean jdkCompatibilityMode) {
-        super(context, alloc, peerHost, peerPort, jdkCompatibilityMode, false);
-    }
-
-    @Override
-    @SuppressWarnings("FinalizeDeclaration")
-    protected void finalize() throws Throwable {
-        super.finalize();
-        OpenSsl.releaseIfNeeded(this);
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
deleted file mode 100644
index 68e2df5713..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-interface OpenSslEngineMap {
-
-    /**
-     * Remove the {@link OpenSslEngine} with the given {@code ssl} address and
-     * return it.
-     */
-    ReferenceCountedOpenSslEngine remove(long ssl);
-
-    /**
-     * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}.
-     */
-    void add(ReferenceCountedOpenSslEngine engine);
-
-    /**
-     * Get the {@link OpenSslEngine} for the given {@code ssl} address.
-     */
-    ReferenceCountedOpenSslEngine get(long ssl);
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
deleted file mode 100644
index e2e20696a2..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
+++ /dev/null
@@ -1,138 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-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.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-
-/**
- * Manages key material for {@link OpenSslEngine}s and so set the right {@link PrivateKey}s and
- * {@link X509Certificate}s.
- */
-final class OpenSslKeyMaterialManager {
-
-    // Code in this class is inspired by code of conscrypts:
-    // - https://android.googlesource.com/platform/external/
-    //   conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java
-    // - https://android.googlesource.com/platform/external/
-    //   conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java
-    //
-    static final String KEY_TYPE_RSA = "RSA";
-    static final String KEY_TYPE_DH_RSA = "DH_RSA";
-    static final String KEY_TYPE_EC = "EC";
-    static final String KEY_TYPE_EC_EC = "EC_EC";
-    static final String KEY_TYPE_EC_RSA = "EC_RSA";
-
-    // key type mappings for types.
-    private static final Map<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);
-    }
-
-    private final OpenSslKeyMaterialProvider provider;
-
-    OpenSslKeyMaterialManager(OpenSslKeyMaterialProvider provider) {
-        this.provider = provider;
-    }
-
-    void setKeyMaterialServerSide(ReferenceCountedOpenSslEngine engine) throws SSLException {
-        String[] authMethods = engine.authMethods();
-        if (authMethods.length == 0) {
-            throw new SSLHandshakeException("Unable to find key material");
-        }
-
-        // authMethods may contain duplicates or may result in the same type
-        // but call chooseServerAlias(...) may be expensive. So let's ensure
-        // we filter out duplicates.
-        Set<String> typeSet = new HashSet<String>(KEY_TYPES.size());
-        for (String authMethod : authMethods) {
-            String type = KEY_TYPES.get(authMethod);
-            if (type != null && typeSet.add(type)) {
-                String alias = chooseServerAlias(engine, type);
-                if (alias != null) {
-                    // We found a match... let's set the key material and return.
-                    setKeyMaterial(engine, alias);
-                    return;
-                }
-            }
-        }
-        throw new SSLHandshakeException("Unable to find key material for auth method(s): "
-                + Arrays.toString(authMethods));
-    }
-
-    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:
-        // https://hg.openjdk.java.net/jdk/jdk11/file/76072a077ee1/
-        // src/java.base/share/classes/sun/security/ssl/CertificateRequest.java#l362
-        if (alias != null) {
-            setKeyMaterial(engine, alias);
-        }
-    }
-
-    private void setKeyMaterial(ReferenceCountedOpenSslEngine engine, String alias) throws SSLException {
-        OpenSslKeyMaterial keyMaterial = null;
-        try {
-            keyMaterial = provider.chooseKeyMaterial(engine.alloc, alias);
-            if (keyMaterial == null) {
-                return;
-            }
-            engine.setKeyMaterial(keyMaterial);
-        } catch (SSLException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new SSLException(e);
-        } finally {
-            if (keyMaterial != null) {
-                keyMaterial.release();
-            }
-        }
-    }
-    private String chooseClientAlias(ReferenceCountedOpenSslEngine engine,
-                                       String[] keyTypes, X500Principal[] issuer) {
-        X509KeyManager manager = provider.keyManager();
-        if (manager instanceof X509ExtendedKeyManager) {
-            return ((X509ExtendedKeyManager) manager).chooseEngineClientAlias(keyTypes, issuer, engine);
-        }
-        return manager.chooseClientAlias(keyTypes, issuer, null);
-    }
-
-    private String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) {
-        X509KeyManager manager = provider.keyManager();
-        if (manager instanceof X509ExtendedKeyManager) {
-            return ((X509ExtendedKeyManager) manager).chooseEngineServerAlias(type, null, engine);
-        }
-        return manager.chooseServerAlias(type, null, null);
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
deleted file mode 100644
index adf545fb61..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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.buffer.ByteBufAllocator;
-import io.netty.buffer.UnpooledByteBufAllocator;
-import io.netty.internal.tcnative.SSL;
-
-import javax.net.ssl.SSLException;
-import javax.net.ssl.X509KeyManager;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-
-import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO;
-
-/**
- * Provides {@link OpenSslKeyMaterial} for a given alias.
- */
-class OpenSslKeyMaterialProvider {
-
-    private final X509KeyManager keyManager;
-    private final String password;
-
-    OpenSslKeyMaterialProvider(X509KeyManager keyManager, String password) {
-        this.keyManager = keyManager;
-        this.password = password;
-    }
-
-    static void validateKeyMaterialSupported(X509Certificate[] keyCertChain, PrivateKey key, String keyPassword)
-            throws SSLException {
-        validateSupported(keyCertChain);
-        validateSupported(key, keyPassword);
-    }
-
-    private static void validateSupported(PrivateKey key, String password) throws SSLException {
-        if (key == null) {
-            return;
-        }
-
-        long pkeyBio = 0;
-        long pkey = 0;
-
-        try {
-            pkeyBio = toBIO(UnpooledByteBufAllocator.DEFAULT, key);
-            pkey = SSL.parsePrivateKey(pkeyBio, password);
-        } catch (Exception e) {
-            throw new SSLException("PrivateKey type not supported " + key.getFormat(), e);
-        } finally {
-            SSL.freeBIO(pkeyBio);
-            if (pkey != 0) {
-                SSL.freePrivateKey(pkey);
-            }
-        }
-    }
-
-    private static void validateSupported(X509Certificate[] certificates) throws SSLException {
-        if (certificates == null || certificates.length == 0) {
-            return;
-        }
-
-        long chainBio = 0;
-        long chain = 0;
-        PemEncoded encoded = null;
-        try {
-            encoded = PemX509Certificate.toPEM(UnpooledByteBufAllocator.DEFAULT, true, certificates);
-            chainBio = toBIO(UnpooledByteBufAllocator.DEFAULT, encoded.retain());
-            chain = SSL.parseX509Chain(chainBio);
-        } catch (Exception e) {
-            throw new SSLException("Certificate type not supported", e);
-        } finally {
-            SSL.freeBIO(chainBio);
-            if (chain != 0) {
-                SSL.freeX509Chain(chain);
-            }
-            if (encoded != null) {
-                encoded.release();
-            }
-        }
-    }
-
-    /**
-     * Returns the underlying {@link X509KeyManager} that is used.
-     */
-    X509KeyManager keyManager() {
-        return keyManager;
-    }
-
-    /**
-     * Returns the {@link OpenSslKeyMaterial} or {@code null} (if none) that should be used during the handshake by
-     * OpenSSL.
-     */
-    OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
-        X509Certificate[] certificates = keyManager.getCertificateChain(alias);
-        if (certificates == null || certificates.length == 0) {
-            return null;
-        }
-
-        PrivateKey key = keyManager.getPrivateKey(alias);
-        PemEncoded encoded = PemX509Certificate.toPEM(allocator, true, certificates);
-        long chainBio = 0;
-        long pkeyBio = 0;
-        long chain = 0;
-        long pkey = 0;
-        try {
-            chainBio = toBIO(allocator, encoded.retain());
-            chain = SSL.parseX509Chain(chainBio);
-
-            OpenSslKeyMaterial keyMaterial;
-            if (key instanceof OpenSslPrivateKey) {
-                keyMaterial = ((OpenSslPrivateKey) key).newKeyMaterial(chain, certificates);
-            } else {
-                pkeyBio = toBIO(allocator, key);
-                pkey = key == null ? 0 : SSL.parsePrivateKey(pkeyBio, password);
-                keyMaterial = new DefaultOpenSslKeyMaterial(chain, pkey, certificates);
-            }
-
-            // See the chain and pkey to 0 so we will not release it as the ownership was
-            // transferred to OpenSslKeyMaterial.
-            chain = 0;
-            pkey = 0;
-            return keyMaterial;
-        } finally {
-            SSL.freeBIO(chainBio);
-            SSL.freeBIO(pkeyBio);
-            if (chain != 0) {
-                SSL.freeX509Chain(chain);
-            }
-            if (pkey != 0) {
-                SSL.freePrivateKey(pkey);
-            }
-            encoded.release();
-        }
-    }
-
-    /**
-     * Will be invoked once the provider should be destroyed.
-     */
-    void destroy() {
-        // NOOP.
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
deleted file mode 100644
index fb6caed2fe..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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.SSL;
-import io.netty.util.AbstractReferenceCounted;
-import io.netty.util.IllegalReferenceCountException;
-import io.netty.util.internal.EmptyArrays;
-
-import javax.security.auth.Destroyable;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-
-final class OpenSslPrivateKey extends AbstractReferenceCounted implements PrivateKey {
-
-    private long privateKeyAddress;
-
-    OpenSslPrivateKey(long privateKeyAddress) {
-        this.privateKeyAddress = privateKeyAddress;
-    }
-
-    @Override
-    public String getAlgorithm() {
-        return "unknown";
-    }
-
-    @Override
-    public String getFormat() {
-        // As we do not support encoding we should return null as stated in the javadocs of PrivateKey.
-        return null;
-    }
-
-    @Override
-    public byte[] getEncoded() {
-        return null;
-    }
-
-    private long privateKeyAddress() {
-        if (refCnt() <= 0) {
-            throw new IllegalReferenceCountException();
-        }
-        return privateKeyAddress;
-    }
-
-    @Override
-    protected void deallocate() {
-        SSL.freePrivateKey(privateKeyAddress);
-        privateKeyAddress = 0;
-    }
-
-    @Override
-    public OpenSslPrivateKey retain() {
-        super.retain();
-        return this;
-    }
-
-    @Override
-    public OpenSslPrivateKey retain(int increment) {
-        super.retain(increment);
-        return this;
-    }
-
-    @Override
-    public OpenSslPrivateKey touch() {
-        super.touch();
-        return this;
-    }
-
-    @Override
-    public OpenSslPrivateKey touch(Object hint) {
-        return this;
-    }
-
-    /**
-     * NOTE: This is a JDK8 interface/method. Due to backwards compatibility
-     * reasons it's not possible to slap the {@code @Override} annotation onto
-     * this method.
-     *
-     * @see Destroyable#destroy()
-     */
-    @Override
-    public void destroy() {
-        release(refCnt());
-    }
-
-    /**
-     * NOTE: This is a JDK8 interface/method. Due to backwards compatibility
-     * reasons it's not possible to slap the {@code @Override} annotation onto
-     * this method.
-     *
-     * @see Destroyable#isDestroyed()
-     */
-    @Override
-    public boolean isDestroyed() {
-        return refCnt() == 0;
-    }
-
-    /**
-     * Create a new {@link OpenSslKeyMaterial} which uses the private key that is held by {@link OpenSslPrivateKey}.
-     *
-     * When the material is created we increment the reference count of the enclosing {@link OpenSslPrivateKey} and
-     * decrement it again when the reference count of the {@link OpenSslKeyMaterial} reaches {@code 0}.
-     */
-    OpenSslKeyMaterial newKeyMaterial(long certificateChain, X509Certificate[] chain) {
-        return new OpenSslPrivateKeyMaterial(certificateChain, chain);
-    }
-
-    // Package-private for unit-test only
-    final class OpenSslPrivateKeyMaterial extends AbstractReferenceCounted implements OpenSslKeyMaterial {
-
-        // Package-private for unit-test only
-        long certificateChain;
-        private final X509Certificate[] x509CertificateChain;
-
-        OpenSslPrivateKeyMaterial(long certificateChain, X509Certificate[] x509CertificateChain) {
-            this.certificateChain = certificateChain;
-            this.x509CertificateChain = x509CertificateChain == null ?
-                    EmptyArrays.EMPTY_X509_CERTIFICATES : x509CertificateChain;
-            OpenSslPrivateKey.this.retain();
-        }
-
-        @Override
-        public X509Certificate[] certificateChain() {
-            return x509CertificateChain.clone();
-        }
-
-        @Override
-        public long certificateChainAddress() {
-            if (refCnt() <= 0) {
-                throw new IllegalReferenceCountException();
-            }
-            return certificateChain;
-        }
-
-        @Override
-        public long privateKeyAddress() {
-            if (refCnt() <= 0) {
-                throw new IllegalReferenceCountException();
-            }
-            return OpenSslPrivateKey.this.privateKeyAddress();
-        }
-
-        @Override
-        public OpenSslKeyMaterial touch(Object hint) {
-            OpenSslPrivateKey.this.touch(hint);
-            return this;
-        }
-
-        @Override
-        public OpenSslKeyMaterial retain() {
-            super.retain();
-            return this;
-        }
-
-        @Override
-        public OpenSslKeyMaterial retain(int increment) {
-            super.retain(increment);
-            return this;
-        }
-
-        @Override
-        public OpenSslKeyMaterial touch() {
-            OpenSslPrivateKey.this.touch();
-            return this;
-        }
-
-        @Override
-        protected void deallocate() {
-            releaseChain();
-            OpenSslPrivateKey.this.release();
-        }
-
-        private void releaseChain() {
-            SSL.freeX509Chain(certificateChain);
-            certificateChain = 0;
-        }
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
deleted file mode 100644
index 84c8229624..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2019 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.SSLPrivateKeyMethod;
-import io.netty.util.internal.UnstableApi;
-
-import javax.net.ssl.SSLEngine;
-
-/**
- * Allow to customize private key signing / decrypting (when using RSA). Only supported when using BoringSSL atm.
- */
-@UnstableApi
-public interface OpenSslPrivateKeyMethod {
-    int SSL_SIGN_RSA_PKCS1_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA1;
-    int SSL_SIGN_RSA_PKCS1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA256;
-    int SSL_SIGN_RSA_PKCS1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA384;
-    int SSL_SIGN_RSA_PKCS1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA512;
-    int SSL_SIGN_ECDSA_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SHA1;
-    int SSL_SIGN_ECDSA_SECP256R1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP256R1_SHA256;
-    int SSL_SIGN_ECDSA_SECP384R1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP384R1_SHA384;
-    int SSL_SIGN_ECDSA_SECP521R1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP521R1_SHA512;
-    int SSL_SIGN_RSA_PSS_RSAE_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA256;
-    int SSL_SIGN_RSA_PSS_RSAE_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA384;
-    int SSL_SIGN_RSA_PSS_RSAE_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA512;
-    int SSL_SIGN_ED25519 = SSLPrivateKeyMethod.SSL_SIGN_ED25519;
-    int SSL_SIGN_RSA_PKCS1_MD5_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_MD5_SHA1;
-
-    /**
-     * Signs the input with the given key and returns the signed bytes.
-     *
-     * @param engine                the {@link SSLEngine}
-     * @param signatureAlgorithm    the algorithm to use for signing
-     * @param input                 the digest itself
-     * @return                      the signed data (must not be {@code null})
-     * @throws Exception            thrown if an error is encountered during the signing
-     */
-    byte[] sign(SSLEngine engine, int signatureAlgorithm, byte[] input) throws Exception;
-
-    /**
-     * Decrypts the input with the given key and returns the decrypted bytes.
-     *
-     * @param engine                the {@link SSLEngine}
-     * @param input                 the input which should be decrypted
-     * @return                      the decrypted data (must not be {@code null})
-     * @throws Exception            thrown if an error is encountered during the decrypting
-     */
-    byte[] decrypt(SSLEngine engine, byte[] input) throws Exception;
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
deleted file mode 100644
index 381c846009..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+++ /dev/null
@@ -1,371 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.SSL;
-
-import java.io.File;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.Map;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-
-import static io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.newSessionContext;
-
-/**
- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
- * <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 OpenSslServerContext extends OpenSslContext {
-    private final OpenSslServerSessionContext sessionContext;
-
-    /**
-     * Creates a new instance.
-     *
-     * @param certChainFile an X.509 certificate chain file in PEM format
-     * @param keyFile a PKCS#8 private key file in PEM format
-     * @deprecated use {@link SslContextBuilder}
-     */
-    @Deprecated
-    public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException {
-        this(certChainFile, keyFile, null);
-    }
-
-    /**
-     * Creates a new instance.
-     *
-     * @param certChainFile an X.509 certificate chain file in PEM format
-     * @param keyFile a PKCS#8 private key file in PEM format
-     * @param keyPassword the password of the {@code keyFile}.
-     *                    {@code null} if it's not password-protected.
-     * @deprecated use {@link SslContextBuilder}
-     */
-    @Deprecated
-    public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException {
-        this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE,
-             ApplicationProtocolConfig.DISABLED, 0, 0);
-    }
-
-    /**
-     * Creates a new instance.
-     *
-     * @param certChainFile an X.509 certificate chain file in PEM format
-     * @param keyFile a PKCS#8 private key file in PEM format
-     * @param keyPassword the password of the {@code keyFile}.
-     *                    {@code null} if it's not password-protected.
-     * @param ciphers the cipher suites to enable, in the order of preference.
-     *                {@code null} to use the default cipher suites.
-     * @param apn Provides a means to configure parameters related to application protocol negotiation.
-     * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-     *                         {@code 0} to use the default value.
-     * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-     *                       {@code 0} to use the default value.
-     * @deprecated use {@link SslContextBuilder}
-     */
-    @Deprecated
-    public OpenSslServerContext(
-            File certChainFile, File keyFile, String keyPassword,
-            Iterable<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.
-     * @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);
-    }
-
-    /**
-     * 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);
-    }
-
-    /**
-     * 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);
-    }
-
-    /**
-     * 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);
-    }
-
-    /**
-     * 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);
-    }
-
-    /**
-     * 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 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());
-    }
-
-    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, Map.Entry<SslContextOption<?>, Object>... options)
-            throws SSLException {
-        this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
-                cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
-                enableOcsp, keyStore, options);
-    }
-
-    @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, Map.Entry<SslContextOption<?>, Object>... options)
-            throws SSLException {
-        super(ciphers, cipherFilter, apn, SSL.SSL_MODE_SERVER, keyCertChain,
-                clientAuth, protocols, startTls, enableOcsp, options);
-
-        // 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,
-                                               sessionCacheSize, sessionTimeout);
-            success = true;
-        } finally {
-            if (!success) {
-                release();
-            }
-        }
-    }
-
-    @Override
-    public OpenSslServerSessionContext sessionContext() {
-        return sessionContext;
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
deleted file mode 100644
index eba161f361..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+++ /dev/null
@@ -1,50 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.SSL;
-import io.netty.internal.tcnative.SSLContext;
-
-import java.util.concurrent.locks.Lock;
-
-
-/**
- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side.
- */
-public final class OpenSslServerSessionContext extends OpenSslSessionContext {
-    OpenSslServerSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) {
-        super(context, provider, SSL.SSL_SESS_CACHE_SERVER, new OpenSslSessionCache(context.engineMap));
-    }
-
-    /**
-     * Set the context within which session be reused (server side only)
-     * See <a href="https://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context.html">
-     *     man SSL_CTX_set_session_id_context</a>
-     *
-     * @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name
-     *               of the application and/or the hostname and/or service name
-     * @return {@code true} if success, {@code false} otherwise.
-     */
-    public boolean setSessionIdContext(byte[] sidCtx) {
-        Lock writerLock = context.ctxLock.writeLock();
-        writerLock.lock();
-        try {
-            return SSLContext.setSessionIdContext(context.ctx, sidCtx);
-        } finally {
-            writerLock.unlock();
-        }
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
deleted file mode 100644
index 0da26c9971..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+++ /dev/null
@@ -1,229 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.SSL;
-import io.netty.internal.tcnative.SSLContext;
-import io.netty.internal.tcnative.SessionTicketKey;
-import io.netty.util.internal.ObjectUtil;
-
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionContext;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.concurrent.locks.Lock;
-
-/**
- * OpenSSL specific {@link SSLSessionContext} implementation.
- */
-public abstract class OpenSslSessionContext implements SSLSessionContext {
-
-    private final OpenSslSessionStats stats;
-
-    // The OpenSslKeyMaterialProvider is not really used by the OpenSslSessionContext but only be stored here
-    // to make it easier to destroy it later because the ReferenceCountedOpenSslContext will hold a reference
-    // to OpenSslSessionContext.
-    private final OpenSslKeyMaterialProvider provider;
-
-    final ReferenceCountedOpenSslContext context;
-
-    private final OpenSslSessionCache sessionCache;
-    private final long mask;
-
-    // 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, long mask,
-                          OpenSslSessionCache cache) {
-        this.context = context;
-        this.provider = provider;
-        this.mask = mask;
-        stats = new OpenSslSessionStats(context);
-        sessionCache = cache;
-        SSLContext.setSSLSessionCache(context.ctx, cache);
-    }
-
-    final boolean useKeyManager() {
-        return provider != null;
-    }
-
-    @Override
-    public void setSessionCacheSize(int size) {
-        ObjectUtil.checkPositiveOrZero(size, "size");
-        sessionCache.setSessionCacheSize(size);
-    }
-
-    @Override
-    public int getSessionCacheSize() {
-        return sessionCache.getSessionCacheSize();
-    }
-
-    @Override
-    public void setSessionTimeout(int seconds) {
-        ObjectUtil.checkPositiveOrZero(seconds, "seconds");
-
-        Lock writerLock = context.ctxLock.writeLock();
-        writerLock.lock();
-        try {
-            SSLContext.setSessionCacheTimeout(context.ctx, seconds);
-            sessionCache.setSessionTimeout(seconds);
-        } finally {
-            writerLock.unlock();
-        }
-    }
-
-    @Override
-    public int getSessionTimeout() {
-        return sessionCache.getSessionTimeout();
-    }
-
-    @Override
-    public SSLSession getSession(byte[] bytes) {
-        return sessionCache.getSession(new OpenSslSessionId(bytes));
-    }
-
-    @Override
-    public Enumeration<byte[]> getIds() {
-        return new Enumeration<byte[]>() {
-            private final Iterator<OpenSslSessionId> ids = sessionCache.getIds().iterator();
-            @Override
-            public boolean hasMoreElements() {
-                return ids.hasNext();
-            }
-
-            @Override
-            public byte[] nextElement() {
-                return ids.next().cloneBytes();
-            }
-        };
-    }
-
-    /**
-     * Sets the SSL session ticket keys of this context.
-     * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}.
-     */
-    @Deprecated
-    public void setTicketKeys(byte[] keys) {
-        if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) {
-            throw new IllegalArgumentException("keys.length % " + SessionTicketKey.TICKET_KEY_SIZE  + " != 0");
-        }
-        SessionTicketKey[] tickets = new SessionTicketKey[keys.length / SessionTicketKey.TICKET_KEY_SIZE];
-        for (int i = 0, a = 0; i < tickets.length; i++) {
-            byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE);
-            a += SessionTicketKey.NAME_SIZE;
-            byte[] hmacKey = Arrays.copyOfRange(keys, a, SessionTicketKey.HMAC_KEY_SIZE);
-            i += SessionTicketKey.HMAC_KEY_SIZE;
-            byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE);
-            a += SessionTicketKey.AES_KEY_SIZE;
-            tickets[i] = new SessionTicketKey(name, hmacKey, aesKey);
-        }
-        Lock writerLock = context.ctxLock.writeLock();
-        writerLock.lock();
-        try {
-            SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
-            SSLContext.setSessionTicketKeys(context.ctx, tickets);
-        } finally {
-            writerLock.unlock();
-        }
-    }
-
-    /**
-     * Sets the SSL session ticket keys of this context. Depending on the underlying native library you may omit the
-     * argument or pass an empty array and so let the native library handle the key generation and rotating for you.
-     * If this is supported by the underlying native library should be checked in this case. For example
-     * <a href="https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#Session-tickets/">
-     *     BoringSSL</a> is known to support this.
-     */
-    public void setTicketKeys(OpenSslSessionTicketKey... keys) {
-        ObjectUtil.checkNotNull(keys, "keys");
-        SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length];
-        for (int i = 0; i < ticketKeys.length; i++) {
-            ticketKeys[i] = keys[i].key;
-        }
-        Lock writerLock = context.ctxLock.writeLock();
-        writerLock.lock();
-        try {
-            SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
-            if (ticketKeys.length > 0) {
-                SSLContext.setSessionTicketKeys(context.ctx, ticketKeys);
-            }
-        } finally {
-            writerLock.unlock();
-        }
-    }
-
-    /**
-     * Enable or disable caching of SSL sessions.
-     */
-    public void setSessionCacheEnabled(boolean enabled) {
-        long mode = enabled ? mask | SSL.SSL_SESS_CACHE_NO_INTERNAL_LOOKUP |
-                SSL.SSL_SESS_CACHE_NO_INTERNAL_STORE : SSL.SSL_SESS_CACHE_OFF;
-        Lock writerLock = context.ctxLock.writeLock();
-        writerLock.lock();
-        try {
-            SSLContext.setSessionCacheMode(context.ctx, mode);
-            if (!enabled) {
-                sessionCache.clear();
-            }
-        } finally {
-            writerLock.unlock();
-        }
-    }
-
-    /**
-     * Return {@code true} if caching of SSL sessions is enabled, {@code false} otherwise.
-     */
-    public boolean isSessionCacheEnabled() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return (SSLContext.getSessionCacheMode(context.ctx) & mask) != 0;
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the stats of this context.
-     */
-    public OpenSslSessionStats stats() {
-        return stats;
-    }
-
-    /**
-     * Remove the given {@link OpenSslSession} from the cache, and so not re-use it for new connections.
-     */
-    final void removeFromCache(OpenSslSessionId id) {
-        sessionCache.removeSessionWithId(id);
-    }
-
-    final boolean isInCache(OpenSslSessionId id) {
-        return sessionCache.containsSessionWithId(id);
-    }
-
-    void setSessionFromCache(String host, int port, long ssl) {
-        sessionCache.setSession(ssl, host, port);
-    }
-
-    final void destroy() {
-        if (provider != null) {
-            provider.destroy();
-        }
-        sessionCache.clear();
-    }
-}
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 85a0ee8b04..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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.SSLContext;
-
-import java.util.concurrent.locks.Lock;
-
-/**
- * Stats exposed by an OpenSSL session context.
- *
- * @see <a href="https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_number.html">SSL_CTX_sess_number</a>
- */
-public final class OpenSslSessionStats {
-
-    private final ReferenceCountedOpenSslContext context;
-
-    // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
-    //            the GC to collect OpenSslContext as this would also free the pointer and so could result in a
-    //            segfault when the user calls any of the methods here that try to pass the pointer down to the native
-    //            level.
-    OpenSslSessionStats(ReferenceCountedOpenSslContext context) {
-        this.context = context;
-    }
-
-    /**
-     * Returns the current number of sessions in the internal session cache.
-     */
-    public long number() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionNumber(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of started SSL/TLS handshakes in client mode.
-     */
-    public long connect() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionConnect(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of successfully established SSL/TLS sessions in client mode.
-     */
-    public long connectGood() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionConnectGood(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of start renegotiations in client mode.
-     */
-    public long connectRenegotiate() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionConnectRenegotiate(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of started SSL/TLS handshakes in server mode.
-     */
-    public long accept() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionAccept(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of successfully established SSL/TLS sessions in server mode.
-     */
-    public long acceptGood() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionAcceptGood(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of start renegotiations in server mode.
-     */
-    public long acceptRenegotiate() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionAcceptRenegotiate(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of successfully reused sessions. In client mode, a session set with {@code SSL_set_session}
-     * successfully reused is counted as a hit. In server mode, a session successfully retrieved from internal or
-     * external cache is counted as a hit.
-     */
-    public long hits() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionHits(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of successfully retrieved sessions from the external session cache in server mode.
-     */
-    public long cbHits() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionCbHits(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of sessions proposed by clients that were not found in the internal session cache
-     * in server mode.
-     */
-    public long misses() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionMisses(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of sessions proposed by clients and either found in the internal or external session cache
-     * in server mode, but that were invalid due to timeout. These sessions are not included in the {@link #hits()}
-     * count.
-     */
-    public long timeouts() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionTimeouts(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of sessions that were removed because the maximum session cache size was exceeded.
-     */
-    public long cacheFull() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionCacheFull(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of times a client presented a ticket that did not match any key in the list.
-     */
-    public long ticketKeyFail() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionTicketKeyFail(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of times a client did not present a ticket and we issued a new one
-     */
-    public long ticketKeyNew() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionTicketKeyNew(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of times a client presented a ticket derived from an older key,
-     * and we upgraded to the primary key.
-     */
-    public long ticketKeyRenew() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionTicketKeyRenew(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Returns the number of times a client presented a ticket derived from the primary key.
-     */
-    public long ticketKeyResume() {
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.sessionTicketKeyResume(context.ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
deleted file mode 100644
index 175a37e5fa..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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.internal.tcnative.SessionTicketKey;
-
-/**
- * Session Ticket Key
- */
-public final class OpenSslSessionTicketKey {
-
-    /**
-     * Size of session ticket key name
-     */
-    public static final int NAME_SIZE = SessionTicketKey.NAME_SIZE;
-    /**
-     * Size of session ticket key HMAC key
-     */
-    public static final int HMAC_KEY_SIZE = SessionTicketKey.HMAC_KEY_SIZE;
-    /**
-     * Size of session ticket key AES key
-     */
-    public static final int AES_KEY_SIZE = SessionTicketKey.AES_KEY_SIZE;
-    /**
-     * Size of session ticker key
-     */
-    public static final int TICKET_KEY_SIZE = SessionTicketKey.TICKET_KEY_SIZE;
-
-    final SessionTicketKey key;
-
-    /**
-     * Construct a OpenSslSessionTicketKey.
-     *
-     * @param name the name of the session ticket key
-     * @param hmacKey the HMAC key of the session ticket key
-     * @param aesKey the AES key of the session ticket key
-     */
-    public OpenSslSessionTicketKey(byte[] name, byte[] hmacKey, byte[] aesKey) {
-        key = new SessionTicketKey(name.clone(), hmacKey.clone(), aesKey.clone());
-    }
-
-    /**
-     * Get name.
-     * @return the name of the session ticket key
-     */
-    public byte[] name() {
-        return key.getName().clone();
-    }
-
-    /**
-     * Get HMAC key.
-     * @return the HMAC key of the session ticket key
-     */
-    public byte[] hmacKey() {
-        return key.getHmacKey().clone();
-    }
-
-    /**
-     * Get AES Key.
-     * @return the AES key of the session ticket key
-     */
-    public byte[] aesKey() {
-        return key.getAesKey().clone();
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
deleted file mode 100644
index df711a0bed..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
+++ /dev/null
@@ -1,416 +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:
- *
- *   https://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.checkNonEmpty;
-import static io.netty.util.internal.ObjectUtil.checkNotNull;
-
-import io.netty.buffer.ByteBufAllocator;
-import io.netty.buffer.UnpooledByteBufAllocator;
-import io.netty.internal.tcnative.SSL;
-import io.netty.util.ReferenceCountUtil;
-import io.netty.util.internal.ObjectUtil;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.KeyManagerFactorySpi;
-import javax.net.ssl.ManagerFactoryParameters;
-import javax.net.ssl.X509KeyManager;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.Key;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.KeyStoreSpi;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.Provider;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Special {@link KeyManagerFactory} that pre-compute the keymaterial used when {@link SslProvider#OPENSSL} or
- * {@link SslProvider#OPENSSL_REFCNT} is used and so will improve handshake times and its performance.
- *
- *
- *
- * Because the keymaterial is pre-computed any modification to the {@link KeyStore} is ignored after
- * {@link #init(KeyStore, char[])} is called.
- *
- * {@link #init(ManagerFactoryParameters)} is not supported by this implementation and so a call to it will always
- * result in an {@link InvalidAlgorithmParameterException}.
- */
-public final class OpenSslX509KeyManagerFactory extends KeyManagerFactory {
-
-    private final OpenSslKeyManagerFactorySpi spi;
-
-    public OpenSslX509KeyManagerFactory() {
-        this(newOpenSslKeyManagerFactorySpi(null));
-    }
-
-    public OpenSslX509KeyManagerFactory(Provider provider) {
-        this(newOpenSslKeyManagerFactorySpi(provider));
-    }
-
-    public OpenSslX509KeyManagerFactory(String algorithm, Provider provider) throws NoSuchAlgorithmException {
-        this(newOpenSslKeyManagerFactorySpi(algorithm, provider));
-    }
-
-    private OpenSslX509KeyManagerFactory(OpenSslKeyManagerFactorySpi spi) {
-        super(spi, spi.kmf.getProvider(), spi.kmf.getAlgorithm());
-        this.spi = spi;
-    }
-
-    private static OpenSslKeyManagerFactorySpi newOpenSslKeyManagerFactorySpi(Provider provider) {
-        try {
-            return newOpenSslKeyManagerFactorySpi(null, provider);
-        } catch (NoSuchAlgorithmException e) {
-            // This should never happen as we use the default algorithm.
-            throw new IllegalStateException(e);
-        }
-    }
-
-    private static OpenSslKeyManagerFactorySpi newOpenSslKeyManagerFactorySpi(String algorithm, Provider provider)
-            throws NoSuchAlgorithmException {
-        if (algorithm == null) {
-            algorithm = KeyManagerFactory.getDefaultAlgorithm();
-        }
-        return new OpenSslKeyManagerFactorySpi(
-                provider == null ? KeyManagerFactory.getInstance(algorithm) :
-                        KeyManagerFactory.getInstance(algorithm, provider));
-    }
-
-    OpenSslKeyMaterialProvider newProvider() {
-        return spi.newProvider();
-    }
-
-    private static final class OpenSslKeyManagerFactorySpi extends KeyManagerFactorySpi {
-        final KeyManagerFactory kmf;
-        private volatile ProviderFactory providerFactory;
-
-        OpenSslKeyManagerFactorySpi(KeyManagerFactory kmf) {
-            this.kmf = ObjectUtil.checkNotNull(kmf, "kmf");
-        }
-
-        @Override
-        protected synchronized void engineInit(KeyStore keyStore, char[] chars)
-                throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
-            if (providerFactory != null) {
-                throw new KeyStoreException("Already initialized");
-            }
-            if (!keyStore.aliases().hasMoreElements()) {
-                throw new KeyStoreException("No aliases found");
-            }
-
-            kmf.init(keyStore, chars);
-            providerFactory = new ProviderFactory(ReferenceCountedOpenSslContext.chooseX509KeyManager(
-                    kmf.getKeyManagers()), password(chars), Collections.list(keyStore.aliases()));
-        }
-
-        private static String password(char[] password) {
-            if (password == null || password.length == 0) {
-                return null;
-            }
-            return new String(password);
-        }
-
-        @Override
-        protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
-                throws InvalidAlgorithmParameterException {
-            throw new InvalidAlgorithmParameterException("Not supported");
-        }
-
-        @Override
-        protected KeyManager[] engineGetKeyManagers() {
-            ProviderFactory providerFactory = this.providerFactory;
-            if (providerFactory == null) {
-                throw new IllegalStateException("engineInit(...) not called yet");
-            }
-            return new KeyManager[] { providerFactory.keyManager };
-        }
-
-        OpenSslKeyMaterialProvider newProvider() {
-            ProviderFactory providerFactory = this.providerFactory;
-            if (providerFactory == null) {
-                throw new IllegalStateException("engineInit(...) not called yet");
-            }
-            return providerFactory.newProvider();
-        }
-
-        private static final class ProviderFactory {
-            private final X509KeyManager keyManager;
-            private final String password;
-            private final Iterable<String> aliases;
-
-            ProviderFactory(X509KeyManager keyManager, String password, Iterable<String> aliases) {
-                this.keyManager = keyManager;
-                this.password = password;
-                this.aliases = aliases;
-            }
-
-            OpenSslKeyMaterialProvider newProvider() {
-                return new OpenSslPopulatedKeyMaterialProvider(keyManager,
-                        password, aliases);
-            }
-
-            /**
-             * {@link OpenSslKeyMaterialProvider} implementation that pre-compute the {@link OpenSslKeyMaterial} for
-             * all aliases.
-             */
-            private static final class OpenSslPopulatedKeyMaterialProvider extends OpenSslKeyMaterialProvider {
-                private final Map<String, Object> materialMap;
-
-                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();
-                        }
-                    }
-                    checkNonEmpty(materialMap, "materialMap");
-                }
-
-                @Override
-                OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
-                    Object value = materialMap.get(alias);
-                    if (value == null) {
-                        // There is no keymaterial for the requested alias, return null
-                        return null;
-                    }
-                    if (value instanceof OpenSslKeyMaterial) {
-                        return ((OpenSslKeyMaterial) value).retain();
-                    }
-                    throw (Exception) value;
-                }
-
-                @Override
-                void destroy() {
-                    for (Object material: materialMap.values()) {
-                        ReferenceCountUtil.release(material);
-                    }
-                    materialMap.clear();
-                }
-            }
-        }
-    }
-
-    /**
-     * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its {@link PrivateKey} directly from
-     * an {@code OpenSSL engine} via the
-     * <a href="https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_load_private_key.html">ENGINE_load_private_key</a>
-     * function.
-     */
-    public static OpenSslX509KeyManagerFactory newEngineBased(File certificateChain, String password)
-            throws CertificateException, IOException,
-                   KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
-        return newEngineBased(SslContext.toX509Certificates(certificateChain), password);
-    }
-
-    /**
-     * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its {@link PrivateKey} directly from
-     * an {@code OpenSSL engine} via the
-     * <a href="https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_load_private_key.html">ENGINE_load_private_key</a>
-     * function.
-     */
-    public static OpenSslX509KeyManagerFactory newEngineBased(X509Certificate[] certificateChain, String password)
-            throws CertificateException, IOException,
-                   KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
-        checkNotNull(certificateChain, "certificateChain");
-        KeyStore store = new OpenSslKeyStore(certificateChain.clone(), false);
-        store.load(null, null);
-        OpenSslX509KeyManagerFactory factory = new OpenSslX509KeyManagerFactory();
-        factory.init(store, password == null ? null : password.toCharArray());
-        return factory;
-    }
-
-    /**
-     * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[], String)}.
-     */
-    public static OpenSslX509KeyManagerFactory newKeyless(File chain)
-            throws CertificateException, IOException,
-            KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
-        return newKeyless(SslContext.toX509Certificates(chain));
-    }
-
-    /**
-     * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[], String)}.
-     */
-    public static OpenSslX509KeyManagerFactory newKeyless(InputStream chain)
-            throws CertificateException, IOException,
-            KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
-        return newKeyless(SslContext.toX509Certificates(chain));
-    }
-
-    /**
-     * Returns a new initialized {@link OpenSslX509KeyManagerFactory} which will provide its private key by using the
-     * {@link OpenSslPrivateKeyMethod}.
-     */
-    public static OpenSslX509KeyManagerFactory newKeyless(X509Certificate... certificateChain)
-            throws CertificateException, IOException,
-            KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
-        checkNotNull(certificateChain, "certificateChain");
-        KeyStore store = new OpenSslKeyStore(certificateChain.clone(), true);
-        store.load(null, null);
-        OpenSslX509KeyManagerFactory factory = new OpenSslX509KeyManagerFactory();
-        factory.init(store, null);
-        return factory;
-    }
-
-    private static final class OpenSslKeyStore extends KeyStore {
-        private OpenSslKeyStore(final X509Certificate[] certificateChain, final boolean keyless) {
-            super(new KeyStoreSpi() {
-
-                private final Date creationDate = new Date();
-
-                @Override
-                public Key engineGetKey(String alias, char[] password) throws UnrecoverableKeyException {
-                    if (engineContainsAlias(alias)) {
-                        final long privateKeyAddress;
-                        if (keyless) {
-                            privateKeyAddress = 0;
-                        } else {
-                            try {
-                                privateKeyAddress = SSL.loadPrivateKeyFromEngine(
-                                        alias, password == null ? null : new String(password));
-                            } catch (Exception e) {
-                                UnrecoverableKeyException keyException =
-                                        new UnrecoverableKeyException("Unable to load key from engine");
-                                keyException.initCause(e);
-                                throw keyException;
-                            }
-                        }
-                        return new OpenSslPrivateKey(privateKeyAddress);
-                    }
-                    return null;
-                }
-
-                @Override
-                public Certificate[] engineGetCertificateChain(String alias) {
-                    return engineContainsAlias(alias)? certificateChain.clone() : null;
-                }
-
-                @Override
-                public Certificate engineGetCertificate(String alias) {
-                    return engineContainsAlias(alias)? certificateChain[0] : null;
-                }
-
-                @Override
-                public Date engineGetCreationDate(String alias) {
-                    return engineContainsAlias(alias)? creationDate : null;
-                }
-
-                @Override
-                public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
-                        throws KeyStoreException {
-                    throw new KeyStoreException("Not supported");
-                }
-
-                @Override
-                public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
-                    throw new KeyStoreException("Not supported");
-                }
-
-                @Override
-                public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
-                    throw new KeyStoreException("Not supported");
-                }
-
-                @Override
-                public void engineDeleteEntry(String alias) throws KeyStoreException {
-                    throw new KeyStoreException("Not supported");
-                }
-
-                @Override
-                public Enumeration<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 21bb540506..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
+++ /dev/null
@@ -1,319 +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:
- *
- *   https://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.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.Map;
-import java.util.Set;
-
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509ExtendedTrustManager;
-import javax.net.ssl.X509TrustManager;
-import javax.security.auth.x500.X500Principal;
-
-/**
- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
- * <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 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 final OpenSslSessionContext 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, String keyStore,
-                                         Map.Entry<SslContextOption<?>, Object>... options) throws SSLException {
-        super(ciphers, cipherFilter, toNegotiator(apn), SSL.SSL_MODE_CLIENT, keyCertChain,
-              ClientAuth.NONE, protocols, false, enableOcsp, true, options);
-        boolean success = false;
-        try {
-            sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-                                               keyCertChain, key, keyPassword, keyManagerFactory, keyStore,
-                                               sessionCacheSize, sessionTimeout);
-            success = true;
-        } finally {
-            if (!success) {
-                release();
-            }
-        }
-    }
-
-    @Override
-    public OpenSslSessionContext sessionContext() {
-        return sessionContext;
-    }
-
-    static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
-                                                   OpenSslEngineMap engineMap,
-                                                   X509Certificate[] trustCertCollection,
-                                                   TrustManagerFactory trustManagerFactory,
-                                                   X509Certificate[] keyCertChain, PrivateKey key,
-                                                   String keyPassword, KeyManagerFactory keyManagerFactory,
-                                                   String keyStore, long sessionCacheSize, long sessionTimeout)
-            throws SSLException {
-        if (key == null && keyCertChain != null || key != null && keyCertChain == null) {
-            throw new IllegalArgumentException(
-                    "Either both keyCertChain and key needs to be null or none of them");
-        }
-        OpenSslKeyMaterialProvider keyMaterialProvider = null;
-        try {
-            try {
-                if (!OpenSsl.useKeyManagerFactory()) {
-                    if (keyManagerFactory != null) {
-                        throw new IllegalArgumentException(
-                                "KeyManagerFactory not supported");
-                    }
-                    if (keyCertChain != null/* && key != null*/) {
-                        setKeyMaterial(ctx, keyCertChain, key, keyPassword);
-                    }
-                } else {
-                    // javadocs state that keyManagerFactory has precedent over keyCertChain
-                    if (keyManagerFactory == null && keyCertChain != null) {
-                        char[] keyPasswordChars = keyStorePassword(keyPassword);
-                        KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
-                        if (ks.aliases().hasMoreElements()) {
-                            keyManagerFactory = new OpenSslX509KeyManagerFactory();
-                        } else {
-                            keyManagerFactory = new OpenSslCachingX509KeyManagerFactory(
-                                    KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
-                        }
-                        keyManagerFactory.init(ks, keyPasswordChars);
-                        keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
-                    } else if (keyManagerFactory != null) {
-                        keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
-                    }
-
-                    if (keyMaterialProvider != null) {
-                        OpenSslKeyMaterialManager materialManager = new OpenSslKeyMaterialManager(keyMaterialProvider);
-                        SSLContext.setCertificateCallback(ctx, new OpenSslClientCertificateCallback(
-                                engineMap, materialManager));
-                    }
-                }
-            } catch (Exception e) {
-                throw new SSLException("failed to set certificate and key", e);
-            }
-
-            // On the client side we always need to use SSL_CVERIFY_OPTIONAL (which will translate to SSL_VERIFY_PEER)
-            // to ensure that when the TrustManager throws we will produce the correct alert back to the server.
-            //
-            // See:
-            //   - https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
-            //   - https://github.com/netty/netty/issues/8942
-            SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_OPTIONAL, VERIFY_DEPTH);
-
-            try {
-                if (trustCertCollection != null) {
-                    trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
-                } else if (trustManagerFactory == null) {
-                    trustManagerFactory = TrustManagerFactory.getInstance(
-                            TrustManagerFactory.getDefaultAlgorithm());
-                    trustManagerFactory.init((KeyStore) null);
-                }
-                final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
-
-                // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as
-                //            otherwise the context can never be collected. This is because the JNI code holds
-                //            a global reference to the callbacks.
-                //
-                //            See https://github.com/netty/netty/issues/5372
-
-                setVerifyCallback(ctx, engineMap, manager);
-            } catch (Exception e) {
-                if (keyMaterialProvider != null) {
-                    keyMaterialProvider.destroy();
-                }
-                throw new SSLException("unable to setup trustmanager", e);
-            }
-            OpenSslClientSessionContext context = new OpenSslClientSessionContext(thiz, keyMaterialProvider);
-            context.setSessionCacheEnabled(CLIENT_ENABLE_SESSION_CACHE);
-            if (sessionCacheSize > 0) {
-                context.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE));
-            }
-            if (sessionTimeout > 0) {
-                context.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE));
-            }
-
-            if (CLIENT_ENABLE_SESSION_TICKET) {
-                context.setTicketKeys();
-            }
-
-            keyMaterialProvider = null;
-            return context;
-        } finally {
-            if (keyMaterialProvider != null) {
-                keyMaterialProvider.destroy();
-            }
-        }
-    }
-
-    @SuppressJava6Requirement(reason = "Guarded by java version check")
-    private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap, X509TrustManager manager) {
-        // Use this to prevent an error when running on java < 7
-        if (useExtendedTrustManager(manager)) {
-            SSLContext.setCertVerifyCallback(ctx,
-                    new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager));
-        } else {
-            SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
-        }
-    }
-
-    static final class OpenSslClientSessionContext extends OpenSslSessionContext {
-        OpenSslClientSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) {
-            super(context, provider, SSL.SSL_SESS_CACHE_CLIENT, new OpenSslClientSessionCache(context.engineMap));
-        }
-    }
-
-    private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
-        private final X509TrustManager manager;
-
-        TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
-            super(engineMap);
-            this.manager = manager;
-        }
-
-        @Override
-        void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-                throws Exception {
-            manager.checkServerTrusted(peerCerts, auth);
-        }
-    }
-
-    @SuppressJava6Requirement(reason = "Usage guarded by java version check")
-    private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
-        private final X509ExtendedTrustManager manager;
-
-        ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
-            super(engineMap);
-            this.manager = manager;
-        }
-
-        @Override
-        void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-                throws Exception {
-            manager.checkServerTrusted(peerCerts, auth, engine);
-        }
-    }
-
-    private static final class OpenSslClientCertificateCallback implements CertificateCallback {
-        private final OpenSslEngineMap engineMap;
-        private final OpenSslKeyMaterialManager keyManagerHolder;
-
-        OpenSslClientCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
-            this.engineMap = engineMap;
-            this.keyManagerHolder = keyManagerHolder;
-        }
-
-        @Override
-        public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
-            final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-            // May be null if it was destroyed in the meantime.
-            if (engine == null) {
-                return;
-            }
-            try {
-                final Set<String> keyTypesSet = supportedClientKeyTypes(keyTypeBytes);
-                final String[] keyTypes = keyTypesSet.toArray(new String[0]);
-                final X500Principal[] issuers;
-                if (asn1DerEncodedPrincipals == null) {
-                    issuers = null;
-                } else {
-                    issuers = new X500Principal[asn1DerEncodedPrincipals.length];
-                    for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
-                        issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
-                    }
-                }
-                keyManagerHolder.setKeyMaterialClientSide(engine, keyTypes, issuers);
-            } catch (Throwable cause) {
-                engine.initHandshakeException(cause);
-                if (cause instanceof Exception) {
-                    throw (Exception) cause;
-                }
-                throw new SSLException(cause);
-            }
-        }
-
-        /**
-         * Gets the supported key types for client certificates.
-         *
-         * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server.
-         *        See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml.
-         * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and
-         *         {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
-         */
-        private static Set<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;
-        }
-
-        private static String clientKeyType(byte clientCertificateType) {
-            // See also https://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 5b1c195e42..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
+++ /dev/null
@@ -1,1129 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufAllocator;
-import io.netty.handler.ssl.util.LazyX509Certificate;
-import io.netty.internal.tcnative.AsyncSSLPrivateKeyMethod;
-import io.netty.internal.tcnative.CertificateCompressionAlgo;
-import io.netty.internal.tcnative.CertificateVerifier;
-import io.netty.internal.tcnative.ResultCallback;
-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.concurrent.Future;
-import io.netty.util.concurrent.FutureListener;
-import io.netty.util.internal.PlatformDependent;
-import io.netty.util.internal.StringUtil;
-import io.netty.util.internal.SuppressJava6Requirement;
-import io.netty.util.internal.SystemPropertyUtil;
-import io.netty.util.internal.UnstableApi;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-import java.security.PrivateKey;
-import java.security.SignatureException;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateExpiredException;
-import java.security.cert.CertificateNotYetValidException;
-import java.security.cert.CertificateRevokedException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Executor;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509ExtendedTrustManager;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import static io.netty.handler.ssl.OpenSsl.DEFAULT_CIPHERS;
-import static io.netty.handler.ssl.OpenSsl.availableJavaCipherSuites;
-import static io.netty.util.internal.ObjectUtil.checkNotNull;
-import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
-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.
- */
-public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted {
-    private static final InternalLogger logger =
-            InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class);
-
-    private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE = Math.max(1,
-            SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize",
-                    2048));
-    // Let's use tasks by default but still allow the user to disable it via system property just in case.
-    static final boolean USE_TASKS =
-            SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.useTasks", true);
-    private static final Integer DH_KEY_LENGTH;
-    private static final ResourceLeakDetector<ReferenceCountedOpenSslContext> leakDetector =
-            ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class);
-
-    // TODO: Maybe make configurable ?
-    protected static final int VERIFY_DEPTH = 10;
-
-    static final boolean CLIENT_ENABLE_SESSION_TICKET =
-            SystemPropertyUtil.getBoolean("jdk.tls.client.enableSessionTicketExtension", false);
-
-    static final boolean CLIENT_ENABLE_SESSION_TICKET_TLSV13 =
-            SystemPropertyUtil.getBoolean("jdk.tls.client.enableSessionTicketExtension", true);
-
-    static final boolean SERVER_ENABLE_SESSION_TICKET =
-            SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension", false);
-
-     static final boolean SERVER_ENABLE_SESSION_TICKET_TLSV13 =
-            SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension", true);
-
-    static final boolean SERVER_ENABLE_SESSION_CACHE =
-            SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.sessionCacheServer", true);
-    // session caching is disabled by default on the client side due a JDK bug:
-    // https://mail.openjdk.java.net/pipermail/security-dev/2021-March/024758.html
-    static final boolean CLIENT_ENABLE_SESSION_CACHE =
-            SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.sessionCacheClient", false);
-
-    /**
-     * 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 OpenSslApplicationProtocolNegotiator apn;
-    private final int mode;
-
-    // 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);
-            }
-
-            return ReferenceCountedOpenSslContext.this;
-        }
-
-        @Override
-        protected void deallocate() {
-            destroy();
-            if (leak != null) {
-                boolean closed = leak.close(ReferenceCountedOpenSslContext.this);
-                assert closed;
-            }
-        }
-    };
-
-    final Certificate[] keyCertChain;
-    final ClientAuth clientAuth;
-    final String[] protocols;
-    final boolean enableOcsp;
-    final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
-    final ReadWriteLock ctxLock = new ReentrantReadWriteLock();
-
-    private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE;
-
-    @SuppressWarnings("deprecation")
-    static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR =
-            new OpenSslApplicationProtocolNegotiator() {
-                @Override
-                public ApplicationProtocolConfig.Protocol protocol() {
-                    return ApplicationProtocolConfig.Protocol.NONE;
-                }
-
-                @Override
-                public List<String> protocols() {
-                    return Collections.emptyList();
-                }
-
-                @Override
-                public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() {
-                    return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL;
-                }
-
-                @Override
-                public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() {
-                    return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT;
-                }
-            };
-
-    static {
-        Integer dhLen = null;
-
-        try {
-            String dhKeySize = SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize");
-            if (dhKeySize != null) {
-                try {
-                    dhLen = Integer.valueOf(dhKeySize);
-                } catch (NumberFormatException e) {
-                    logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: "
-                            + dhKeySize);
-                }
-            }
-        } catch (Throwable ignore) {
-            // ignore
-        }
-        DH_KEY_LENGTH = dhLen;
-    }
-
-    final boolean tlsFalseStart;
-
-    ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
-                                   OpenSslApplicationProtocolNegotiator apn, int mode, Certificate[] keyCertChain,
-                                   ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp,
-                                   boolean leakDetection, Map.Entry<SslContextOption<?>, Object>... ctxOptions)
-            throws SSLException {
-        super(startTls);
-
-        OpenSsl.ensureAvailability();
-
-        if (enableOcsp && !OpenSsl.isOcspSupported()) {
-            throw new IllegalStateException("OCSP is not supported.");
-        }
-
-        if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) {
-            throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT");
-        }
-
-        boolean tlsFalseStart = false;
-        boolean useTasks = USE_TASKS;
-        OpenSslPrivateKeyMethod privateKeyMethod = null;
-        OpenSslAsyncPrivateKeyMethod asyncPrivateKeyMethod = null;
-        OpenSslCertificateCompressionConfig certCompressionConfig = null;
-
-        if (ctxOptions != null) {
-            for (Map.Entry<SslContextOption<?>, Object> ctxOpt : ctxOptions) {
-                SslContextOption<?> option = ctxOpt.getKey();
-
-                if (option == OpenSslContextOption.TLS_FALSE_START) {
-                    tlsFalseStart = (Boolean) ctxOpt.getValue();
-                } else if (option == OpenSslContextOption.USE_TASKS) {
-                    useTasks = (Boolean) ctxOpt.getValue();
-                } else if (option == OpenSslContextOption.PRIVATE_KEY_METHOD) {
-                    privateKeyMethod = (OpenSslPrivateKeyMethod) ctxOpt.getValue();
-                } else if (option == OpenSslContextOption.ASYNC_PRIVATE_KEY_METHOD) {
-                    asyncPrivateKeyMethod = (OpenSslAsyncPrivateKeyMethod) ctxOpt.getValue();
-                } else if (option == OpenSslContextOption.CERTIFICATE_COMPRESSION_ALGORITHMS) {
-                    certCompressionConfig = (OpenSslCertificateCompressionConfig) ctxOpt.getValue();
-                } else {
-                    logger.debug("Skipping unsupported " + SslContextOption.class.getSimpleName()
-                            + ": " + ctxOpt.getKey());
-                }
-            }
-        }
-        if (privateKeyMethod != null && asyncPrivateKeyMethod != null) {
-            throw new IllegalArgumentException("You can either only use "
-                    + OpenSslAsyncPrivateKeyMethod.class.getSimpleName() + " or "
-                    + OpenSslPrivateKeyMethod.class.getSimpleName());
-        }
-
-        this.tlsFalseStart = tlsFalseStart;
-
-        leak = leakDetection ? leakDetector.track(this) : null;
-        this.mode = mode;
-        this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE;
-        this.protocols = protocols;
-        this.enableOcsp = enableOcsp;
-
-        this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone();
-
-        String[] suites = checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites(
-                ciphers, DEFAULT_CIPHERS, availableJavaCipherSuites());
-        // Filter out duplicates.
-        LinkedHashSet<String> suitesSet = new LinkedHashSet<String>(suites.length);
-        Collections.addAll(suitesSet, suites);
-        unmodifiableCiphers = new ArrayList<String>(suitesSet);
-
-        this.apn = checkNotNull(apn, "apn");
-
-        // Create a new SSL_CTX and configure it.
-        boolean success = false;
-        try {
-            boolean tlsv13Supported = OpenSsl.isTlsv13Supported();
-
-            try {
-                int protocolOpts = SSL.SSL_PROTOCOL_SSLV3 | SSL.SSL_PROTOCOL_TLSV1 |
-                        SSL.SSL_PROTOCOL_TLSV1_1 | SSL.SSL_PROTOCOL_TLSV1_2;
-                if (tlsv13Supported) {
-                    protocolOpts |= SSL.SSL_PROTOCOL_TLSV1_3;
-                }
-                ctx = SSLContext.make(protocolOpts, mode);
-            } catch (Exception e) {
-                throw new SSLException("failed to create an SSL_CTX", e);
-            }
-
-            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,
-                                OpenSsl.checkTls13Ciphers(logger, cipherTLSv13Builder.toString()), true);
-                    }
-                }
-            } catch (SSLException e) {
-                throw e;
-            } catch (Exception e) {
-                throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e);
-            }
-
-            int options = SSLContext.getOptions(ctx) |
-                    SSL.SSL_OP_NO_SSLv2 |
-                    SSL.SSL_OP_NO_SSLv3 |
-                    // Disable TLSv1 and TLSv1.1 by default as these are not considered secure anymore
-                    // and the JDK is doing the same:
-                    // https://www.oracle.com/java/technologies/javase/8u291-relnotes.html
-                    SSL.SSL_OP_NO_TLSv1 |
-                    SSL.SSL_OP_NO_TLSv1_1 |
-
-                    SSL.SSL_OP_CIPHER_SERVER_PREFERENCE |
-
-                    // We do not support compression at the moment so we should explicitly disable it.
-                    SSL.SSL_OP_NO_COMPRESSION |
-
-                    // Disable ticket support by default to be more inline with SSLEngineImpl of the JDK.
-                    // This also let SSLSession.getId() work the same way for the JDK implementation and the
-                    // OpenSSLEngine. If tickets are supported SSLSession.getId() will only return an ID on the
-                    // server-side if it could make use of tickets.
-                    SSL.SSL_OP_NO_TICKET;
-
-            if (cipherBuilder.length() == 0) {
-                // No ciphers that are compatible with SSLv2 / SSLv3 / TLSv1 / TLSv1.1 / TLSv1.2
-                options |= SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1
-                        | SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2;
-            }
-
-            SSLContext.setOptions(ctx, options);
-
-            // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between
-            // calling OpenSSLEngine.wrap(...).
-            // See https://github.com/netty/netty-tcnative/issues/100
-            SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-
-            if (DH_KEY_LENGTH != null) {
-                SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH);
-            }
-
-            List<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();
-                }
-            }
-
-            if (enableOcsp) {
-                SSLContext.enableOcsp(ctx, isClient());
-            }
-
-            SSLContext.setUseTasks(ctx, useTasks);
-            if (privateKeyMethod != null) {
-                SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, privateKeyMethod));
-            }
-            if (asyncPrivateKeyMethod != null) {
-                SSLContext.setPrivateKeyMethod(ctx, new AsyncPrivateKeyMethod(engineMap, asyncPrivateKeyMethod));
-            }
-            if (certCompressionConfig != null) {
-                for (OpenSslCertificateCompressionConfig.AlgorithmConfig configPair : certCompressionConfig) {
-                    final CertificateCompressionAlgo algo = new CompressionAlgorithm(engineMap, configPair.algorithm());
-                    switch (configPair.mode()) {
-                        case Decompress:
-                            SSLContext.addCertificateCompressionAlgorithm(
-                                    ctx, SSL.SSL_CERT_COMPRESSION_DIRECTION_DECOMPRESS, algo);
-                            break;
-                        case Compress:
-                            SSLContext.addCertificateCompressionAlgorithm(
-                                    ctx, SSL.SSL_CERT_COMPRESSION_DIRECTION_COMPRESS, algo);
-                            break;
-                        case Both:
-                            SSLContext.addCertificateCompressionAlgorithm(
-                                    ctx, SSL.SSL_CERT_COMPRESSION_DIRECTION_BOTH, algo);
-                            break;
-                        default:
-                            throw new IllegalStateException();
-                    }
-                }
-            }
-            // Set the curves.
-            SSLContext.setCurvesList(ctx, OpenSsl.NAMED_GROUPS);
-            success = true;
-        } finally {
-            if (!success) {
-                release();
-            }
-        }
-    }
-
-    private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) {
-        switch (behavior) {
-            case NO_ADVERTISE:
-                return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE;
-            case CHOOSE_MY_LAST_PROTOCOL:
-                return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL;
-            default:
-                throw new Error();
-        }
-    }
-
-    @Override
-    public final List<String> cipherSuites() {
-        return unmodifiableCiphers;
-    }
-
-    @Override
-    public ApplicationProtocolNegotiator applicationProtocolNegotiator() {
-        return apn;
-    }
-
-    @Override
-    public final boolean isClient() {
-        return mode == SSL.SSL_MODE_CLIENT;
-    }
-
-    @Override
-    public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) {
-        return newEngine0(alloc, peerHost, peerPort, true);
-    }
-
-    @Override
-    protected final SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
-        return new SslHandler(newEngine0(alloc, null, -1, false), startTls);
-    }
-
-    @Override
-    protected final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls) {
-        return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), startTls);
-    }
-
-    @Override
-    protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor executor) {
-        return new SslHandler(newEngine0(alloc, null, -1, false), startTls, executor);
-    }
-
-    @Override
-    protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort,
-                                    boolean startTls, Executor executor) {
-        return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), executor);
-    }
-
-    SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) {
-        return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode, true);
-    }
-
-    /**
-     * Returns a new server-side {@link SSLEngine} with the current configuration.
-     */
-    @Override
-    public final SSLEngine newEngine(ByteBufAllocator alloc) {
-        return newEngine(alloc, null, -1);
-    }
-
-    /**
-     * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
-     * Be aware that it is freed as soon as the {@link #finalize()}  method is called.
-     * At this point {@code 0} will be returned.
-     *
-     * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
-     */
-    @Deprecated
-    public final long context() {
-        return sslCtxPointer();
-    }
-
-    /**
-     * Returns the stats of this context.
-     *
-     * @deprecated use {@link #sessionContext#stats()}
-     */
-    @Deprecated
-    public final OpenSslSessionStats stats() {
-        return sessionContext().stats();
-    }
-
-    /**
-     * {@deprecated Renegotiation is not supported}
-     * Specify if remote initiated renegotiation is supported or not. If not supported and the remote side tries
-     * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during decoding.
-     */
-    @Deprecated
-    public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) {
-        if (!rejectRemoteInitiatedRenegotiation) {
-            throw new UnsupportedOperationException("Renegotiation is not supported");
-        }
-    }
-
-    /**
-     * {@deprecated Renegotiation is not supported}
-     * @return {@code true} because renegotiation is not supported.
-     */
-    @Deprecated
-    public boolean getRejectRemoteInitiatedRenegotiation() {
-        return true;
-    }
-
-    /**
-     * Set the size of the buffer used by the BIO for non-application based writes
-     * (e.g. handshake, renegotiation, etc...).
-     */
-    public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) {
-        this.bioNonApplicationBufferSize =
-                checkPositiveOrZero(bioNonApplicationBufferSize, "bioNonApplicationBufferSize");
-    }
-
-    /**
-     * Returns the size of the buffer used by the BIO for non-application based writes
-     */
-    public int getBioNonApplicationBufferSize() {
-        return bioNonApplicationBufferSize;
-    }
-
-    /**
-     * Sets the SSL session ticket keys of this context.
-     *
-     * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])}
-     */
-    @Deprecated
-    public final void setTicketKeys(byte[] keys) {
-        sessionContext().setTicketKeys(keys);
-    }
-
-    @Override
-    public abstract OpenSslSessionContext sessionContext();
-
-    /**
-     * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
-     * Be aware that it is freed as soon as the {@link #release()} method is called.
-     * At this point {@code 0} will be returned.
-     *
-     * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
-     */
-    @Deprecated
-    public final long sslCtxPointer() {
-        Lock readerLock = ctxLock.readLock();
-        readerLock.lock();
-        try {
-            return SSLContext.getSslCtx(ctx);
-        } finally {
-            readerLock.unlock();
-        }
-    }
-
-    /**
-     * Set the {@link OpenSslPrivateKeyMethod} to use. This allows to offload private-key operations
-     * if needed.
-     *
-     * This method is currently only supported when {@code BoringSSL} is used.
-     *
-     * @param        method method to use.
-     * @deprecated   use {@link SslContextBuilder#option(SslContextOption, Object)} with
-     *              {@link OpenSslContextOption#PRIVATE_KEY_METHOD}.
-     */
-    @Deprecated
-    @UnstableApi
-    public final void setPrivateKeyMethod(OpenSslPrivateKeyMethod method) {
-        checkNotNull(method, "method");
-        Lock writerLock = ctxLock.writeLock();
-        writerLock.lock();
-        try {
-            SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, method));
-        } finally {
-            writerLock.unlock();
-        }
-    }
-
-    /**
-     * @deprecated   use {@link SslContextBuilder#option(SslContextOption, Object)} with
-     *              {@link OpenSslContextOption#USE_TASKS}.
-     */
-    @Deprecated
-    public final void setUseTasks(boolean useTasks) {
-        Lock writerLock = ctxLock.writeLock();
-        writerLock.lock();
-        try {
-            SSLContext.setUseTasks(ctx, useTasks);
-        } finally {
-            writerLock.unlock();
-        }
-    }
-
-    // IMPORTANT: This method must only be called from either the constructor or the finalizer as a user MUST never
-    //            get access to an OpenSslSessionContext after this method was called to prevent the user from
-    //            producing a segfault.
-    private void destroy() {
-        Lock writerLock = ctxLock.writeLock();
-        writerLock.lock();
-        try {
-            if (ctx != 0) {
-                if (enableOcsp) {
-                    SSLContext.disableOcsp(ctx);
-                }
-
-                SSLContext.free(ctx);
-                ctx = 0;
-
-                OpenSslSessionContext context = sessionContext();
-                if (context != null) {
-                    context.destroy();
-                }
-            }
-        } finally {
-            writerLock.unlock();
-        }
-    }
-
-    protected static X509Certificate[] certificates(byte[][] chain) {
-        X509Certificate[] peerCerts = new X509Certificate[chain.length];
-        for (int i = 0; i < peerCerts.length; i++) {
-            peerCerts[i] = new LazyX509Certificate(chain[i]);
-        }
-        return peerCerts;
-    }
-
-    protected static X509TrustManager chooseTrustManager(TrustManager[] managers) {
-        for (TrustManager m : managers) {
-            if (m instanceof X509TrustManager) {
-                if (PlatformDependent.javaVersion() >= 7) {
-                    return OpenSslX509TrustManagerWrapper.wrapIfNeeded((X509TrustManager) m);
-                }
-                return (X509TrustManager) m;
-            }
-        }
-        throw new IllegalStateException("no X509TrustManager found");
-    }
-
-    protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) {
-        for (KeyManager km : kms) {
-            if (km instanceof X509KeyManager) {
-                return (X509KeyManager) km;
-            }
-        }
-        throw new IllegalStateException("no X509KeyManager found");
-    }
-
-    /**
-     * Translate a {@link ApplicationProtocolConfig} object to a
-     * {@link OpenSslApplicationProtocolNegotiator} object.
-     *
-     * @param config The configuration which defines the translation
-     * @return The results of the translation
-     */
-    @SuppressWarnings("deprecation")
-    static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) {
-        if (config == null) {
-            return NONE_PROTOCOL_NEGOTIATOR;
-        }
-
-        switch (config.protocol()) {
-            case NONE:
-                return NONE_PROTOCOL_NEGOTIATOR;
-            case ALPN:
-            case NPN:
-            case NPN_AND_ALPN:
-                switch (config.selectedListenerFailureBehavior()) {
-                    case CHOOSE_MY_LAST_PROTOCOL:
-                    case ACCEPT:
-                        switch (config.selectorFailureBehavior()) {
-                            case CHOOSE_MY_LAST_PROTOCOL:
-                            case NO_ADVERTISE:
-                                return new OpenSslDefaultApplicationProtocolNegotiator(
-                                        config);
-                            default:
-                                throw new UnsupportedOperationException(
-                                        new StringBuilder("OpenSSL provider does not support ")
-                                                .append(config.selectorFailureBehavior())
-                                                .append(" behavior").toString());
-                        }
-                    default:
-                        throw new UnsupportedOperationException(
-                                new StringBuilder("OpenSSL provider does not support ")
-                                        .append(config.selectedListenerFailureBehavior())
-                                        .append(" behavior").toString());
-                }
-            default:
-                throw new Error();
-        }
-    }
-
-    @SuppressJava6Requirement(reason = "Guarded by java version check")
-    static boolean useExtendedTrustManager(X509TrustManager trustManager) {
-        return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager;
-    }
-
-    @Override
-    public final int refCnt() {
-        return refCnt.refCnt();
-    }
-
-    @Override
-    public final ReferenceCounted retain() {
-        refCnt.retain();
-        return this;
-    }
-
-    @Override
-    public final ReferenceCounted retain(int increment) {
-        refCnt.retain(increment);
-        return this;
-    }
-
-    @Override
-    public final ReferenceCounted touch() {
-        refCnt.touch();
-        return this;
-    }
-
-    @Override
-    public final ReferenceCounted touch(Object hint) {
-        refCnt.touch(hint);
-        return this;
-    }
-
-    @Override
-    public final boolean release() {
-        return refCnt.release();
-    }
-
-    @Override
-    public final boolean release(int decrement) {
-        return refCnt.release(decrement);
-    }
-
-    abstract static class AbstractCertificateVerifier extends CertificateVerifier {
-        private final OpenSslEngineMap engineMap;
-
-        AbstractCertificateVerifier(OpenSslEngineMap engineMap) {
-            this.engineMap = engineMap;
-        }
-
-        @Override
-        public final int verify(long ssl, byte[][] chain, String auth) {
-            final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-            if (engine == null) {
-                // May be null if it was destroyed in the meantime.
-                return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
-            }
-            X509Certificate[] peerCerts = certificates(chain);
-            try {
-                verify(engine, peerCerts, auth);
-                return CertificateVerifier.X509_V_OK;
-            } catch (Throwable cause) {
-                logger.debug("verification of certificate failed", cause);
-                engine.initHandshakeException(cause);
-
-                // Try to extract the correct error code that should be used.
-                if (cause instanceof OpenSslCertificateException) {
-                    // This will never return a negative error code as its validated when constructing the
-                    // OpenSslCertificateException.
-                    return ((OpenSslCertificateException) cause).errorCode();
-                }
-                if (cause instanceof CertificateExpiredException) {
-                    return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
-                }
-                if (cause instanceof CertificateNotYetValidException) {
-                    return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
-                }
-                if (PlatformDependent.javaVersion() >= 7) {
-                    return translateToError(cause);
-                }
-
-                // Could not detect a specific error code to use, so fallback to a default code.
-                return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
-            }
-        }
-
-        @SuppressJava6Requirement(reason = "Usage guarded by java version check")
-        private static int translateToError(Throwable cause) {
-            if (cause instanceof CertificateRevokedException) {
-                return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
-            }
-
-            // The X509TrustManagerImpl uses a Validator which wraps a CertPathValidatorException into
-            // an CertificateException. So we need to handle the wrapped CertPathValidatorException to be
-            // able to send the correct alert.
-            Throwable wrapped = cause.getCause();
-            while (wrapped != null) {
-                if (wrapped instanceof CertPathValidatorException) {
-                    CertPathValidatorException ex = (CertPathValidatorException) wrapped;
-                    CertPathValidatorException.Reason reason = ex.getReason();
-                    if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
-                        return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
-                    }
-                    if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
-                        return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
-                    }
-                    if (reason == CertPathValidatorException.BasicReason.REVOKED) {
-                        return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
-                    }
-                }
-                wrapped = wrapped.getCause();
-            }
-            return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
-        }
-
-        abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
-                             String auth) throws Exception;
-    }
-
-    private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
-        private final Map<Long, ReferenceCountedOpenSslEngine> engines = PlatformDependent.newConcurrentHashMap();
-
-        @Override
-        public ReferenceCountedOpenSslEngine remove(long ssl) {
-            return engines.remove(ssl);
-        }
-
-        @Override
-        public void add(ReferenceCountedOpenSslEngine engine) {
-            engines.put(engine.sslPointer(), engine);
-        }
-
-        @Override
-        public ReferenceCountedOpenSslEngine get(long ssl) {
-            return engines.get(ssl);
-        }
-    }
-
-    static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword)
-            throws SSLException {
-         /* Load the certificate file and private key. */
-        long keyBio = 0;
-        long keyCertChainBio = 0;
-        long keyCertChainBio2 = 0;
-        PemEncoded encoded = null;
-        try {
-            // Only encode one time
-            encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain);
-            keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-            keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-
-            if (key != null) {
-                keyBio = toBIO(ByteBufAllocator.DEFAULT, key);
-            }
-
-            SSLContext.setCertificateBio(
-                    ctx, keyCertChainBio, keyBio,
-                    keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword);
-            // We may have more then one cert in the chain so add all of them now.
-            SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true);
-        } catch (SSLException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new SSLException("failed to set certificate and key", e);
-        } finally {
-            freeBio(keyBio);
-            freeBio(keyCertChainBio);
-            freeBio(keyCertChainBio2);
-            if (encoded != null) {
-                encoded.release();
-            }
-        }
-    }
-
-    static void freeBio(long bio) {
-        if (bio != 0) {
-            SSL.freeBIO(bio);
-        }
-    }
-
-    /**
-     * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
-     * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}.
-     */
-    static long toBIO(ByteBufAllocator allocator, PrivateKey key) throws Exception {
-        if (key == null) {
-            return 0;
-        }
-
-        PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key);
-        try {
-            return toBIO(allocator, pem.retain());
-        } finally {
-            pem.release();
-        }
-    }
-
-    /**
-     * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
-     * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}.
-     */
-    static long toBIO(ByteBufAllocator allocator, X509Certificate... certChain) throws Exception {
-        if (certChain == null) {
-            return 0;
-        }
-
-        checkNonEmpty(certChain, "certChain");
-
-        PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain);
-        try {
-            return toBIO(allocator, pem.retain());
-        } finally {
-            pem.release();
-        }
-    }
-
-    static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception {
-        try {
-            // We can turn direct buffers straight into BIOs. No need to
-            // make a yet another copy.
-            ByteBuf content = pem.content();
-
-            if (content.isDirect()) {
-                return newBIO(content.retainedSlice());
-            }
-
-            ByteBuf buffer = allocator.directBuffer(content.readableBytes());
-            try {
-                buffer.writeBytes(content, content.readerIndex(), content.readableBytes());
-                return newBIO(buffer.retainedSlice());
-            } finally {
-                try {
-                    // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we
-                    // need to zero out the bytes of the copy before we're releasing it.
-                    if (pem.isSensitive()) {
-                        SslUtils.zeroout(buffer);
-                    }
-                } finally {
-                    buffer.release();
-                }
-            }
-        } finally {
-            pem.release();
-        }
-    }
-
-    private static long newBIO(ByteBuf buffer) throws Exception {
-        try {
-            long bio = SSL.newMemBIO();
-            int readable = buffer.readableBytes();
-            if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) {
-                SSL.freeBIO(bio);
-                throw new IllegalStateException("Could not write data to memory BIO");
-            }
-            return bio;
-        } finally {
-            buffer.release();
-        }
-    }
-
-    /**
-     * Returns the {@link OpenSslKeyMaterialProvider} that should be used for OpenSSL. Depending on the given
-     * {@link KeyManagerFactory} this may cache the {@link OpenSslKeyMaterial} for better performance if it can
-     * ensure that the same material is always returned for the same alias.
-     */
-    static OpenSslKeyMaterialProvider providerFor(KeyManagerFactory factory, String password) {
-        if (factory instanceof OpenSslX509KeyManagerFactory) {
-            return ((OpenSslX509KeyManagerFactory) factory).newProvider();
-        }
-
-        if (factory instanceof OpenSslCachingX509KeyManagerFactory) {
-            // The user explicit used OpenSslCachingX509KeyManagerFactory which signals us that its fine to cache.
-            return ((OpenSslCachingX509KeyManagerFactory) factory).newProvider(password);
-        }
-        // We can not be sure if the material may change at runtime so we will not cache it.
-        return new OpenSslKeyMaterialProvider(chooseX509KeyManager(factory.getKeyManagers()), password);
-    }
-
-    private static ReferenceCountedOpenSslEngine retrieveEngine(OpenSslEngineMap engineMap, 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;
-    }
-
-    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;
-        }
-
-        @Override
-        public byte[] sign(long ssl, int signatureAlgorithm, byte[] digest) throws Exception {
-            ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
-            try {
-                return verifyResult(keyMethod.sign(engine, signatureAlgorithm, digest));
-            } catch (Exception e) {
-                engine.initHandshakeException(e);
-                throw e;
-            }
-        }
-
-        @Override
-        public byte[] decrypt(long ssl, byte[] input) throws Exception {
-            ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
-            try {
-                return verifyResult(keyMethod.decrypt(engine, input));
-            } catch (Exception e) {
-                engine.initHandshakeException(e);
-                throw e;
-            }
-        }
-    }
-
-    private static final class AsyncPrivateKeyMethod implements AsyncSSLPrivateKeyMethod {
-
-        private final OpenSslEngineMap engineMap;
-        private final OpenSslAsyncPrivateKeyMethod keyMethod;
-
-        AsyncPrivateKeyMethod(OpenSslEngineMap engineMap, OpenSslAsyncPrivateKeyMethod keyMethod) {
-            this.engineMap = engineMap;
-            this.keyMethod = keyMethod;
-        }
-
-        @Override
-        public void sign(long ssl, int signatureAlgorithm, byte[] bytes, ResultCallback<byte[]> resultCallback) {
-            try {
-                ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
-                keyMethod.sign(engine, signatureAlgorithm, bytes)
-                        .addListener(new ResultCallbackListener(engine, ssl, resultCallback));
-            } catch (SSLException e) {
-                resultCallback.onError(ssl, e);
-            }
-        }
-
-        @Override
-        public void decrypt(long ssl, byte[] bytes, ResultCallback<byte[]> resultCallback) {
-            try {
-                ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
-                keyMethod.decrypt(engine, bytes)
-                        .addListener(new ResultCallbackListener(engine, ssl, resultCallback));
-            } catch (SSLException e) {
-                resultCallback.onError(ssl, e);
-            }
-        }
-
-        private static final class ResultCallbackListener implements FutureListener<byte[]> {
-            private final ReferenceCountedOpenSslEngine engine;
-            private final long ssl;
-            private final ResultCallback<byte[]> resultCallback;
-
-            ResultCallbackListener(ReferenceCountedOpenSslEngine engine, long ssl,
-                                   ResultCallback<byte[]> resultCallback) {
-                this.engine = engine;
-                this.ssl = ssl;
-                this.resultCallback = resultCallback;
-            }
-
-            @Override
-            public void operationComplete(Future<byte[]> future) {
-                Throwable cause = future.cause();
-                if (cause == null) {
-                    try {
-                        byte[] result = verifyResult(future.getNow());
-                        resultCallback.onSuccess(ssl, result);
-                        return;
-                    } catch (SignatureException e) {
-                        cause = e;
-                        engine.initHandshakeException(e);
-                    }
-                }
-                resultCallback.onError(ssl, cause);
-            }
-        }
-    }
-
-    private static byte[] verifyResult(byte[] result) throws SignatureException {
-        if (result == null) {
-            throw new SignatureException();
-        }
-        return result;
-    }
-
-    private static final class CompressionAlgorithm implements CertificateCompressionAlgo {
-        private final OpenSslEngineMap engineMap;
-        private final OpenSslCertificateCompressionAlgorithm compressionAlgorithm;
-
-        CompressionAlgorithm(OpenSslEngineMap engineMap, OpenSslCertificateCompressionAlgorithm compressionAlgorithm) {
-            this.engineMap = engineMap;
-            this.compressionAlgorithm = compressionAlgorithm;
-        }
-
-        @Override
-        public byte[] compress(long ssl, byte[] bytes) throws Exception {
-            ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
-            return compressionAlgorithm.compress(engine, bytes);
-        }
-
-        @Override
-        public byte[] decompress(long ssl, int len, byte[] bytes) throws Exception {
-            ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
-            return compressionAlgorithm.decompress(engine, len, bytes);
-        }
-
-        @Override
-        public int algorithmId() {
-            return compressionAlgorithm.algorithmId();
-        }
-    }
-}
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 ac55afdfb4..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
+++ /dev/null
@@ -1,2641 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufAllocator;
-import io.netty.handler.ssl.util.LazyJavaxX509Certificate;
-import io.netty.handler.ssl.util.LazyX509Certificate;
-import io.netty.internal.tcnative.AsyncTask;
-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.PlatformDependent;
-import io.netty.util.internal.StringUtil;
-import io.netty.util.internal.SuppressJava6Requirement;
-import io.netty.util.internal.ThrowableUtil;
-import io.netty.util.internal.UnstableApi;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-import java.nio.ByteBuffer;
-import java.nio.ReadOnlyBufferException;
-import java.security.Principal;
-import java.security.cert.Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.Lock;
-
-import javax.crypto.spec.SecretKeySpec;
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLEngineResult;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLParameters;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionBindingEvent;
-import javax.net.ssl.SSLSessionBindingListener;
-import javax.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.ObjectUtil.checkNotNull;
-import static io.netty.util.internal.ObjectUtil.checkNotNullArrayParam;
-import static io.netty.util.internal.ObjectUtil.checkNotNullWithIAE;
-import static java.lang.Integer.MAX_VALUE;
-import static java.lang.Math.min;
-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_TASK;
-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
-import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
-import static javax.net.ssl.SSLEngineResult.Status.OK;
-
-/**
- * Implements a {@link SSLEngine} using
- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
- *
- * <p>Instances of this class <strong>must</strong> be released before the {@link ReferenceCountedOpenSslContext}
- * the instance depends upon are released. Otherwise if any method of this class is called which uses the
- * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash.
- */
-public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted, ApplicationProtocolAccessor {
-
-    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class);
-
-    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
-    };
-
-    /**
-     * 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!
-     */
-    static final int MAX_RECORD_SIZE = SSL.SSL_MAX_RECORD_LENGTH;
-
-    private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0);
-    private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
-    private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0);
-    private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0);
-    private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
-
-    // OpenSSL state
-    private long ssl;
-    private long networkBIO;
-
-    private enum HandshakeState {
-        /**
-         * Not started yet.
-         */
-        NOT_STARTED,
-        /**
-         * Started via unwrap/wrap.
-         */
-        STARTED_IMPLICITLY,
-        /**
-         * Started via {@link #beginHandshake()}.
-         */
-        STARTED_EXPLICITLY,
-        /**
-         * Handshake is finished.
-         */
-        FINISHED
-    }
-
-    private HandshakeState handshakeState = HandshakeState.NOT_STARTED;
-    private boolean receivedShutdown;
-    private volatile boolean destroyed;
-    private volatile String applicationProtocol;
-    private volatile boolean needTask;
-    private String[] explicitlyEnabledProtocols;
-    private boolean sessionSet;
-
-    // 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);
-            }
-
-            return ReferenceCountedOpenSslEngine.this;
-        }
-
-        @Override
-        protected void deallocate() {
-            shutdown();
-            if (leak != null) {
-                boolean closed = leak.close(ReferenceCountedOpenSslEngine.this);
-                assert closed;
-            }
-            parentContext.release();
-        }
-    };
-
-    private volatile ClientAuth clientAuth = ClientAuth.NONE;
-
-    // Updated once a new handshake is started and so the SSLSession reused.
-    private volatile long lastAccessed = -1;
-
-    private String endPointIdentificationAlgorithm;
-    // Store as object as AlgorithmConstraints only exists since java 7.
-    private Object algorithmConstraints;
-    private List<String> sniHostNames;
-
-    // Mark as volatile as accessed by checkSniHostnameMatch(...) and also not specify the SNIMatcher type to allow us
-    // using it with java7.
-    private volatile Collection<?> matchers;
-
-    // SSL Engine status variables
-    private boolean isInboundDone;
-    private boolean outboundClosed;
-
-    final boolean jdkCompatibilityMode;
-    private final boolean clientMode;
-    final ByteBufAllocator alloc;
-    private final OpenSslEngineMap engineMap;
-    private final OpenSslApplicationProtocolNegotiator apn;
-    private final ReferenceCountedOpenSslContext parentContext;
-    private final OpenSslSession session;
-    private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1];
-    private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1];
-    private final boolean enableOcsp;
-    private int maxWrapOverhead;
-    private int maxWrapBufferSize;
-    private Throwable pendingException;
-
-    /**
-     * Create a new instance.
-     * @param context Reference count release responsibility is not transferred! The callee still owns this object.
-     * @param alloc The allocator to use.
-     * @param peerHost The peer host name.
-     * @param peerPort The peer port.
-     * @param jdkCompatibilityMode {@code true} to behave like described in
-     *                             https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html.
-     *                             {@code false} allows for partial and/or multiple packets to be process in a single
-     *                             wrap or unwrap call.
-     * @param leakDetection {@code true} to enable leak detection of this object.
-     */
-    ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context, final ByteBufAllocator alloc, String peerHost,
-                                  int peerPort, boolean jdkCompatibilityMode, boolean leakDetection) {
-        super(peerHost, peerPort);
-        OpenSsl.ensureAvailability();
-        this.alloc = checkNotNull(alloc, "alloc");
-        apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator();
-        clientMode = context.isClient();
-
-        if (PlatformDependent.javaVersion() >= 7) {
-            session = new ExtendedOpenSslSession(new DefaultOpenSslSession(context.sessionContext())) {
-                private String[] peerSupportedSignatureAlgorithms;
-                private List requestedServerNames;
-
-                @Override
-                public List getRequestedServerNames() {
-                    if (clientMode) {
-                        return Java8SslUtils.getSniHostNames(sniHostNames);
-                    } else {
-                        synchronized (ReferenceCountedOpenSslEngine.this) {
-                            if (requestedServerNames == null) {
-                                if (isDestroyed()) {
-                                    requestedServerNames = Collections.emptyList();
-                                } else {
-                                    String name = SSL.getSniHostname(ssl);
-                                    if (name == null) {
-                                        requestedServerNames = Collections.emptyList();
-                                    } else {
-                                        // Convert to bytes as we do not want to do any strict validation of the
-                                        // SNIHostName while creating it.
-                                        requestedServerNames =
-                                                Java8SslUtils.getSniHostName(
-                                                        SSL.getSniHostname(ssl).getBytes(CharsetUtil.UTF_8));
-                                    }
-                                }
-                            }
-                            return requestedServerNames;
-                        }
-                    }
-                }
-
-                @Override
-                public String[] getPeerSupportedSignatureAlgorithms() {
-                    synchronized (ReferenceCountedOpenSslEngine.this) {
-                        if (peerSupportedSignatureAlgorithms == null) {
-                            if (isDestroyed()) {
-                                peerSupportedSignatureAlgorithms = EmptyArrays.EMPTY_STRINGS;
-                            } else {
-                                String[] algs = SSL.getSigAlgs(ssl);
-                                if (algs == null) {
-                                    peerSupportedSignatureAlgorithms = EmptyArrays.EMPTY_STRINGS;
-                                } else {
-                                    Set<String> algorithmList = new LinkedHashSet<String>(algs.length);
-                                    for (String alg: algs) {
-                                        String converted = SignatureAlgorithmConverter.toJavaName(alg);
-
-                                        if (converted != null) {
-                                            algorithmList.add(converted);
-                                        }
-                                    }
-                                    peerSupportedSignatureAlgorithms = algorithmList.toArray(new String[0]);
-                                }
-                            }
-                        }
-                        return peerSupportedSignatureAlgorithms.clone();
-                    }
-                }
-
-                @Override
-                public List<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());
-        }
-        engineMap = context.engineMap;
-        enableOcsp = context.enableOcsp;
-        if (!context.sessionContext().useKeyManager()) {
-            session.setLocalCertificate(context.keyCertChain);
-        }
-
-        this.jdkCompatibilityMode = jdkCompatibilityMode;
-        Lock readerLock = context.ctxLock.readLock();
-        readerLock.lock();
-        final long finalSsl;
-        try {
-            finalSsl = SSL.newSSL(context.ctx, !context.isClient());
-        } finally {
-            readerLock.unlock();
-        }
-        synchronized (this) {
-            ssl = finalSsl;
-            try {
-                networkBIO = SSL.bioNewByteBuffer(ssl, context.getBioNonApplicationBufferSize());
-
-                // Set the client auth mode, this needs to be done via setClientAuth(...) method so we actually call the
-                // needed JNI methods.
-                setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth);
-
-                if (context.protocols != null) {
-                    setEnabledProtocols0(context.protocols, true);
-                } else {
-                    this.explicitlyEnabledProtocols = getEnabledProtocols();
-                }
-
-                // Use SNI if peerHost was specified and a valid hostname
-                // See https://github.com/netty/netty/issues/4746
-                if (clientMode && SslUtils.isValidHostNameForSNI(peerHost)) {
-                    // If on java8 and later we should do some extra validation to ensure we can construct the
-                    // SNIHostName later again.
-                    if (PlatformDependent.javaVersion() >= 8) {
-                        if (Java8SslUtils.isValidHostNameForSNI(peerHost)) {
-                            SSL.setTlsExtHostName(ssl, peerHost);
-                            sniHostNames = Collections.singletonList(peerHost);
-                        }
-                    } else {
-                        SSL.setTlsExtHostName(ssl, peerHost);
-                        sniHostNames = Collections.singletonList(peerHost);
-                    }
-                }
-
-                if (enableOcsp) {
-                    SSL.enableOcsp(ssl);
-                }
-
-                if (!jdkCompatibilityMode) {
-                    SSL.setMode(ssl, SSL.getMode(ssl) | SSL.SSL_MODE_ENABLE_PARTIAL_WRITE);
-                }
-
-                if (isProtocolEnabled(SSL.getOptions(ssl), SSL.SSL_OP_NO_TLSv1_3, SslProtocols.TLS_v1_3)) {
-                    final boolean enableTickets = clientMode ?
-                            ReferenceCountedOpenSslContext.CLIENT_ENABLE_SESSION_TICKET_TLSV13 :
-                            ReferenceCountedOpenSslContext.SERVER_ENABLE_SESSION_TICKET_TLSV13;
-                    if (enableTickets) {
-                        // We should enable session tickets for stateless resumption when TLSv1.3 is enabled. This
-                        // is also done by OpenJDK and without this session resumption does not work at all with
-                        // BoringSSL when TLSv1.3 is used as BoringSSL only supports stateless resumption with TLSv1.3:
-                        //
-                        // See:
-                        //  - https://bugs.openjdk.java.net/browse/JDK-8223922
-                        //  - https://boringssl.googlesource.com/boringssl/+/refs/heads/master/ssl/tls13_server.cc#104
-                        SSL.clearOptions(ssl, SSL.SSL_OP_NO_TICKET);
-                    }
-                }
-
-                if (OpenSsl.isBoringSSL() && clientMode) {
-                    // If in client-mode and BoringSSL let's allow to renegotiate once as the server may use this
-                    // for client auth.
-                    //
-                    // See https://github.com/netty/netty/issues/11529
-                    SSL.setRenegotiateMode(ssl, SSL.SSL_RENEGOTIATE_ONCE);
-                }
-                // setMode may impact the overhead.
-                calculateMaxWrapOverhead();
-            } catch (Throwable cause) {
-                // Call shutdown so we are sure we correctly release all native memory and also guard against the
-                // case when shutdown() will be called by the finalizer again.
-                shutdown();
-
-                PlatformDependent.throwException(cause);
-            }
-        }
-
-        // Now that everything looks good and we're going to successfully return the
-        // object so we need to retain a reference to the parent context.
-        parentContext = context;
-        parentContext.retain();
-
-        // Only create the leak after everything else was executed and so ensure we don't produce a false-positive for
-        // the ResourceLeakDetector.
-        leak = leakDetection ? leakDetector.track(this) : null;
-    }
-
-    final synchronized String[] authMethods() {
-        if (isDestroyed()) {
-            return EmptyArrays.EMPTY_STRINGS;
-        }
-        return SSL.authenticationMethods(ssl);
-    }
-
-    final boolean setKeyMaterial(OpenSslKeyMaterial keyMaterial) throws  Exception {
-        synchronized (this) {
-            if (isDestroyed()) {
-                return false;
-            }
-            SSL.setKeyMaterial(ssl, keyMaterial.certificateChainAddress(), keyMaterial.privateKeyAddress());
-        }
-        session.setLocalCertificate(keyMaterial.certificateChain());
-        return true;
-    }
-
-    final synchronized SecretKeySpec masterKey() {
-        if (isDestroyed()) {
-            return null;
-        }
-        return new SecretKeySpec(SSL.getMasterKey(ssl), "AES");
-    }
-
-    synchronized boolean isSessionReused() {
-        if (isDestroyed()) {
-            return false;
-        }
-        return SSL.isSessionReused(ssl);
-    }
-
-    /**
-     * Sets the OCSP response.
-     */
-    @UnstableApi
-    public void setOcspResponse(byte[] response) {
-        if (!enableOcsp) {
-            throw new IllegalStateException("OCSP stapling is not enabled");
-        }
-
-        if (clientMode) {
-            throw new IllegalStateException("Not a server SSLEngine");
-        }
-
-        synchronized (this) {
-            if (!isDestroyed()) {
-                SSL.setOcspResponse(ssl, response);
-            }
-        }
-    }
-
-    /**
-     * Returns the OCSP response or {@code null} if the server didn't provide a stapled OCSP response.
-     */
-    @UnstableApi
-    public byte[] getOcspResponse() {
-        if (!enableOcsp) {
-            throw new IllegalStateException("OCSP stapling is not enabled");
-        }
-
-        if (!clientMode) {
-            throw new IllegalStateException("Not a client SSLEngine");
-        }
-
-        synchronized (this) {
-            if (isDestroyed()) {
-                return EmptyArrays.EMPTY_BYTES;
-            }
-            return SSL.getOcspResponse(ssl);
-        }
-    }
-
-    @Override
-    public final int refCnt() {
-        return refCnt.refCnt();
-    }
-
-    @Override
-    public final ReferenceCounted retain() {
-        refCnt.retain();
-        return this;
-    }
-
-    @Override
-    public final ReferenceCounted retain(int increment) {
-        refCnt.retain(increment);
-        return this;
-    }
-
-    @Override
-    public final ReferenceCounted touch() {
-        refCnt.touch();
-        return this;
-    }
-
-    @Override
-    public final ReferenceCounted touch(Object hint) {
-        refCnt.touch(hint);
-        return this;
-    }
-
-    @Override
-    public final boolean release() {
-        return refCnt.release();
-    }
-
-    @Override
-    public final boolean release(int decrement) {
-        return refCnt.release(decrement);
-    }
-
-    // These method will override the method defined by Java 8u251 and later. As we may compile with an earlier
-    // java8 version we don't use @Override annotations here.
-    public String getApplicationProtocol() {
-        return applicationProtocol;
-    }
-
-    // These method will override the method defined by Java 8u251 and later. As we may compile with an earlier
-    // java8 version we don't use @Override annotations here.
-    public String getHandshakeApplicationProtocol() {
-        return applicationProtocol;
-    }
-
-    @Override
-    public final synchronized SSLSession getHandshakeSession() {
-        // Javadocs state return value should be:
-        // null if this instance is not currently handshaking, or if the current handshake has not
-        // progressed far enough to create a basic SSLSession. Otherwise, this method returns the
-        // SSLSession currently being negotiated.
-        switch(handshakeState) {
-            case NOT_STARTED:
-            case FINISHED:
-                return null;
-            default:
-                return session;
-        }
-    }
-
-    /**
-     * Returns the pointer to the {@code SSL} object for this {@link ReferenceCountedOpenSslEngine}.
-     * Be aware that it is freed as soon as the {@link #release()} or {@link #shutdown()} methods are called.
-     * At this point {@code 0} will be returned.
-     */
-    public final synchronized long sslPointer() {
-        return ssl;
-    }
-
-    /**
-     * Destroys this engine.
-     */
-    public final synchronized void shutdown() {
-        if (!destroyed) {
-            destroyed = true;
-            engineMap.remove(ssl);
-            SSL.freeSSL(ssl);
-            ssl = networkBIO = 0;
-
-            isInboundDone = outboundClosed = true;
-        }
-
-        // On shutdown clear all errors
-        SSL.clearError();
-    }
-
-    /**
-     * Write plaintext data to the OpenSSL internal BIO
-     *
-     * Calling this function with src.remaining == 0 is undefined.
-     */
-    private int writePlaintextData(final ByteBuffer src, int len) {
-        final int pos = src.position();
-        final int limit = src.limit();
-        final int sslWrote;
-
-        if (src.isDirect()) {
-            sslWrote = SSL.writeToSSL(ssl, bufferAddress(src) + pos, len);
-            if (sslWrote > 0) {
-                src.position(pos + sslWrote);
-            }
-        } else {
-            ByteBuf buf = alloc.directBuffer(len);
-            try {
-                src.limit(pos + len);
-
-                buf.setBytes(0, src);
-                src.limit(limit);
-
-                sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len);
-                if (sslWrote > 0) {
-                    src.position(pos + sslWrote);
-                } else {
-                    src.position(pos);
-                }
-            } finally {
-                buf.release();
-            }
-        }
-        return sslWrote;
-    }
-
-    /**
-     * Write encrypted data to the OpenSSL network BIO.
-     */
-    private ByteBuf writeEncryptedData(final ByteBuffer src, int len) throws SSLException {
-        final int pos = src.position();
-        if (src.isDirect()) {
-            SSL.bioSetByteBuffer(networkBIO, bufferAddress(src) + pos, len, false);
-        } else {
-            final ByteBuf buf = alloc.directBuffer(len);
-            try {
-                final int limit = src.limit();
-                src.limit(pos + len);
-                buf.writeBytes(src);
-                // Restore the original position and limit because we don't want to consume from `src`.
-                src.position(pos);
-                src.limit(limit);
-
-                SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false);
-                return buf;
-            } catch (Throwable cause) {
-                buf.release();
-                PlatformDependent.throwException(cause);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Read plaintext data from the OpenSSL internal BIO
-     */
-    private int readPlaintextData(final ByteBuffer dst) throws SSLException {
-        final int sslRead;
-        final int pos = dst.position();
-        if (dst.isDirect()) {
-            sslRead = SSL.readFromSSL(ssl, bufferAddress(dst) + pos, dst.limit() - pos);
-            if (sslRead > 0) {
-                dst.position(pos + sslRead);
-            }
-        } else {
-            final int limit = dst.limit();
-            final int len = min(maxEncryptedPacketLength0(), limit - pos);
-            final ByteBuf buf = alloc.directBuffer(len);
-            try {
-                sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len);
-                if (sslRead > 0) {
-                    dst.limit(pos + sslRead);
-                    buf.getBytes(buf.readerIndex(), dst);
-                    dst.limit(limit);
-                }
-            } finally {
-                buf.release();
-            }
-        }
-
-        return sslRead;
-    }
-
-    /**
-     * Visible only for testing!
-     */
-    final synchronized int maxWrapOverhead() {
-        return maxWrapOverhead;
-    }
-
-    /**
-     * Visible only for testing!
-     */
-    final synchronized int maxEncryptedPacketLength() {
-        return maxEncryptedPacketLength0();
-    }
-
-    /**
-     * This method is intentionally not synchronized, only use if you know you are in the EventLoop
-     * thread and visibility on {@link #maxWrapOverhead} is achieved via other synchronized blocks.
-     */
-    final int maxEncryptedPacketLength0() {
-        return maxWrapOverhead + MAX_PLAINTEXT_LENGTH;
-    }
-
-    /**
-     * This method is intentionally not synchronized, only use if you know you are in the EventLoop
-     * thread and visibility on {@link #maxWrapBufferSize} and {@link #maxWrapOverhead} is achieved
-     * via other synchronized blocks.
-     */
-    final int calculateMaxLengthForWrap(int plaintextLength, int numComponents) {
-        return (int) min(maxWrapBufferSize, plaintextLength + (long) maxWrapOverhead * numComponents);
-    }
-
-    final synchronized int sslPending() {
-        return sslPending0();
-    }
-
-    /**
-     * It is assumed this method is called in a synchronized block (or the constructor)!
-     */
-    private void calculateMaxWrapOverhead() {
-        maxWrapOverhead = SSL.getMaxWrapOverhead(ssl);
-
-        // maxWrapBufferSize must be set after maxWrapOverhead because there is a dependency on this value.
-        // If jdkCompatibility mode is off we allow enough space to encrypt 16 buffers at a time. This could be
-        // configurable in the future if necessary.
-        maxWrapBufferSize = jdkCompatibilityMode ? maxEncryptedPacketLength0() : maxEncryptedPacketLength0() << 4;
-    }
-
-    private int sslPending0() {
-        // OpenSSL has a limitation where if you call SSL_pending before the handshake is complete OpenSSL will throw a
-        // "called a function you should not call" error. Using the TLS_method instead of SSLv23_method may solve this
-        // issue but this API is only available in 1.1.0+ [1].
-        // [1] https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_new.html
-        return handshakeState != HandshakeState.FINISHED ? 0 : SSL.sslPending(ssl);
-    }
-
-    private boolean isBytesAvailableEnoughForWrap(int bytesAvailable, int plaintextLength, int numComponents) {
-        return bytesAvailable - (long) maxWrapOverhead * numComponents >= plaintextLength;
-    }
-
-    @Override
-    public final SSLEngineResult wrap(
-            final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst) throws SSLException {
-        // Throw required runtime exceptions
-        checkNotNullWithIAE(srcs, "srcs");
-        checkNotNullWithIAE(dst, "dst");
-
-        if (offset >= srcs.length || offset + length > srcs.length) {
-            throw new IndexOutOfBoundsException(
-                    "offset: " + offset + ", length: " + length +
-                            " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
-        }
-
-        if (dst.isReadOnly()) {
-            throw new ReadOnlyBufferException();
-        }
-
-        synchronized (this) {
-            if (isOutboundDone()) {
-                // All drained in the outbound buffer
-                return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_UNWRAP_CLOSED;
-            }
-
-            int bytesProduced = 0;
-            ByteBuf bioReadCopyBuf = null;
-            try {
-                // Setup the BIO buffer so that we directly write the encryption results into dst.
-                if (dst.isDirect()) {
-                    SSL.bioSetByteBuffer(networkBIO, bufferAddress(dst) + dst.position(), dst.remaining(),
-                            true);
-                } else {
-                    bioReadCopyBuf = alloc.directBuffer(dst.remaining());
-                    SSL.bioSetByteBuffer(networkBIO, memoryAddress(bioReadCopyBuf), bioReadCopyBuf.writableBytes(),
-                            true);
-                }
-
-                int bioLengthBefore = SSL.bioLengthByteBuffer(networkBIO);
-
-                // Explicitly use outboundClosed as we want to drain any bytes that are still present.
-                if (outboundClosed) {
-                    // If the outbound was closed we want to ensure we can produce the alert to the destination buffer.
-                    // This is true even if we not using jdkCompatibilityMode.
-                    //
-                    // We use a plaintextLength of 2 as we at least want to have an alert fit into it.
-                    // https://tools.ietf.org/html/rfc5246#section-7.2
-                    if (!isBytesAvailableEnoughForWrap(dst.remaining(), 2, 1)) {
-                        return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
-                    }
-
-                    // There is something left to drain.
-                    // See https://github.com/netty/netty/issues/6260
-                    bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-                    if (bytesProduced <= 0) {
-                        return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0);
-                    }
-                    // It is possible when the outbound was closed there was not enough room in the non-application
-                    // buffers to hold the close_notify. We should keep trying to close until we consume all the data
-                    // OpenSSL can give us.
-                    if (!doSSLShutdown()) {
-                        return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, bytesProduced);
-                    }
-                    bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
-                    return newResultMayFinishHandshake(NEED_WRAP, 0, bytesProduced);
-                }
-
-                // Flush any data that may be implicitly generated by OpenSSL (handshake, close, etc..).
-                SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
-                // Prepare OpenSSL to work in server mode and receive handshake
-                if (handshakeState != HandshakeState.FINISHED) {
-                    if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
-                        // Update accepted so we know we triggered the handshake via wrap
-                        handshakeState = HandshakeState.STARTED_IMPLICITLY;
-                    }
-
-                    // Flush any data that may have been written implicitly during the handshake by OpenSSL.
-                    bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-
-                    if (pendingException != null) {
-                        // TODO(scott): It is possible that when the handshake failed there was not enough room in the
-                        // non-application buffers to hold the alert. We should get all the data before progressing on.
-                        // However I'm not aware of a way to do this with the OpenSSL APIs.
-                        // See https://github.com/netty/netty/issues/6385.
-
-                        // We produced / consumed some data during the handshake, signal back to the caller.
-                        // If there is a handshake exception and we have produced data, we should send the data before
-                        // we allow handshake() to throw the handshake exception.
-                        //
-                        // When the user calls wrap() again we will propagate the handshake error back to the user as
-                        // soon as there is no more data to was produced (as part of an alert etc).
-                        if (bytesProduced > 0) {
-                            return newResult(NEED_WRAP, 0, bytesProduced);
-                        }
-                        // Nothing was produced see if there is a handshakeException that needs to be propagated
-                        // to the caller by calling handshakeException() which will return the right HandshakeStatus
-                        // if it can "recover" from the exception for now.
-                        return newResult(handshakeException(), 0, 0);
-                    }
-
-                    status = handshake();
-
-                    // Handshake may have generated more data, for example if the internal SSL buffer is small
-                    // we may have freed up space by flushing above.
-                    bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
-
-                    if (status == NEED_TASK) {
-                        return newResult(status, 0, bytesProduced);
-                    }
-
-                    if (bytesProduced > 0) {
-                        // If we have filled up the dst buffer and we have not finished the handshake we should try to
-                        // wrap again. Otherwise we should only try to wrap again if there is still data pending in
-                        // SSL buffers.
-                        return newResult(mayFinishHandshake(status != FINISHED ?
-                                         bytesProduced == bioLengthBefore ? NEED_WRAP :
-                                         getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) : FINISHED),
-                                         0, bytesProduced);
-                    }
-
-                    if (status == NEED_UNWRAP) {
-                        // Signal if the outbound is done or not.
-                        return isOutboundDone() ? NEED_UNWRAP_CLOSED : NEED_UNWRAP_OK;
-                    }
-
-                    // Explicit use outboundClosed and not outboundClosed() as we want to drain any bytes that are
-                    // still present.
-                    if (outboundClosed) {
-                        bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-                        return newResultMayFinishHandshake(status, 0, bytesProduced);
-                    }
-                }
-
-                final int endOffset = offset + length;
-                if (jdkCompatibilityMode) {
-                    int srcsLen = 0;
-                    for (int i = offset; i < endOffset; ++i) {
-                        final ByteBuffer src = srcs[i];
-                        if (src == null) {
-                            throw new IllegalArgumentException("srcs[" + i + "] is null");
-                        }
-                        if (srcsLen == MAX_PLAINTEXT_LENGTH) {
-                            continue;
-                        }
-
-                        srcsLen += src.remaining();
-                        if (srcsLen > MAX_PLAINTEXT_LENGTH || srcsLen < 0) {
-                            // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to MAX_PLAINTEXT_LENGTH.
-                            // This also help us to guard against overflow.
-                            // We not break out here as we still need to check for null entries in srcs[].
-                            srcsLen = MAX_PLAINTEXT_LENGTH;
-                        }
-                    }
-
-                    // jdkCompatibilityMode will only produce a single TLS packet, and we don't aggregate src buffers,
-                    // so we always fix the number of buffers to 1 when checking if the dst buffer is large enough.
-                    if (!isBytesAvailableEnoughForWrap(dst.remaining(), srcsLen, 1)) {
-                        return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
-                    }
-                }
-
-                // There was no pending data in the network BIO -- encrypt any application data
-                int bytesConsumed = 0;
-                assert bytesProduced == 0;
-
-                // Flush any data that may have been written implicitly by OpenSSL in case a shutdown/alert occurs.
-                bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-
-                if (bytesProduced > 0) {
-                    return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
-                }
-                // There was a pending exception that we just delayed because there was something to produce left.
-                // Throw it now and shutdown the engine.
-                if (pendingException != null) {
-                    Throwable error = pendingException;
-                    pendingException = null;
-                    shutdown();
-                    // Throw a new exception wrapping the pending exception, so the stacktrace is meaningful and
-                    // contains all the details.
-                    throw new SSLException(error);
-                }
-
-                for (; offset < endOffset; ++offset) {
-                    final ByteBuffer src = srcs[offset];
-                    final int remaining = src.remaining();
-                    if (remaining == 0) {
-                        continue;
-                    }
-
-                    final int bytesWritten;
-                    if (jdkCompatibilityMode) {
-                        // Write plaintext application data to the SSL engine. We don't have to worry about checking
-                        // if there is enough space if jdkCompatibilityMode because we only wrap at most
-                        // MAX_PLAINTEXT_LENGTH and we loop over the input before hand and check if there is space.
-                        bytesWritten = writePlaintextData(src, min(remaining, MAX_PLAINTEXT_LENGTH - bytesConsumed));
-                    } else {
-                        // OpenSSL's SSL_write keeps state between calls. We should make sure the amount we attempt to
-                        // write is guaranteed to succeed so we don't have to worry about keeping state consistent
-                        // between calls.
-                        final int availableCapacityForWrap = dst.remaining() - bytesProduced - maxWrapOverhead;
-                        if (availableCapacityForWrap <= 0) {
-                            return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), bytesConsumed,
-                                    bytesProduced);
-                        }
-                        bytesWritten = writePlaintextData(src, min(remaining, availableCapacityForWrap));
-                    }
-
-                    // Determine how much encrypted data was generated.
-                    //
-                    // Even if SSL_write doesn't consume any application data it is possible that OpenSSL will
-                    // produce non-application data into the BIO. For example session tickets....
-                    // See https://github.com/netty/netty/issues/10041
-                    final int pendingNow = SSL.bioLengthByteBuffer(networkBIO);
-                    bytesProduced += bioLengthBefore - pendingNow;
-                    bioLengthBefore = pendingNow;
-
-                    if (bytesWritten > 0) {
-                        bytesConsumed += bytesWritten;
-
-                        if (jdkCompatibilityMode || bytesProduced == dst.remaining()) {
-                            return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
-                        }
-                    } else {
-                        int sslError = SSL.getError(ssl, bytesWritten);
-                        if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
-                            // This means the connection was shutdown correctly, close inbound and outbound
-                            if (!receivedShutdown) {
-                                closeAll();
-
-                                bytesProduced += bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
-
-                                // If we have filled up the dst buffer and we have not finished the handshake we should
-                                // try to wrap again. Otherwise we should only try to wrap again if there is still data
-                                // pending in SSL buffers.
-                                SSLEngineResult.HandshakeStatus hs = mayFinishHandshake(
-                                        status != FINISHED ? bytesProduced == dst.remaining() ? NEED_WRAP
-                                                : getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO))
-                                                : FINISHED);
-                                return newResult(hs, bytesConsumed, bytesProduced);
-                            }
-
-                            return newResult(NOT_HANDSHAKING, bytesConsumed, bytesProduced);
-                        } else if (sslError == SSL.SSL_ERROR_WANT_READ) {
-                            // If there is no pending data to read from BIO we should go back to event loop and try
-                            // to read more data [1]. It is also possible that event loop will detect the socket has
-                            // been closed. [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
-                            return newResult(NEED_UNWRAP, bytesConsumed, bytesProduced);
-                        } else if (sslError == SSL.SSL_ERROR_WANT_WRITE) {
-                            // SSL_ERROR_WANT_WRITE typically means that the underlying transport is not writable
-                            // and we should set the "want write" flag on the selector and try again when the
-                            // underlying transport is writable [1]. However we are not directly writing to the
-                            // underlying transport and instead writing to a BIO buffer. The OpenSsl documentation
-                            // says we should do the following [1]:
-                            //
-                            // "When using a buffering BIO, like a BIO pair, data must be written into or retrieved
-                            // out of the BIO before being able to continue."
-                            //
-                            // In practice this means the destination buffer doesn't have enough space for OpenSSL
-                            // to write encrypted data to. This is an OVERFLOW condition.
-                            // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
-                            if (bytesProduced > 0) {
-                                // If we produced something we should report this back and let the user call
-                                // wrap again.
-                                return newResult(NEED_WRAP, bytesConsumed, bytesProduced);
-                            }
-                            return newResult(BUFFER_OVERFLOW, status, bytesConsumed, bytesProduced);
-                        } else if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
-                                sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
-                                sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
-
-                            return newResult(NEED_TASK, bytesConsumed, bytesProduced);
-                        } else {
-                            // Everything else is considered as error
-                            throw shutdownWithError("SSL_write", sslError);
-                        }
-                    }
-                }
-                return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
-            } finally {
-                SSL.bioClearByteBuffer(networkBIO);
-                if (bioReadCopyBuf == null) {
-                    dst.position(dst.position() + bytesProduced);
-                } else {
-                    assert bioReadCopyBuf.readableBytes() <= dst.remaining() : "The destination buffer " + dst +
-                            " didn't have enough remaining space to hold the encrypted content in " + bioReadCopyBuf;
-                    dst.put(bioReadCopyBuf.internalNioBuffer(bioReadCopyBuf.readerIndex(), bytesProduced));
-                    bioReadCopyBuf.release();
-                }
-            }
-        }
-    }
-
-    private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int bytesConsumed, int bytesProduced) {
-        return newResult(OK, hs, bytesConsumed, bytesProduced);
-    }
-
-    private SSLEngineResult newResult(SSLEngineResult.Status status, SSLEngineResult.HandshakeStatus hs,
-                                      int bytesConsumed, int bytesProduced) {
-        // If isOutboundDone, then the data from the network BIO
-        // was the close_notify message and all was consumed we are not required to wait
-        // for the receipt the peer's close_notify message -- shutdown.
-        if (isOutboundDone()) {
-            if (isInboundDone()) {
-                // If the inbound was done as well, we need to ensure we return NOT_HANDSHAKING to signal we are done.
-                hs = NOT_HANDSHAKING;
-
-                // As the inbound and the outbound is done we can shutdown the engine now.
-                shutdown();
-            }
-            return new SSLEngineResult(CLOSED, hs, bytesConsumed, bytesProduced);
-        }
-        if (hs == NEED_TASK) {
-            // Set needTask to true so getHandshakeStatus() will return the correct value.
-            needTask = true;
-        }
-        return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced);
-    }
-
-    private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus hs,
-                                                        int bytesConsumed, int bytesProduced) throws SSLException {
-        return newResult(mayFinishHandshake(hs, bytesConsumed, bytesProduced), bytesConsumed, bytesProduced);
-    }
-
-    private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status,
-                                                        SSLEngineResult.HandshakeStatus hs,
-                                                        int bytesConsumed, int bytesProduced) throws SSLException {
-        return newResult(status, mayFinishHandshake(hs, bytesConsumed, bytesProduced), bytesConsumed, bytesProduced);
-    }
-
-    /**
-     * Log the error, shutdown the engine and throw an exception.
-     */
-    private SSLException shutdownWithError(String operations, int sslError) {
-        return shutdownWithError(operations, sslError, SSL.getLastErrorNumber());
-    }
-
-    private SSLException shutdownWithError(String operation, int sslError, int error) {
-        String errorString = SSL.getErrorString(error);
-        if (logger.isDebugEnabled()) {
-            logger.debug("{} failed with {}: OpenSSL error: {} {}",
-                         operation, sslError, error, errorString);
-        }
-
-        // There was an internal error -- shutdown
-        shutdown();
-        if (handshakeState == HandshakeState.FINISHED) {
-            return new SSLException(errorString);
-        }
-
-        SSLHandshakeException exception = new SSLHandshakeException(errorString);
-        // If we have a handshakeException stored already we should include it as well to help the user debug things.
-        if (pendingException != null) {
-            exception.initCause(pendingException);
-            pendingException = null;
-        }
-        return exception;
-    }
-
-    private SSLEngineResult handleUnwrapException(int bytesConsumed, int bytesProduced, SSLException e)
-            throws SSLException {
-        int lastError = SSL.getLastErrorNumber();
-        if (lastError != 0) {
-            return sslReadErrorResult(SSL.SSL_ERROR_SSL, lastError, bytesConsumed,
-                    bytesProduced);
-        }
-        throw e;
-    }
-
-    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
-        checkNotNullWithIAE(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 + "))");
-        }
-        checkNotNullWithIAE(dsts, "dsts");
-        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 = checkNotNullArrayParam(dsts[i], i, "dsts");
-            if (dst.isReadOnly()) {
-                throw new ReadOnlyBufferException();
-            }
-            capacity += dst.remaining();
-        }
-
-        final int srcsEndOffset = srcsOffset + srcsLength;
-        long len = 0;
-        for (int i = srcsOffset; i < srcsEndOffset; i++) {
-            ByteBuffer src = checkNotNullArrayParam(srcs[i], i, "srcs");
-            len += src.remaining();
-        }
-
-        synchronized (this) {
-            if (isInboundDone()) {
-                return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_WRAP_CLOSED;
-            }
-
-            SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
-            // Prepare OpenSSL to work in server mode and receive handshake
-            if (handshakeState != HandshakeState.FINISHED) {
-                if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
-                    // Update accepted so we know we triggered the handshake via wrap
-                    handshakeState = HandshakeState.STARTED_IMPLICITLY;
-                }
-
-                status = handshake();
-
-                if (status == NEED_TASK) {
-                    return newResult(status, 0, 0);
-                }
-
-                if (status == NEED_WRAP) {
-                    return NEED_WRAP_OK;
-                }
-                // Check if the inbound is considered to be closed if so let us try to wrap again.
-                if (isInboundDone) {
-                    return NEED_WRAP_CLOSED;
-                }
-            }
-
-            int sslPending = sslPending0();
-            int packetLength;
-            // The JDK implies that only a single SSL packet should be processed per unwrap call [1]. If we are in
-            // JDK compatibility mode then we should honor this, but if not we just wrap as much as possible. If there
-            // are multiple records or partial records this may reduce thrashing events through the pipeline.
-            // [1] https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html
-            if (jdkCompatibilityMode) {
-                if (len < SSL_RECORD_HEADER_LENGTH) {
-                    return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
-                }
-
-                packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset);
-                if (packetLength == SslUtils.NOT_ENCRYPTED) {
-                    throw new NotSslRecordException("not an SSL/TLS record");
-                }
-
-                final int packetLengthDataOnly = packetLength - SSL_RECORD_HEADER_LENGTH;
-                if (packetLengthDataOnly > capacity) {
-                    // Not enough space in the destination buffer so signal the caller that the buffer needs to be
-                    // increased.
-                    if (packetLengthDataOnly > MAX_RECORD_SIZE) {
-                        // The packet length MUST NOT exceed 2^14 [1]. However we do accommodate more data to support
-                        // legacy use cases which may violate this condition (e.g. OpenJDK's SslEngineImpl). If the max
-                        // length is exceeded we fail fast here to avoid an infinite loop due to the fact that we
-                        // won't allocate a buffer large enough.
-                        // [1] https://tools.ietf.org/html/rfc5246#section-6.2.1
-                        throw new SSLException("Illegal packet length: " + packetLengthDataOnly + " > " +
-                                                session.getApplicationBufferSize());
-                    } else {
-                        session.tryExpandApplicationBufferSize(packetLengthDataOnly);
-                    }
-                    return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
-                }
-
-                if (len < packetLength) {
-                    // We either don't have enough data to read the packet length or not enough for reading the whole
-                    // packet.
-                    return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
-                }
-            } else if (len == 0 && sslPending <= 0) {
-                return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
-            } else if (capacity == 0) {
-                return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
-            } else {
-                packetLength = (int) min(MAX_VALUE, len);
-            }
-
-            // This must always be the case when we reached here as if not we returned BUFFER_UNDERFLOW.
-            assert srcsOffset < srcsEndOffset;
-
-            // This must always be the case if we reached here.
-            assert capacity > 0;
-
-            // Number of produced bytes
-            int bytesProduced = 0;
-            int bytesConsumed = 0;
-            try {
-                srcLoop:
-                for (;;) {
-                    ByteBuffer src = srcs[srcsOffset];
-                    int remaining = src.remaining();
-                    final ByteBuf bioWriteCopyBuf;
-                    int pendingEncryptedBytes;
-                    if (remaining == 0) {
-                        if (sslPending <= 0) {
-                            // We must skip empty buffers as BIO_write will return 0 if asked to write something
-                            // with length 0.
-                            if (++srcsOffset >= srcsEndOffset) {
-                                break;
-                            }
-                            continue;
-                        } else {
-                            bioWriteCopyBuf = null;
-                            pendingEncryptedBytes = SSL.bioLengthByteBuffer(networkBIO);
-                        }
-                    } else {
-                        // Write more encrypted data into the BIO. Ensure we only read one packet at a time as
-                        // stated in the SSLEngine javadocs.
-                        pendingEncryptedBytes = min(packetLength, remaining);
-                        try {
-                            bioWriteCopyBuf = writeEncryptedData(src, pendingEncryptedBytes);
-                        } catch (SSLException e) {
-                            // Ensure we correctly handle the error stack.
-                            return handleUnwrapException(bytesConsumed, bytesProduced, e);
-                        }
-                    }
-                    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;
-                            try {
-                                bytesRead = readPlaintextData(dst);
-                            } catch (SSLException e) {
-                                // Ensure we correctly handle the error stack.
-                                return handleUnwrapException(bytesConsumed, bytesProduced, e);
-                            }
-                            // We are directly using the ByteBuffer memory for the write, and so we only know what has
-                            // been consumed after we let SSL decrypt the data. At this point we should update the
-                            // number of bytes consumed, update the ByteBuffer position, and release temp ByteBuf.
-                            int localBytesConsumed = pendingEncryptedBytes - SSL.bioLengthByteBuffer(networkBIO);
-                            bytesConsumed += localBytesConsumed;
-                            packetLength -= localBytesConsumed;
-                            pendingEncryptedBytes -= localBytesConsumed;
-                            src.position(src.position() + localBytesConsumed);
-
-                            if (bytesRead > 0) {
-                                bytesProduced += bytesRead;
-
-                                if (!dst.hasRemaining()) {
-                                    sslPending = sslPending0();
-                                    // Move to the next dst buffer as this one is full.
-                                    if (++dstsOffset >= dstsEndOffset) {
-                                        return sslPending > 0 ?
-                                                newResult(BUFFER_OVERFLOW, status, bytesConsumed, bytesProduced) :
-                                                newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
-                                                        bytesConsumed, bytesProduced);
-                                    }
-                                } else if (packetLength == 0 || jdkCompatibilityMode) {
-                                    // We either consumed all data or we are in jdkCompatibilityMode and have consumed
-                                    // a single TLS packet and should stop consuming until this method is called again.
-                                    break srcLoop;
-                                }
-                            } else {
-                                int sslError = SSL.getError(ssl, bytesRead);
-                                if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
-                                    // break to the outer loop as we want to read more data which means we need to
-                                    // write more to the BIO.
-                                    break;
-                                } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
-                                    // This means the connection was shutdown correctly, close inbound and outbound
-                                    if (!receivedShutdown) {
-                                        closeAll();
-                                    }
-                                    return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
-                                            bytesConsumed, bytesProduced);
-                                } else if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
-                                        sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
-                                        sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
-                                    return newResult(isInboundDone() ? CLOSED : OK,
-                                            NEED_TASK, bytesConsumed, bytesProduced);
-                                } else {
-                                    return sslReadErrorResult(sslError, SSL.getLastErrorNumber(), bytesConsumed,
-                                            bytesProduced);
-                                }
-                            }
-                        }
-
-                        if (++srcsOffset >= srcsEndOffset) {
-                            break;
-                        }
-                    } finally {
-                        if (bioWriteCopyBuf != null) {
-                            bioWriteCopyBuf.release();
-                        }
-                    }
-                }
-            } finally {
-                SSL.bioClearByteBuffer(networkBIO);
-                rejectRemoteInitiatedRenegotiation();
-            }
-
-            // Check to see if we received a close_notify message from the peer.
-            if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
-                closeAll();
-            }
-
-            return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced);
-        }
-    }
-
-    private boolean needWrapAgain(int stackError) {
-        // 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 true;
-        }
-        return false;
-    }
-
-    private SSLEngineResult sslReadErrorResult(int error, int stackError, int bytesConsumed, int bytesProduced)
-            throws SSLException {
-        if (needWrapAgain(stackError)) {
-            // There is something that needs to be send to the remote peer before we can teardown.
-            // This is most likely some alert.
-            return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced);
-        }
-        throw shutdownWithError("SSL_read", error, stackError);
-    }
-
-    private void closeAll() throws SSLException {
-        receivedShutdown = true;
-        closeOutbound();
-        closeInbound();
-    }
-
-    private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException {
-        // As rejectRemoteInitiatedRenegotiation() is called in a finally block we also need to check if we shutdown
-        // the engine before as otherwise SSL.getHandshakeCount(ssl) will throw an NPE if the passed in ssl is 0.
-        // See https://github.com/netty/netty/issues/7353
-        if (!isDestroyed() && (!clientMode && SSL.getHandshakeCount(ssl) > 1 ||
-                // Let's allow to renegotiate once for client auth.
-                clientMode && SSL.getHandshakeCount(ssl) > 2) &&
-            // 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.
-            !SslProtocols.TLS_v1_3.equals(session.getProtocol()) && handshakeState == HandshakeState.FINISHED) {
-            // TODO: In future versions me may also want to send a fatal_alert to the client and so notify it
-            // that the renegotiation failed.
-            shutdown();
-            throw new SSLHandshakeException("remote-initiated renegotiation not allowed");
-        }
-    }
-
-    public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException {
-        return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
-    }
-
-    private ByteBuffer[] singleSrcBuffer(ByteBuffer src) {
-        singleSrcBuffer[0] = src;
-        return singleSrcBuffer;
-    }
-
-    private void resetSingleSrcBuffer() {
-        singleSrcBuffer[0] = null;
-    }
-
-    private ByteBuffer[] singleDstBuffer(ByteBuffer src) {
-        singleDstBuffer[0] = src;
-        return singleDstBuffer;
-    }
-
-    private void resetSingleDstBuffer() {
-        singleDstBuffer[0] = null;
-    }
-
-    @Override
-    public final synchronized SSLEngineResult unwrap(
-            final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException {
-        try {
-            return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length);
-        } finally {
-            resetSingleSrcBuffer();
-        }
-    }
-
-    @Override
-    public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
-        try {
-            return wrap(singleSrcBuffer(src), dst);
-        } finally {
-            resetSingleSrcBuffer();
-        }
-    }
-
-    @Override
-    public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
-        try {
-            return unwrap(singleSrcBuffer(src), singleDstBuffer(dst));
-        } finally {
-            resetSingleSrcBuffer();
-            resetSingleDstBuffer();
-        }
-    }
-
-    @Override
-    public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
-        try {
-            return unwrap(singleSrcBuffer(src), dsts);
-        } finally {
-            resetSingleSrcBuffer();
-        }
-    }
-
-    private class TaskDecorator<R extends Runnable> implements Runnable {
-        protected final R task;
-        TaskDecorator(R task) {
-            this.task = task;
-        }
-
-        @Override
-        public void run() {
-            runAndResetNeedTask(task);
-        }
-    }
-
-    private final class AsyncTaskDecorator extends TaskDecorator<AsyncTask> implements AsyncRunnable {
-        AsyncTaskDecorator(AsyncTask task) {
-            super(task);
-        }
-
-        @Override
-        public void run(final Runnable runnable) {
-            if (isDestroyed()) {
-                // The engine was destroyed in the meantime, just return.
-                return;
-            }
-            task.runAsync(new TaskDecorator<Runnable>(runnable));
-        }
-    }
-
-    private synchronized void runAndResetNeedTask(Runnable task) {
-        try {
-            if (isDestroyed()) {
-                // The engine was destroyed in the meantime, just return.
-                return;
-            }
-            task.run();
-        } finally {
-            // The task was run, reset needTask to false so getHandshakeStatus() returns the correct value.
-            needTask = false;
-        }
-    }
-
-    @Override
-    public final synchronized Runnable getDelegatedTask() {
-        if (isDestroyed()) {
-            return null;
-        }
-        final Runnable task = SSL.getTask(ssl);
-        if (task == null) {
-            return null;
-        }
-        if (task instanceof AsyncTask) {
-            return new AsyncTaskDecorator((AsyncTask) task);
-        }
-        return new TaskDecorator<Runnable>(task);
-    }
-
-    @Override
-    public final synchronized void closeInbound() throws SSLException {
-        if (isInboundDone) {
-            return;
-        }
-
-        isInboundDone = true;
-
-        if (isOutboundDone()) {
-            // Only call shutdown if there is no outbound data pending.
-            // See https://github.com/netty/netty/issues/6167
-            shutdown();
-        }
-
-        if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown) {
-            throw new SSLException(
-                    "Inbound closed before receiving peer's close_notify: possible truncation attack?");
-        }
-    }
-
-    @Override
-    public final synchronized boolean isInboundDone() {
-        return isInboundDone;
-    }
-
-    @Override
-    public final synchronized void closeOutbound() {
-        if (outboundClosed) {
-            return;
-        }
-
-        outboundClosed = true;
-
-        if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) {
-            int mode = SSL.getShutdown(ssl);
-            if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) {
-                doSSLShutdown();
-            }
-        } else {
-            // engine closing before initial handshake
-            shutdown();
-        }
-    }
-
-    /**
-     * Attempt to call {@link SSL#shutdownSSL(long)}.
-     * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not attempted or returned an error.
-     */
-    private boolean doSSLShutdown() {
-        if (SSL.isInInit(ssl) != 0) {
-            // Only try to call SSL_shutdown if we are not in the init state anymore.
-            // Otherwise we will see 'error:140E0197:SSL routines:SSL_shutdown:shutdown while in init' in our logs.
-            //
-            // See also https://hg.nginx.org/nginx/rev/062c189fee20
-            return false;
-        }
-        int err = SSL.shutdownSSL(ssl);
-        if (err < 0) {
-            int sslErr = SSL.getError(ssl, err);
-            if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) {
-                if (logger.isDebugEnabled()) {
-                    int error = SSL.getLastErrorNumber();
-                    logger.debug("SSL_shutdown failed: OpenSSL error: {} {}", error, SSL.getErrorString(error));
-                }
-                // There was an internal error -- shutdown
-                shutdown();
-                return false;
-            }
-            SSL.clearError();
-        }
-        return true;
-    }
-
-    @Override
-    public final synchronized boolean isOutboundDone() {
-        // Check if there is anything left in the outbound buffer.
-        // We need to ensure we only call SSL.pendingWrittenBytesInBIO(...) if the engine was not destroyed yet.
-        return outboundClosed && (networkBIO == 0 || SSL.bioLengthNonApplication(networkBIO) == 0);
-    }
-
-    @Override
-    public final String[] getSupportedCipherSuites() {
-        return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[0]);
-    }
-
-    @Override
-    public final String[] getEnabledCipherSuites() {
-        final String[] extraCiphers;
-        final String[] enabled;
-        final boolean tls13Enabled;
-        synchronized (this) {
-            if (!isDestroyed()) {
-                enabled = SSL.getCiphers(ssl);
-                int opts = SSL.getOptions(ssl);
-                if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, SslProtocols.TLS_v1_3)) {
-                    extraCiphers = OpenSsl.EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
-                    tls13Enabled = true;
-                } else {
-                    extraCiphers = EmptyArrays.EMPTY_STRINGS;
-                    tls13Enabled = false;
-                }
-            } else {
-                return EmptyArrays.EMPTY_STRINGS;
-            }
-        }
-        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 ((!tls13Enabled || !OpenSsl.isTlsv13Supported()) && SslUtils.isTLSv13Cipher(cipher)) {
-                        continue;
-                    }
-                    enabledSet.add(cipher);
-                }
-                Collections.addAll(enabledSet, extraCiphers);
-            }
-            return enabledSet.toArray(new String[0]);
-        }
-    }
-
-    @Override
-    public final void setEnabledCipherSuites(String[] cipherSuites) {
-        checkNotNull(cipherSuites, "cipherSuites");
-
-        final StringBuilder buf = new StringBuilder();
-        final StringBuilder bufTLSv13 = new StringBuilder();
-
-        CipherSuiteConverter.convertToCipherStrings(Arrays.asList(cipherSuites), buf, bufTLSv13, OpenSsl.isBoringSSL());
-        final String cipherSuiteSpec = buf.toString();
-        final String cipherSuiteSpecTLSv13 = bufTLSv13.toString();
-
-        if (!OpenSsl.isTlsv13Supported() && !cipherSuiteSpecTLSv13.isEmpty()) {
-            throw new IllegalArgumentException("TLSv1.3 is not supported by this java version.");
-        }
-        synchronized (this) {
-            if (!isDestroyed()) {
-                try {
-                    // Set non TLSv1.3 ciphers.
-                    SSL.setCipherSuites(ssl, cipherSuiteSpec, false);
-                    if (OpenSsl.isTlsv13Supported()) {
-                        // Set TLSv1.3 ciphers.
-                        SSL.setCipherSuites(ssl, OpenSsl.checkTls13Ciphers(logger, cipherSuiteSpecTLSv13), true);
-                    }
-
-                    // We also need to update the enabled protocols to ensure we disable the protocol if there are
-                    // no compatible ciphers left.
-                    Set<String> protocols = new HashSet<String>(explicitlyEnabledProtocols.length);
-                    Collections.addAll(protocols, explicitlyEnabledProtocols);
-
-                    // We have no ciphers that are compatible with none-TLSv1.3, let us explicit disable all other
-                    // protocols.
-                    if (cipherSuiteSpec.isEmpty()) {
-                        protocols.remove(SslProtocols.TLS_v1);
-                        protocols.remove(SslProtocols.TLS_v1_1);
-                        protocols.remove(SslProtocols.TLS_v1_2);
-                        protocols.remove(SslProtocols.SSL_v3);
-                        protocols.remove(SslProtocols.SSL_v2);
-                        protocols.remove(SslProtocols.SSL_v2_HELLO);
-                    }
-                    // We have no ciphers that are compatible with TLSv1.3, let us explicit disable it.
-                    if (cipherSuiteSpecTLSv13.isEmpty()) {
-                        protocols.remove(SslProtocols.TLS_v1_3);
-                    }
-                    // Update the protocols but not cache the value. We only cache when we call it from the user
-                    // code or when we construct the engine.
-                    setEnabledProtocols0(protocols.toArray(EmptyArrays.EMPTY_STRINGS), false);
-                } catch (Exception e) {
-                    throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e);
-                }
-            } else {
-                throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec);
-            }
-        }
-    }
-
-    @Override
-    public final String[] getSupportedProtocols() {
-        return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[0]);
-    }
-
-    @Override
-    public final String[] getEnabledProtocols() {
-        List<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(SslProtocols.SSL_v2_HELLO);
-
-        int opts;
-        synchronized (this) {
-            if (!isDestroyed()) {
-                opts = SSL.getOptions(ssl);
-            } else {
-                return enabled.toArray(new String[0]);
-            }
-        }
-        if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, SslProtocols.TLS_v1)) {
-            enabled.add(SslProtocols.TLS_v1);
-        }
-        if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, SslProtocols.TLS_v1_1)) {
-            enabled.add(SslProtocols.TLS_v1_1);
-        }
-        if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, SslProtocols.TLS_v1_2)) {
-            enabled.add(SslProtocols.TLS_v1_2);
-        }
-        if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, SslProtocols.TLS_v1_3)) {
-            enabled.add(SslProtocols.TLS_v1_3);
-        }
-        if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, SslProtocols.SSL_v2)) {
-            enabled.add(SslProtocols.SSL_v2);
-        }
-        if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, SslProtocols.SSL_v3)) {
-            enabled.add(SslProtocols.SSL_v3);
-        }
-        return enabled.toArray(new String[0]);
-    }
-
-    private static boolean isProtocolEnabled(int opts, int disableMask, String protocolString) {
-        // We also need to check if the actual protocolString is supported as depending on the openssl API
-        // implementations it may use a disableMask of 0 (BoringSSL is doing this for example).
-        return (opts & disableMask) == 0 && OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString);
-    }
-
-    /**
-     * {@inheritDoc}
-     * TLS doesn't support a way to advertise non-contiguous versions from the client's perspective, and the client
-     * just advertises the max supported version. The TLS protocol also doesn't support all different combinations of
-     * discrete protocols, and instead assumes contiguous ranges. OpenSSL has some unexpected behavior
-     * (e.g. handshake failures) if non-contiguous protocols are used even where there is a compatible set of protocols
-     * and ciphers. For these reasons this method will determine the minimum protocol and the maximum protocol and
-     * enabled a contiguous range from [min protocol, max protocol] in OpenSSL.
-     */
-    @Override
-    public final void setEnabledProtocols(String[] protocols) {
-        setEnabledProtocols0(protocols, true);
-    }
-
-    private void setEnabledProtocols0(String[] protocols, boolean cache) {
-        // This is correct from the API docs
-        checkNotNullWithIAE(protocols, "protocols");
-        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(SslProtocols.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) { // lgtm[java/constant-comparison]
-                    maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
-                }
-            } else if (p.equals(SslProtocols.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(SslProtocols.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(SslProtocols.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(SslProtocols.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(SslProtocols.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 (cache) {
-                this.explicitlyEnabledProtocols = protocols;
-            }
-            if (!isDestroyed()) {
-                // Clear out options which disable protocols
-                SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 |
-                                      SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2 | SSL.SSL_OP_NO_TLSv1_3);
-
-                int opts = 0;
-                for (int i = 0; i < minProtocolIndex; ++i) {
-                    opts |= OPENSSL_OP_NO_PROTOCOLS[i];
-                }
-                assert maxProtocolIndex != MAX_VALUE;
-                for (int i = maxProtocolIndex + 1; i < OPENSSL_OP_NO_PROTOCOLS.length; ++i) {
-                    opts |= OPENSSL_OP_NO_PROTOCOLS[i];
-                }
-
-                // Disable protocols we do not want
-                SSL.setOptions(ssl, opts);
-            } else {
-                throw new IllegalStateException("failed to enable protocols: " + Arrays.asList(protocols));
-            }
-        }
-    }
-
-    @Override
-    public final SSLSession getSession() {
-        return session;
-    }
-
-    @Override
-    public final synchronized void beginHandshake() throws SSLException {
-        switch (handshakeState) {
-            case STARTED_IMPLICITLY:
-                checkEngineClosed();
-
-                // A user did not start handshake by calling this method by him/herself,
-                // but handshake has been started already by wrap() or unwrap() implicitly.
-                // Because it's the user's first time to call this method, it is unfair to
-                // raise an exception.  From the user's standpoint, he or she never asked
-                // for renegotiation.
-
-                handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this method is invoked by the user,
-                calculateMaxWrapOverhead();
-                // we should raise an exception.
-                break;
-            case STARTED_EXPLICITLY:
-                // Nothing to do as the handshake is not done yet.
-                break;
-            case FINISHED:
-                throw new SSLException("renegotiation unsupported");
-            case NOT_STARTED:
-                handshakeState = HandshakeState.STARTED_EXPLICITLY;
-                if (handshake() == NEED_TASK) {
-                    // Set needTask to true so getHandshakeStatus() will return the correct value.
-                    needTask = true;
-                }
-                calculateMaxWrapOverhead();
-                break;
-            default:
-                throw new Error();
-        }
-    }
-
-    private void checkEngineClosed() throws SSLException {
-        if (isDestroyed()) {
-            throw new SSLException("engine closed");
-        }
-    }
-
-    private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingStatus) {
-        // Depending on if there is something left in the BIO we need to WRAP or UNWRAP
-        return pendingStatus > 0 ? NEED_WRAP : NEED_UNWRAP;
-    }
-
-    private static boolean isEmpty(Object[] arr) {
-        return arr == null || arr.length == 0;
-    }
-
-    private static boolean isEmpty(byte[] cert) {
-        return cert == null || cert.length == 0;
-    }
-
-    private SSLEngineResult.HandshakeStatus handshakeException() throws SSLException {
-        if (SSL.bioLengthNonApplication(networkBIO) > 0) {
-            // There is something pending, we need to consume it first via a WRAP so we don't loose anything.
-            return NEED_WRAP;
-        }
-
-        Throwable exception = pendingException;
-        assert exception != null;
-        pendingException = null;
-        shutdown();
-        if (exception instanceof SSLHandshakeException) {
-            throw (SSLHandshakeException) exception;
-        }
-        SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem");
-        e.initCause(exception);
-        throw e;
-    }
-
-    /**
-     * Should be called if the handshake will be failed due a callback that throws an exception.
-     * This cause will then be used to give more details as part of the {@link SSLHandshakeException}.
-     */
-    final void initHandshakeException(Throwable cause) {
-        if (pendingException == null) {
-            pendingException = cause;
-        } else {
-            ThrowableUtil.addSuppressed(pendingException, cause);
-        }
-    }
-
-    private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
-        if (needTask) {
-            return NEED_TASK;
-        }
-        if (handshakeState == HandshakeState.FINISHED) {
-            return FINISHED;
-        }
-
-        checkEngineClosed();
-
-        if (pendingException != null) {
-            // Let's call SSL.doHandshake(...) again in case there is some async operation pending that would fill the
-            // outbound buffer.
-            if (SSL.doHandshake(ssl) <= 0) {
-                // Clear any error that was put on the stack by the handshake
-                SSL.clearError();
-            }
-            return handshakeException();
-        }
-
-        // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the AbstractCertificateVerifier.
-        engineMap.add(this);
-
-        if (!sessionSet) {
-            parentContext.sessionContext().setSessionFromCache(getPeerHost(), getPeerPort(), ssl);
-            sessionSet = true;
-        }
-
-        if (lastAccessed == -1) {
-            lastAccessed = System.currentTimeMillis();
-        }
-
-        int code = SSL.doHandshake(ssl);
-        if (code <= 0) {
-            int sslError = SSL.getError(ssl, code);
-            if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
-                return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
-            }
-
-            if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
-                    sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
-                    sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
-                return NEED_TASK;
-            }
-
-            if (needWrapAgain(SSL.getLastErrorNumber())) {
-                // There is something that needs to be send to the remote peer before we can teardown.
-                // This is most likely some alert.
-                return NEED_WRAP;
-            }
-            // Check if we have a pending exception that was created during the handshake and if so throw it after
-            // shutdown the connection.
-            if (pendingException != null) {
-                return handshakeException();
-            }
-
-            // Everything else is considered as error
-            throw shutdownWithError("SSL_do_handshake", sslError);
-        }
-        // We have produced more data as part of the handshake if this is the case the user should call wrap(...)
-        if (SSL.bioLengthNonApplication(networkBIO) > 0) {
-            return NEED_WRAP;
-        }
-        // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means the handshake was finished.
-        session.handshakeFinished(SSL.getSessionId(ssl), SSL.getCipherForSSL(ssl), SSL.getVersion(ssl),
-                SSL.getPeerCertificate(ssl), SSL.getPeerCertChain(ssl),
-                SSL.getTime(ssl) * 1000L, parentContext.sessionTimeout() * 1000L);
-        selectApplicationProtocol();
-        return FINISHED;
-    }
-
-    private SSLEngineResult.HandshakeStatus mayFinishHandshake(
-            SSLEngineResult.HandshakeStatus hs, int bytesConsumed, int bytesProduced) throws SSLException {
-        return hs == NEED_UNWRAP && bytesProduced > 0 || hs == NEED_WRAP && bytesConsumed > 0 ?
-            handshake() : mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED);
-    }
-
-    private SSLEngineResult.HandshakeStatus mayFinishHandshake(SSLEngineResult.HandshakeStatus status)
-            throws SSLException {
-        if (status == NOT_HANDSHAKING) {
-            if (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();
-            }
-            if (!isDestroyed() && SSL.bioLengthNonApplication(networkBIO) > 0) {
-                // We have something left that needs to be wrapped.
-                return NEED_WRAP;
-            }
-        }
-        return status;
-    }
-
-    @Override
-    public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
-        // Check if we are in the initial handshake phase or shutdown phase
-        if (needPendingStatus()) {
-            if (needTask) {
-                // There is a task outstanding
-                return NEED_TASK;
-            }
-            return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
-        }
-        return NOT_HANDSHAKING;
-    }
-
-    private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
-        // Check if we are in the initial handshake phase or shutdown phase
-        if (needPendingStatus()) {
-            if (needTask) {
-                // There is a task outstanding
-                return NEED_TASK;
-            }
-            return pendingStatus(pending);
-        }
-        return NOT_HANDSHAKING;
-    }
-
-    private boolean needPendingStatus() {
-        return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()
-                && (handshakeState != HandshakeState.FINISHED || isInboundDone() || isOutboundDone());
-    }
-
-    /**
-     * Converts the specified OpenSSL cipher suite to the Java cipher suite.
-     */
-    private String toJavaCipherSuite(String openSslCipherSuite) {
-        if (openSslCipherSuite == null) {
-            return null;
-        }
-
-        String version = SSL.getVersion(ssl);
-        String prefix = toJavaCipherSuitePrefix(version);
-        return CipherSuiteConverter.toJava(openSslCipherSuite, prefix);
-    }
-
-    /**
-     * Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string.
-     */
-    private static String toJavaCipherSuitePrefix(String protocolVersion) {
-        final char c;
-        if (protocolVersion == null || protocolVersion.isEmpty()) {
-            c = 0;
-        } else {
-            c = protocolVersion.charAt(0);
-        }
-
-        switch (c) {
-            case 'T':
-                return "TLS";
-            case 'S':
-                return "SSL";
-            default:
-                return "UNKNOWN";
-        }
-    }
-
-    @Override
-    public final void setUseClientMode(boolean clientMode) {
-        if (clientMode != this.clientMode) {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    @Override
-    public final boolean getUseClientMode() {
-        return clientMode;
-    }
-
-    @Override
-    public final void setNeedClientAuth(boolean b) {
-        setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE);
-    }
-
-    @Override
-    public final boolean getNeedClientAuth() {
-        return clientAuth == ClientAuth.REQUIRE;
-    }
-
-    @Override
-    public final void setWantClientAuth(boolean b) {
-        setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE);
-    }
-
-    @Override
-    public final boolean getWantClientAuth() {
-        return clientAuth == ClientAuth.OPTIONAL;
-    }
-
-    /**
-     * See <a href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html">SSL_set_verify</a> and
-     * {@link SSL#setVerify(long, int, int)}.
-     */
-    @UnstableApi
-    public final synchronized void setVerify(int verifyMode, int depth) {
-        if (!isDestroyed()) {
-            SSL.setVerify(ssl, verifyMode, depth);
-        }
-    }
-
-    private void setClientAuth(ClientAuth mode) {
-        if (clientMode) {
-            return;
-        }
-        synchronized (this) {
-            if (clientAuth == mode) {
-                // No need to issue any JNI calls if the mode is the same
-                return;
-            }
-            if (!isDestroyed()) {
-                switch (mode) {
-                    case NONE:
-                        SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-                        break;
-                    case REQUIRE:
-                        SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-                        break;
-                    case OPTIONAL:
-                        SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-                        break;
-                    default:
-                        throw new Error(mode.toString());
-                }
-            }
-            clientAuth = mode;
-        }
-    }
-
-    @Override
-    public final void setEnableSessionCreation(boolean b) {
-        if (b) {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    @Override
-    public final boolean getEnableSessionCreation() {
-        return false;
-    }
-
-    @SuppressJava6Requirement(reason = "Usage guarded by java version check")
-    @Override
-    public final synchronized SSLParameters getSSLParameters() {
-        SSLParameters sslParameters = super.getSSLParameters();
-
-        int version = PlatformDependent.javaVersion();
-        if (version >= 7) {
-            sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
-            Java7SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints);
-            if (version >= 8) {
-                if (sniHostNames != null) {
-                    Java8SslUtils.setSniHostNames(sslParameters, sniHostNames);
-                }
-                if (!isDestroyed()) {
-                    Java8SslUtils.setUseCipherSuitesOrder(
-                            sslParameters, (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0);
-                }
-
-                Java8SslUtils.setSNIMatchers(sslParameters, matchers);
-            }
-        }
-        return sslParameters;
-    }
-
-    @SuppressJava6Requirement(reason = "Usage guarded by java version check")
-    @Override
-    public final synchronized void setSSLParameters(SSLParameters sslParameters) {
-        int version = PlatformDependent.javaVersion();
-        if (version >= 7) {
-            if (sslParameters.getAlgorithmConstraints() != null) {
-                throw new IllegalArgumentException("AlgorithmConstraints are not supported.");
-            }
-
-            boolean isDestroyed = isDestroyed();
-            if (version >= 8) {
-                if (!isDestroyed) {
-                    if (clientMode) {
-                        final List<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();
-            }
-
-            final String endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm();
-            if (!isDestroyed) {
-                // If the user asks for hostname verification we must ensure we verify the peer.
-                // If the user disables hostname verification we leave it up to the user to change the mode manually.
-                if (clientMode && isEndPointVerificationEnabled(endPointIdentificationAlgorithm)) {
-                    SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1);
-                }
-            }
-            this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm;
-            algorithmConstraints = sslParameters.getAlgorithmConstraints();
-        }
-        super.setSSLParameters(sslParameters);
-    }
-
-    private static boolean isEndPointVerificationEnabled(String endPointIdentificationAlgorithm) {
-        return endPointIdentificationAlgorithm != null && !endPointIdentificationAlgorithm.isEmpty();
-    }
-
-    private boolean isDestroyed() {
-        return destroyed;
-    }
-
-    final boolean checkSniHostnameMatch(byte[] hostname) {
-        return Java8SslUtils.checkSniHostnameMatch(matchers, hostname);
-    }
-
-    @Override
-    public String getNegotiatedApplicationProtocol() {
-        return applicationProtocol;
-    }
-
-    private static long bufferAddress(ByteBuffer b) {
-        assert b.isDirect();
-        if (PlatformDependent.hasUnsafe()) {
-            return PlatformDependent.directBufferAddress(b);
-        }
-        return Buffer.address(b);
-    }
-
-    /**
-     * 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();
-        }
-    }
-
-    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);
-                }
-            }
-        }
-    }
-
-    final void setSessionId(OpenSslSessionId id) {
-        session.setSessionId(id);
-    }
-
-    private final class DefaultOpenSslSession implements OpenSslSession  {
-        private final OpenSslSessionContext sessionContext;
-
-        // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any
-        // thread.
-        private X509Certificate[] x509PeerCerts;
-        private Certificate[] peerCerts;
-
-        private boolean valid = true;
-        private String protocol;
-        private String cipher;
-        private OpenSslSessionId id = OpenSslSessionId.NULL_ID;
-        private volatile long creationTime;
-        private volatile int applicationBufferSize = MAX_PLAINTEXT_LENGTH;
-        private volatile Certificate[] localCertificateChain;
-        // lazy init for memory reasons
-        private Map<String, Object> values;
-
-        DefaultOpenSslSession(OpenSslSessionContext sessionContext) {
-            this.sessionContext = sessionContext;
-        }
-
-        private SSLSessionBindingEvent newSSLSessionBindingEvent(String name) {
-            return new SSLSessionBindingEvent(session, name);
-        }
-
-        @Override
-        public void setSessionId(OpenSslSessionId sessionId) {
-            synchronized (ReferenceCountedOpenSslEngine.this) {
-                if (this.id == OpenSslSessionId.NULL_ID) {
-                    this.id = sessionId;
-                    creationTime = System.currentTimeMillis();
-                }
-            }
-        }
-
-        @Override
-        public OpenSslSessionId sessionId() {
-            synchronized (ReferenceCountedOpenSslEngine.this) {
-                if (this.id == OpenSslSessionId.NULL_ID && !isDestroyed()) {
-                    byte[] sessionId = SSL.getSessionId(ssl);
-                    if (sessionId != null) {
-                        id = new OpenSslSessionId(sessionId);
-                    }
-                }
-
-                return id;
-            }
-        }
-
-        @Override
-        public void setLocalCertificate(Certificate[] localCertificate) {
-            this.localCertificateChain = localCertificate;
-        }
-
-        @Override
-        public byte[] getId() {
-            return sessionId().cloneBytes();
-        }
-
-        @Override
-        public OpenSslSessionContext getSessionContext() {
-            return sessionContext;
-        }
-
-        @Override
-        public long getCreationTime() {
-            synchronized (ReferenceCountedOpenSslEngine.this) {
-                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) {
-                valid = false;
-                sessionContext.removeFromCache(id);
-            }
-        }
-
-        @Override
-        public boolean isValid() {
-            synchronized (ReferenceCountedOpenSslEngine.this) {
-                return valid || sessionContext.isInCache(id);
-            }
-        }
-
-        @Override
-        public void putValue(String name, Object value) {
-            checkNotNull(name, "name");
-            checkNotNull(value, "value");
-
-            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);
-                }
-                old = values.put(name, value);
-            }
-
-            if (value instanceof SSLSessionBindingListener) {
-                // Use newSSLSessionBindingEvent so we always use the wrapper if needed.
-                ((SSLSessionBindingListener) value).valueBound(newSSLSessionBindingEvent(name));
-            }
-            notifyUnbound(old, name);
-        }
-
-        @Override
-        public Object getValue(String name) {
-            checkNotNull(name, "name");
-            synchronized (this) {
-                if (values == null) {
-                    return null;
-                }
-                return values.get(name);
-            }
-        }
-
-        @Override
-        public void removeValue(String name) {
-            checkNotNull(name, "name");
-
-            final Object old;
-            synchronized (this) {
-                Map<String, Object> values = this.values;
-                if (values == null) {
-                    return;
-                }
-                old = values.remove(name);
-            }
-
-            notifyUnbound(old, name);
-        }
-
-        @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]);
-            }
-        }
-
-        private void notifyUnbound(Object value, String name) {
-            if (value instanceof SSLSessionBindingListener) {
-                // Use newSSLSessionBindingEvent so we always use the wrapper if needed.
-                ((SSLSessionBindingListener) value).valueUnbound(newSSLSessionBindingEvent(name));
-            }
-        }
-
-        /**
-         * Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by
-         * the user.
-         */
-        @Override
-        public void handshakeFinished(byte[] id, String cipher, String protocol, byte[] peerCertificate,
-                                      byte[][] peerCertificateChain, long creationTime, long timeout)
-                throws SSLException {
-            synchronized (ReferenceCountedOpenSslEngine.this) {
-                if (!isDestroyed()) {
-                    this.creationTime = creationTime;
-                    if (this.id == OpenSslSessionId.NULL_ID) {
-                        this.id = id == null ? OpenSslSessionId.NULL_ID : new OpenSslSessionId(id);
-                    }
-                    this.cipher = toJavaCipherSuite(cipher);
-                    this.protocol = protocol;
-
-                    if (clientMode) {
-                        if (isEmpty(peerCertificateChain)) {
-                            peerCerts = EmptyArrays.EMPTY_CERTIFICATES;
-                            x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
-                        } else {
-                            peerCerts = new Certificate[peerCertificateChain.length];
-                            x509PeerCerts = new X509Certificate[peerCertificateChain.length];
-                            initCerts(peerCertificateChain, 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
-                        if (isEmpty(peerCertificate)) {
-                            peerCerts = EmptyArrays.EMPTY_CERTIFICATES;
-                            x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
-                        } else {
-                            if (isEmpty(peerCertificateChain)) {
-                                peerCerts = new Certificate[] {new LazyX509Certificate(peerCertificate)};
-                                x509PeerCerts = new X509Certificate[] {new LazyJavaxX509Certificate(peerCertificate)};
-                            } else {
-                                peerCerts = new Certificate[peerCertificateChain.length + 1];
-                                x509PeerCerts = new X509Certificate[peerCertificateChain.length + 1];
-                                peerCerts[0] = new LazyX509Certificate(peerCertificate);
-                                x509PeerCerts[0] = new LazyJavaxX509Certificate(peerCertificate);
-                                initCerts(peerCertificateChain, 1);
-                            }
-                        }
-                    }
-
-                    calculateMaxWrapOverhead();
-
-                    handshakeState = HandshakeState.FINISHED;
-                } else {
-                    throw new SSLException("Already closed");
-                }
-            }
-        }
-
-        private void initCerts(byte[][] chain, int startPos) {
-            for (int i = 0; i < chain.length; i++) {
-                int certPos = startPos + i;
-                peerCerts[certPos] = new LazyX509Certificate(chain[i]);
-                x509PeerCerts[certPos] = new LazyJavaxX509Certificate(chain[i]);
-            }
-        }
-
-        @Override
-        public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
-            synchronized (ReferenceCountedOpenSslEngine.this) {
-                if (isEmpty(peerCerts)) {
-                    throw new SSLPeerUnverifiedException("peer not verified");
-                }
-                return peerCerts.clone();
-            }
-        }
-
-        @Override
-        public Certificate[] getLocalCertificates() {
-            Certificate[] localCerts = this.localCertificateChain;
-            if (localCerts == null) {
-                return null;
-            }
-            return localCerts.clone();
-        }
-
-        @Override
-        public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
-            synchronized (ReferenceCountedOpenSslEngine.this) {
-                if (isEmpty(x509PeerCerts)) {
-                    throw new SSLPeerUnverifiedException("peer not verified");
-                }
-                return x509PeerCerts.clone();
-            }
-        }
-
-        @Override
-        public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
-            Certificate[] peer = getPeerCertificates();
-            // No need for null or length > 0 is needed as this is done in getPeerCertificates()
-            // already.
-            return ((java.security.cert.X509Certificate) peer[0]).getSubjectX500Principal();
-        }
-
-        @Override
-        public Principal getLocalPrincipal() {
-            Certificate[] local = this.localCertificateChain;
-            if (local == null || local.length == 0) {
-                return null;
-            }
-            return ((java.security.cert.X509Certificate) local[0]).getSubjectX500Principal();
-        }
-
-        @Override
-        public String getCipherSuite() {
-            synchronized (ReferenceCountedOpenSslEngine.this) {
-                if (cipher == null) {
-                    return SslUtils.INVALID_CIPHER;
-                }
-                return cipher;
-            }
-        }
-
-        @Override
-        public String getProtocol() {
-            String protocol = this.protocol;
-            if (protocol == null) {
-                synchronized (ReferenceCountedOpenSslEngine.this) {
-                    if (!isDestroyed()) {
-                        protocol = SSL.getVersion(ssl);
-                    } else {
-                        protocol = StringUtil.EMPTY_STRING;
-                    }
-                }
-            }
-            return protocol;
-        }
-
-        @Override
-        public String getPeerHost() {
-            return ReferenceCountedOpenSslEngine.this.getPeerHost();
-        }
-
-        @Override
-        public int getPeerPort() {
-            return ReferenceCountedOpenSslEngine.this.getPeerPort();
-        }
-
-        @Override
-        public int getPacketBufferSize() {
-            return maxEncryptedPacketLength();
-        }
-
-        @Override
-        public int getApplicationBufferSize() {
-            return applicationBufferSize;
-        }
-
-        @Override
-        public void tryExpandApplicationBufferSize(int packetLengthDataOnly) {
-            if (packetLengthDataOnly > MAX_PLAINTEXT_LENGTH && applicationBufferSize != MAX_RECORD_SIZE) {
-                applicationBufferSize = MAX_RECORD_SIZE;
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "DefaultOpenSslSession{" +
-                    "sessionContext=" + sessionContext +
-                    ", id=" + id +
-                    '}';
-        }
-    }
-}
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 07e0a5de17..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
+++ /dev/null
@@ -1,298 +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:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl;
-
-import io.netty.buffer.ByteBufAllocator;
-import io.netty.internal.tcnative.CertificateCallback;
-import io.netty.internal.tcnative.SSL;
-import io.netty.internal.tcnative.SSLContext;
-import io.netty.internal.tcnative.SniHostNameMatcher;
-import io.netty.util.CharsetUtil;
-import io.netty.util.internal.PlatformDependent;
-import io.netty.util.internal.SuppressJava6Requirement;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.Map;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509ExtendedTrustManager;
-import javax.net.ssl.X509TrustManager;
-
-import static io.netty.util.internal.ObjectUtil.checkNotNull;
-
-/**
- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
- * <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;
-
-    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, Map.Entry<SslContextOption<?>, Object>... options)
-            throws SSLException {
-        this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
-                cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
-                enableOcsp, keyStore, options);
-    }
-
-    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, Map.Entry<SslContextOption<?>, Object>... options)
-            throws SSLException {
-        super(ciphers, cipherFilter, apn, SSL.SSL_MODE_SERVER, keyCertChain,
-              clientAuth, protocols, startTls, enableOcsp, true, options);
-        // Create a new SSL_CTX and configure it.
-        boolean success = false;
-        try {
-            sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-                    keyCertChain, key, keyPassword, keyManagerFactory, keyStore,
-                    sessionCacheSize, sessionTimeout);
-            if (SERVER_ENABLE_SESSION_TICKET) {
-                sessionContext.setTicketKeys();
-            }
-            success = true;
-        } finally {
-            if (!success) {
-                release();
-            }
-        }
-    }
-
-    @Override
-    public OpenSslServerSessionContext sessionContext() {
-        return sessionContext;
-    }
-
-    static OpenSslServerSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
-                                                         OpenSslEngineMap engineMap,
-                                                         X509Certificate[] trustCertCollection,
-                                                         TrustManagerFactory trustManagerFactory,
-                                                         X509Certificate[] keyCertChain, PrivateKey key,
-                                                         String keyPassword, KeyManagerFactory keyManagerFactory,
-                                                         String keyStore, long sessionCacheSize, long sessionTimeout)
-            throws SSLException {
-        OpenSslKeyMaterialProvider keyMaterialProvider = null;
-        try {
-            try {
-                SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
-                if (!OpenSsl.useKeyManagerFactory()) {
-                    if (keyManagerFactory != null) {
-                        throw new IllegalArgumentException(
-                                "KeyManagerFactory not supported");
-                    }
-                    checkNotNull(keyCertChain, "keyCertChain");
-
-                    setKeyMaterial(ctx, keyCertChain, key, keyPassword);
-                } else {
-                    // javadocs state that keyManagerFactory has precedent over keyCertChain, and we must have a
-                    // keyManagerFactory for the server so build one if it is not specified.
-                    if (keyManagerFactory == null) {
-                        char[] keyPasswordChars = keyStorePassword(keyPassword);
-                        KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
-                        if (ks.aliases().hasMoreElements()) {
-                            keyManagerFactory = new OpenSslX509KeyManagerFactory();
-                        } else {
-                            keyManagerFactory = new OpenSslCachingX509KeyManagerFactory(
-                                    KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
-                        }
-                        keyManagerFactory.init(ks, keyPasswordChars);
-                    }
-                    keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
-
-                    SSLContext.setCertificateCallback(ctx, new OpenSslServerCertificateCallback(
-                            engineMap, new OpenSslKeyMaterialManager(keyMaterialProvider)));
-                }
-            } catch (Exception e) {
-                throw new SSLException("failed to set certificate and key", e);
-            }
-            try {
-                if (trustCertCollection != null) {
-                    trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
-                } else if (trustManagerFactory == null) {
-                    // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
-                    trustManagerFactory = TrustManagerFactory.getInstance(
-                            TrustManagerFactory.getDefaultAlgorithm());
-                    trustManagerFactory.init((KeyStore) null);
-                }
-
-                final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
-
-                // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as
-                //            otherwise the context can never be collected. This is because the JNI code holds
-                //            a global reference to the callbacks.
-                //
-                //            See https://github.com/netty/netty/issues/5372
-
-                setVerifyCallback(ctx, engineMap, manager);
-
-                X509Certificate[] issuers = manager.getAcceptedIssuers();
-                if (issuers != null && issuers.length > 0) {
-                    long bio = 0;
-                    try {
-                        bio = toBIO(ByteBufAllocator.DEFAULT, issuers);
-                        if (!SSLContext.setCACertificateBio(ctx, bio)) {
-                            throw new SSLException("unable to setup accepted issuers for trustmanager " + manager);
-                        }
-                    } finally {
-                        freeBio(bio);
-                    }
-                }
-
-                if (PlatformDependent.javaVersion() >= 8) {
-                    // Only do on Java8+ as SNIMatcher is not supported in earlier releases.
-                    // IMPORTANT: The callbacks set for hostname matching must be static to prevent memory leak as
-                    //            otherwise the context can never be collected. This is because the JNI code holds
-                    //            a global reference to the matcher.
-                    SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engineMap));
-                }
-            } catch (SSLException e) {
-                throw e;
-            } catch (Exception e) {
-                throw new SSLException("unable to setup trustmanager", e);
-            }
-
-            OpenSslServerSessionContext sessionContext = new OpenSslServerSessionContext(thiz, keyMaterialProvider);
-            sessionContext.setSessionIdContext(ID);
-            // Enable session caching by default
-            sessionContext.setSessionCacheEnabled(SERVER_ENABLE_SESSION_CACHE);
-            if (sessionCacheSize > 0) {
-                sessionContext.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE));
-            }
-            if (sessionTimeout > 0) {
-                sessionContext.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE));
-            }
-
-            keyMaterialProvider = null;
-
-            return sessionContext;
-        } finally {
-            if (keyMaterialProvider != null) {
-                keyMaterialProvider.destroy();
-            }
-        }
-    }
-
-    @SuppressJava6Requirement(reason = "Guarded by java version check")
-    private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap, X509TrustManager manager) {
-        // Use this to prevent an error when running on java < 7
-        if (useExtendedTrustManager(manager)) {
-            SSLContext.setCertVerifyCallback(ctx, new ExtendedTrustManagerVerifyCallback(
-                    engineMap, (X509ExtendedTrustManager) manager));
-        } else {
-            SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
-        }
-    }
-
-    private static final class OpenSslServerCertificateCallback implements CertificateCallback {
-        private final OpenSslEngineMap engineMap;
-        private final OpenSslKeyMaterialManager keyManagerHolder;
-
-        OpenSslServerCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
-            this.engineMap = engineMap;
-            this.keyManagerHolder = keyManagerHolder;
-        }
-
-        @Override
-        public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
-            final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-            if (engine == null) {
-                // Maybe null if destroyed in the meantime.
-                return;
-            }
-            try {
-                // For now we just ignore the asn1DerEncodedPrincipals as this is kind of inline with what the
-                // OpenJDK SSLEngineImpl does.
-                keyManagerHolder.setKeyMaterialServerSide(engine);
-            } catch (Throwable cause) {
-                engine.initHandshakeException(cause);
-
-                if (cause instanceof Exception) {
-                    throw (Exception) cause;
-                }
-                throw new SSLException(cause);
-            }
-        }
-    }
-
-    private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
-        private final X509TrustManager manager;
-
-        TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
-            super(engineMap);
-            this.manager = manager;
-        }
-
-        @Override
-        void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-                throws Exception {
-            manager.checkClientTrusted(peerCerts, auth);
-        }
-    }
-
-    @SuppressJava6Requirement(reason = "Usage guarded by java version check")
-    private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
-        private final X509ExtendedTrustManager manager;
-
-        ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
-            super(engineMap);
-            this.manager = manager;
-        }
-
-        @Override
-        void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-                throws Exception {
-            manager.checkClientTrusted(peerCerts, auth, engine);
-        }
-    }
-
-    private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher {
-        private final OpenSslEngineMap engineMap;
-
-        OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) {
-            this.engineMap = engineMap;
-        }
-
-        @Override
-        public boolean match(long ssl, String hostname) {
-            ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-            if (engine != null) {
-                // TODO: In the next release of tcnative we should pass the byte[] directly in and not use a String.
-                return engine.checkSniHostnameMatch(hostname.getBytes(CharsetUtil.UTF_8));
-            }
-            logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl);
-            return false;
-        }
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
index ff93d4011c..1c8efb7151 100644
--- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java
+++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
@@ -121,11 +121,7 @@ public abstract class SslContext {
     }
 
     private static SslProvider defaultProvider() {
-        if (OpenSsl.isAvailable()) {
-            return SslProvider.OPENSSL;
-        } else {
-            return SslProvider.JDK;
-        }
+        return SslProvider.JDK;
     }
 
     /**
@@ -468,18 +464,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, ctxOptions);
-        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, ctxOptions);
         default:
             throw new Error(provider.toString());
         }
@@ -825,20 +809,6 @@ public abstract class SslContext {
                         trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
                         keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize,
                         sessionTimeout, keyStoreType);
-            case OPENSSL:
-                verifyNullSslContextProvider(provider, sslContextProvider);
-                OpenSsl.ensureAvailability();
-                return new OpenSslClientContext(
-                        trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
-                        keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
-                        enableOcsp, keyStoreType, options);
-            case OPENSSL_REFCNT:
-                verifyNullSslContextProvider(provider, sslContextProvider);
-                OpenSsl.ensureAvailability();
-                return new ReferenceCountedOpenSslClientContext(
-                        trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
-                        keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
-                        enableOcsp, keyStoreType, options);
             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 73f1bdad3c..ac9f2ed35c 100644
--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
@@ -198,51 +198,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 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(in.readerIndex(), len), handler.singleBuffer);
-                    } finally {
-                        handler.singleBuffer[0] = null;
-                    }
-                } else {
-                    result = handler.engine.unwrap(toByteBuffer(in, in.readerIndex(), len),
-                        toByteBuffer(out, writerIndex, out.writableBytes()));
-                }
-                out.writerIndex(writerIndex + result.bytesProduced());
-                return result;
-            }
-
-            @Override
-            ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
-                                       int pendingBytes, int numComponents) {
-                return allocator.directBuffer(((ReferenceCountedOpenSslEngine) handler.engine)
-                        .calculateMaxLengthForWrap(pendingBytes, numComponents));
-            }
-
-            @Override
-            int calculatePendingData(SslHandler handler, int guess) {
-                int sslPending = ((ReferenceCountedOpenSslEngine) handler.engine).sslPending();
-                return sslPending > 0 ? sslPending : guess;
-            }
-
-            @Override
-            boolean jdkCompatibilityMode(SSLEngine engine) {
-                return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
-            }
-        },
         JDK(false, MERGE_CUMULATOR) {
             @Override
             SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int len, ByteBuf out) throws SSLException {
@@ -294,7 +249,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 231bd7985e..38bd913993 100644
--- a/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
+++ b/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
@@ -139,9 +139,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 9f890e2e79..0bc7c5b156 100644
--- a/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
+++ b/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
@@ -28,16 +28,7 @@ public enum SslProvider {
     /**
      * JDK's default implementation.
      */
-    JDK,
-    /**
-     * OpenSSL-based implementation.
-     */
-    OPENSSL,
-    /**
-     * OpenSSL-based implementation which does not have finalizers and instead implements {@link ReferenceCounted}.
-     */
-    @UnstableApi
-    OPENSSL_REFCNT;
+    JDK;
 
     /**
      * Returns {@code true} if the specified {@link SslProvider} supports
@@ -48,9 +39,6 @@ public enum SslProvider {
         switch (provider) {
             case JDK:
                 return JdkAlpnApplicationProtocolNegotiator.isAlpnSupported();
-            case OPENSSL:
-            case OPENSSL_REFCNT:
-                return OpenSsl.isAlpnSupported();
             default:
                 throw new Error("Unknown SslProvider: " + provider);
         }
@@ -72,9 +60,6 @@ public enum SslProvider {
         switch (sslProvider) {
             case JDK:
                 return SslUtils.isTLSv13SupportedByJDK(provider);
-            case OPENSSL:
-            case OPENSSL_REFCNT:
-                return OpenSsl.isTlsv13Supported();
             default:
                 throw new Error("Unknown SslProvider: " + sslProvider);
         }
@@ -88,9 +73,6 @@ public enum SslProvider {
         switch (sslProvider) {
             case JDK:
                 return SslUtils.isTLSv13EnabledByJDK(provider);
-            case OPENSSL:
-            case OPENSSL_REFCNT:
-                return OpenSsl.isTlsv13Supported();
             default:
                 throw new Error("Unknown SslProvider: " + sslProvider);
         }
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 7f9cdf65cb..0000000000
--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2017 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.handler.ssl.ocsp;
-
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
-import io.netty.handler.ssl.ReferenceCountedOpenSslContext;
-import io.netty.handler.ssl.ReferenceCountedOpenSslEngine;
-import io.netty.handler.ssl.SslHandshakeCompletionEvent;
-import io.netty.util.internal.ObjectUtil;
-import io.netty.util.internal.UnstableApi;
-
-import javax.net.ssl.SSLHandshakeException;
-
-/**
- * A handler for SSL clients to handle and act upon stapled OCSP responses.
- *
- * @see ReferenceCountedOpenSslContext#enableOcsp()
- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
- */
-@UnstableApi
-public abstract class OcspClientHandler extends ChannelInboundHandlerAdapter {
-
-    private final ReferenceCountedOpenSslEngine engine;
-
-    protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) {
-        this.engine = ObjectUtil.checkNotNull(engine, "engine");
-    }
-
-    /**
-     * @see ReferenceCountedOpenSslEngine#getOcspResponse()
-     */
-    protected abstract boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception;
-
-    @Override
-    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
-        if (evt instanceof SslHandshakeCompletionEvent) {
-            ctx.pipeline().remove(this);
-
-            SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt;
-            if (event.isSuccess() && !verify(ctx, engine)) {
-                throw new SSLHandshakeException("Bad OCSP response");
-            }
-        }
-
-        ctx.fireUserEventTriggered(evt);
-    }
-}
diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
deleted file mode 100644
index 7e81ae6b23..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:
- *
- *   https://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 2f2799f731..c743bd97f3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -659,23 +659,6 @@
         <version>3.0.0-alpha-5</version>
       </dependency>
 
-      <!-- Our own Tomcat Native fork - completely optional for the native lib, used for accelerating SSL with OpenSSL. -->
-      <dependency>
-        <groupId>${project.groupId}</groupId>
-        <artifactId>netty-tcnative-classes</artifactId>
-        <version>${tcnative.version}</version>
-        <scope>compile</scope>
-        <optional>true</optional>
-      </dependency>
-      <dependency>
-        <groupId>${project.groupId}</groupId>
-        <artifactId>${tcnative.artifactId}</artifactId>
-        <version>${tcnative.version}</version>
-        <classifier>${tcnative.classifier}</classifier>
-        <scope>runtime</scope>
-        <optional>true</optional>
-      </dependency>
-
       <!--
         Bouncy Castle - completely optional, only needed when:
         - you generate a temporary self-signed certificate using SelfSignedCertificate, and
-- 
2.35.1

