From c84caa81fd8f809cdae53719bff1d02838e1b47b Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Fri, 7 Jun 2019 14:44:30 -0400 Subject: [PATCH] import netty-4.1.13-5.el8+1359+ee4104af --- .gitignore | 1 + .netty.metadata | 1 + ...-OpenSSL-parts-depending-on-tcnative.patch | 8985 +++++++++++++++++ SOURCES/0002-Remove-NPN.patch | 353 + SOURCES/0003-Remove-conscrypt-ALPN.patch | 511 + SOURCES/0004-Remove-jetty-ALPN.patch | 217 + SOURCES/codegen.bash | 22 + SPECS/netty.spec | 378 + 8 files changed, 10468 insertions(+) create mode 100644 .gitignore create mode 100644 .netty.metadata create mode 100644 SOURCES/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch create mode 100644 SOURCES/0002-Remove-NPN.patch create mode 100644 SOURCES/0003-Remove-conscrypt-ALPN.patch create mode 100644 SOURCES/0004-Remove-jetty-ALPN.patch create mode 100755 SOURCES/codegen.bash create mode 100644 SPECS/netty.spec diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7bf606 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/netty-4.1.13.Final.tar.gz diff --git a/.netty.metadata b/.netty.metadata new file mode 100644 index 0000000..ab78cdc --- /dev/null +++ b/.netty.metadata @@ -0,0 +1 @@ +9242c1e3b29ec71a94791e036ee97b9c3ce0af58 SOURCES/netty-4.1.13.Final.tar.gz diff --git a/SOURCES/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch b/SOURCES/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch new file mode 100644 index 0000000..aee0650 --- /dev/null +++ b/SOURCES/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch @@ -0,0 +1,8985 @@ +From 39b320920d3473d8cbc94d4a35dad37fa236e278 Mon Sep 17 00:00:00 2001 +From: Severin Gehwolf +Date: Thu, 20 Oct 2016 15:54:52 +0200 +Subject: [PATCH 1/3] Remove OpenSSL parts depending on tcnative. + +--- + handler/pom.xml | 6 - + .../main/java/io/netty/handler/ssl/OpenSsl.java | 503 ----- + .../handler/ssl/OpenSslCertificateException.java | 79 - + .../io/netty/handler/ssl/OpenSslClientContext.java | 211 -- + .../java/io/netty/handler/ssl/OpenSslContext.java | 58 - + .../java/io/netty/handler/ssl/OpenSslEngine.java | 40 - + .../io/netty/handler/ssl/OpenSslEngineMap.java | 35 - + .../ssl/OpenSslExtendedKeyMaterialManager.java | 40 - + .../handler/ssl/OpenSslKeyMaterialManager.java | 179 -- + .../io/netty/handler/ssl/OpenSslServerContext.java | 373 ---- + .../handler/ssl/OpenSslServerSessionContext.java | 124 -- + .../netty/handler/ssl/OpenSslSessionContext.java | 137 -- + .../io/netty/handler/ssl/OpenSslSessionStats.java | 253 --- + .../netty/handler/ssl/OpenSslSessionTicketKey.java | 78 - + .../ssl/ReferenceCountedOpenSslClientContext.java | 298 --- + .../ssl/ReferenceCountedOpenSslContext.java | 867 --------- + .../handler/ssl/ReferenceCountedOpenSslEngine.java | 2037 -------------------- + .../ssl/ReferenceCountedOpenSslServerContext.java | 239 --- + .../main/java/io/netty/handler/ssl/SslContext.java | 30 +- + .../main/java/io/netty/handler/ssl/SslHandler.java | 47 +- + .../netty/handler/ssl/ocsp/OcspClientHandler.java | 65 - + .../io/netty/handler/ssl/ocsp/package-info.java | 23 - + .../handler/ssl/JdkOpenSslEngineInteroptTest.java | 108 -- + .../ssl/OpenSslCertificateExceptionTest.java | 49 - + .../handler/ssl/OpenSslClientContextTest.java | 38 - + .../io/netty/handler/ssl/OpenSslEngineTest.java | 661 ------- + .../ssl/OpenSslJdkSslEngineInteroptTest.java | 114 -- + .../ssl/OpenSslRenegotiateSmallBIOTest.java | 23 - + .../netty/handler/ssl/OpenSslRenegotiateTest.java | 36 - + .../handler/ssl/OpenSslServerContextTest.java | 39 - + .../io/netty/handler/ssl/OpenSslTestUtils.java | 27 - + .../java/io/netty/handler/ssl/PemEncodedTest.java | 95 - + .../ssl/ReferenceCountedOpenSslEngineTest.java | 57 - + .../java/io/netty/handler/ssl/SniClientTest.java | 161 -- + .../java/io/netty/handler/ssl/SniHandlerTest.java | 496 ----- + .../netty/handler/ssl/SslContextBuilderTest.java | 132 -- + .../java/io/netty/handler/ssl/SslErrorTest.java | 255 --- + .../java/io/netty/handler/ssl/SslHandlerTest.java | 58 +- + .../java/io/netty/handler/ssl/ocsp/OcspTest.java | 501 ----- + 39 files changed, 10 insertions(+), 8562 deletions(-) + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSsl.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/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/ReferenceCountedOpenSslClientContext.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SniClientTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java + +diff --git a/handler/pom.xml b/handler/pom.xml +index 7535c45..d0ed1bc 100644 +--- a/handler/pom.xml ++++ b/handler/pom.xml +@@ -50,12 +50,6 @@ + ${project.version} + + +- ${project.groupId} +- ${tcnative.artifactId} +- ${tcnative.classifier} +- true +- +- + org.bouncycastle + bcpkix-jdk15on + true +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 d2f091a..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java ++++ /dev/null +@@ -1,503 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-package io.netty.handler.ssl; +- +-import io.netty.buffer.ByteBuf; +-import io.netty.handler.ssl.util.SelfSignedCertificate; +-import io.netty.util.ReferenceCountUtil; +-import io.netty.util.ReferenceCounted; +-import io.netty.util.internal.NativeLibraryLoader; +-import io.netty.util.internal.SystemPropertyUtil; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; +-import io.netty.internal.tcnative.Buffer; +-import io.netty.internal.tcnative.Library; +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +- +-import java.security.AccessController; +-import java.security.PrivilegedAction; +-import java.util.Collections; +-import java.util.LinkedHashSet; +-import java.util.Locale; +-import java.util.Set; +- +-/** +- * Tells if {@code netty-tcnative} and its OpenSSL support +- * are available. +- */ +-public final class OpenSsl { +- +- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class); +- private static final String LINUX = "linux"; +- private static final String UNKNOWN = "unknown"; +- private static final Throwable UNAVAILABILITY_CAUSE; +- +- static final Set AVAILABLE_CIPHER_SUITES; +- private static final Set AVAILABLE_OPENSSL_CIPHER_SUITES; +- private static final Set AVAILABLE_JAVA_CIPHER_SUITES; +- private static final boolean SUPPORTS_KEYMANAGER_FACTORY; +- private static final boolean SUPPORTS_HOSTNAME_VALIDATION; +- private static final boolean USE_KEYMANAGER_FACTORY; +- private static final boolean SUPPORTS_OCSP; +- +- // Protocols +- static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello"; +- static final String PROTOCOL_SSL_V2 = "SSLv2"; +- static final String PROTOCOL_SSL_V3 = "SSLv3"; +- static final String PROTOCOL_TLS_V1 = "TLSv1"; +- static final String PROTOCOL_TLS_V1_1 = "TLSv1.1"; +- static final String PROTOCOL_TLS_V1_2 = "TLSv1.2"; +- +- static final Set SUPPORTED_PROTOCOLS_SET; +- +- static { +- Throwable cause = null; +- +- // Test if netty-tcnative is in the classpath first. +- try { +- Class.forName("io.netty.internal.tcnative.SSL", false, OpenSsl.class.getClassLoader()); +- } catch (ClassNotFoundException t) { +- cause = t; +- logger.debug( +- "netty-tcnative not in the classpath; " + +- OpenSslEngine.class.getSimpleName() + " will be unavailable."); +- } +- +- // If in the classpath, try to load the native library and initialize netty-tcnative. +- if (cause == null) { +- try { +- // The JNI library was not already loaded. Load it now. +- loadTcNative(); +- } catch (Throwable t) { +- cause = t; +- logger.debug( +- "Failed to load netty-tcnative; " + +- OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " + +- "application has already loaded the symbols by some other means. " + +- "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t); +- } +- +- try { +- initializeTcNative(); +- +- // The library was initialized successfully. If loading the library failed above, +- // reset the cause now since it appears that the library was loaded by some other +- // means. +- cause = null; +- } catch (Throwable t) { +- if (cause == null) { +- cause = t; +- } +- logger.debug( +- "Failed to initialize netty-tcnative; " + +- OpenSslEngine.class.getSimpleName() + " will be unavailable. " + +- "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t); +- } +- } +- +- UNAVAILABILITY_CAUSE = cause; +- +- if (cause == null) { +- logger.debug("netty-tcnative using native library: {}", SSL.versionString()); +- +- final Set availableOpenSslCipherSuites = new LinkedHashSet(128); +- boolean supportsKeyManagerFactory = false; +- boolean useKeyManagerFactory = false; +- boolean supportsHostNameValidation = false; +- try { +- final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER); +- long certBio = 0; +- SelfSignedCertificate cert = null; +- try { +- SSLContext.setCipherSuite(sslCtx, "ALL"); +- final long ssl = SSL.newSSL(sslCtx, true); +- try { +- for (String c: SSL.getCiphers(ssl)) { +- // Filter out bad input. +- if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c)) { +- continue; +- } +- availableOpenSslCipherSuites.add(c); +- } +- try { +- SSL.setHostNameValidation(ssl, 0, "netty.io"); +- supportsHostNameValidation = true; +- } catch (Throwable ignore) { +- logger.debug("Hostname Verification not supported."); +- } +- try { +- cert = new SelfSignedCertificate(); +- certBio = ReferenceCountedOpenSslContext.toBIO(cert.cert()); +- SSL.setCertificateChainBio(ssl, certBio, false); +- supportsKeyManagerFactory = true; +- try { +- useKeyManagerFactory = AccessController.doPrivileged(new PrivilegedAction() { +- @Override +- public Boolean run() { +- return SystemPropertyUtil.getBoolean( +- "io.netty.handler.ssl.openssl.useKeyManagerFactory", true); +- } +- }); +- } catch (Throwable ignore) { +- logger.debug("Failed to get useKeyManagerFactory system property."); +- } +- } catch (Throwable ignore) { +- logger.debug("KeyManagerFactory not supported."); +- } +- } finally { +- SSL.freeSSL(ssl); +- if (certBio != 0) { +- SSL.freeBIO(certBio); +- } +- if (cert != null) { +- cert.delete(); +- } +- } +- } finally { +- SSLContext.free(sslCtx); +- } +- } catch (Exception e) { +- logger.warn("Failed to get the list of available OpenSSL cipher suites.", e); +- } +- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites); +- +- final Set availableJavaCipherSuites = new LinkedHashSet( +- AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2); +- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) { +- // Included converted but also openssl cipher name +- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS")); +- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL")); +- } +- AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites); +- +- final Set availableCipherSuites = new LinkedHashSet( +- AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size()); +- availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES); +- availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES); +- +- AVAILABLE_CIPHER_SUITES = availableCipherSuites; +- SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory; +- SUPPORTS_HOSTNAME_VALIDATION = supportsHostNameValidation; +- USE_KEYMANAGER_FACTORY = useKeyManagerFactory; +- +- Set protocols = new LinkedHashSet(6); +- // Seems like there is no way to explicitly disable SSLv2Hello in openssl so it is always enabled +- protocols.add(PROTOCOL_SSL_V2_HELLO); +- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2)) { +- protocols.add(PROTOCOL_SSL_V2); +- } +- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3)) { +- protocols.add(PROTOCOL_SSL_V3); +- } +- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1)) { +- protocols.add(PROTOCOL_TLS_V1); +- } +- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1)) { +- protocols.add(PROTOCOL_TLS_V1_1); +- } +- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2)) { +- protocols.add(PROTOCOL_TLS_V1_2); +- } +- +- SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols); +- SUPPORTS_OCSP = doesSupportOcsp(); +- } else { +- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet(); +- AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet(); +- AVAILABLE_CIPHER_SUITES = Collections.emptySet(); +- SUPPORTS_KEYMANAGER_FACTORY = false; +- SUPPORTS_HOSTNAME_VALIDATION = false; +- USE_KEYMANAGER_FACTORY = false; +- SUPPORTED_PROTOCOLS_SET = Collections.emptySet(); +- SUPPORTS_OCSP = false; +- } +- } +- +- 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) { +- long sslCtx = -1; +- try { +- sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED); +- return true; +- } catch (Exception ignore) { +- return false; +- } finally { +- if (sslCtx != -1) { +- SSLContext.free(sslCtx); +- } +- } +- } +- +- /** +- * Returns {@code true} if and only if +- * {@code netty-tcnative} and its OpenSSL support +- * are available. +- */ +- public static boolean isAvailable() { +- return UNAVAILABILITY_CAUSE == null; +- } +- +- /** +- * Returns {@code true} if the used version of openssl supports +- * ALPN. +- */ +- public static boolean isAlpnSupported() { +- return version() >= 0x10002000L; +- } +- +- /** +- * Returns {@code true} if the used version of OpenSSL supports OCSP stapling. +- */ +- public static boolean isOcspSupported() { +- return SUPPORTS_OCSP; +- } +- +- /** +- * Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()} +- * returns {@code false}. +- */ +- public static int version() { +- return isAvailable() ? SSL.version() : -1; +- } +- +- /** +- * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()} +- * returns {@code false}. +- */ +- public static String versionString() { +- return isAvailable() ? SSL.versionString() : null; +- } +- +- /** +- * Ensure that {@code netty-tcnative} and +- * its OpenSSL support are available. +- * +- * @throws UnsatisfiedLinkError if unavailable +- */ +- public static void ensureAvailability() { +- if (UNAVAILABILITY_CAUSE != null) { +- throw (Error) new UnsatisfiedLinkError( +- "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE); +- } +- } +- +- /** +- * Returns the cause of unavailability of +- * {@code netty-tcnative} and its OpenSSL support. +- * +- * @return the cause if unavailable. {@code null} if available. +- */ +- public static Throwable unavailabilityCause() { +- return UNAVAILABILITY_CAUSE; +- } +- +- /** +- * @deprecated use {@link #availableOpenSslCipherSuites()} +- */ +- @Deprecated +- public static Set availableCipherSuites() { +- return availableOpenSslCipherSuites(); +- } +- +- /** +- * Returns all the available OpenSSL cipher suites. +- * Please note that the returned array may include the cipher suites that are insecure or non-functional. +- */ +- public static Set availableOpenSslCipherSuites() { +- return AVAILABLE_OPENSSL_CIPHER_SUITES; +- } +- +- /** +- * Returns all the available cipher suites (Java-style). +- * Please note that the returned array may include the cipher suites that are insecure or non-functional. +- */ +- public static Set availableJavaCipherSuites() { +- return AVAILABLE_JAVA_CIPHER_SUITES; +- } +- +- /** +- * Returns {@code true} if and only if the specified cipher suite is available in OpenSSL. +- * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted. +- */ +- public static boolean isCipherSuiteAvailable(String cipherSuite) { +- String converted = CipherSuiteConverter.toOpenSsl(cipherSuite); +- 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; +- } +- +- /** +- * Returns {@code true} if Hostname Validation +- * is supported when using OpenSSL. +- */ +- public static boolean supportsHostnameValidation() { +- return SUPPORTS_HOSTNAME_VALIDATION; +- } +- +- static boolean useKeyManagerFactory() { +- return USE_KEYMANAGER_FACTORY; +- } +- +- static long memoryAddress(ByteBuf buf) { +- assert buf.isDirect(); +- return buf.hasMemoryAddress() ? buf.memoryAddress() : Buffer.address(buf.nioBuffer()); +- } +- +- private OpenSsl() { } +- +- private static void loadTcNative() throws Exception { +- String os = normalizeOs(SystemPropertyUtil.get("os.name", "")); +- String arch = normalizeArch(SystemPropertyUtil.get("os.arch", "")); +- +- Set libNames = new LinkedHashSet(4); +- // First, try loading the platform-specific library. Platform-specific +- // libraries will be available if using a tcnative uber jar. +- libNames.add("netty-tcnative-" + os + '-' + arch); +- if (LINUX.equalsIgnoreCase(os)) { +- // Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0).. +- libNames.add("netty-tcnative-" + os + '-' + arch + "-fedora"); +- } +- // finally the default library. +- libNames.add("netty-tcnative"); +- // in Java 8, statically compiled JNI code is namespaced +- libNames.add("netty_tcnative"); +- +- NativeLibraryLoader.loadFirstAvailable(SSL.class.getClassLoader(), +- libNames.toArray(new String[libNames.size()])); +- } +- +- private static boolean initializeTcNative() throws Exception { +- return Library.initialize(); +- } +- +- private static String normalizeOs(String value) { +- value = normalize(value); +- if (value.startsWith("aix")) { +- return "aix"; +- } +- if (value.startsWith("hpux")) { +- return "hpux"; +- } +- if (value.startsWith("os400")) { +- // Avoid the names such as os4000 +- if (value.length() <= 5 || !Character.isDigit(value.charAt(5))) { +- return "os400"; +- } +- } +- if (value.startsWith(LINUX)) { +- return LINUX; +- } +- if (value.startsWith("macosx") || value.startsWith("osx")) { +- return "osx"; +- } +- if (value.startsWith("freebsd")) { +- return "freebsd"; +- } +- if (value.startsWith("openbsd")) { +- return "openbsd"; +- } +- if (value.startsWith("netbsd")) { +- return "netbsd"; +- } +- if (value.startsWith("solaris") || value.startsWith("sunos")) { +- return "sunos"; +- } +- if (value.startsWith("windows")) { +- return "windows"; +- } +- +- return UNKNOWN; +- } +- +- private static String normalizeArch(String value) { +- value = normalize(value); +- if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) { +- return "x86_64"; +- } +- if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) { +- return "x86_32"; +- } +- if (value.matches("^(ia64|itanium64)$")) { +- return "itanium_64"; +- } +- if (value.matches("^(sparc|sparc32)$")) { +- return "sparc_32"; +- } +- if (value.matches("^(sparcv9|sparc64)$")) { +- return "sparc_64"; +- } +- if (value.matches("^(arm|arm32)$")) { +- return "arm_32"; +- } +- if ("aarch64".equals(value)) { +- return "aarch_64"; +- } +- if (value.matches("^(ppc|ppc32)$")) { +- return "ppc_32"; +- } +- if ("ppc64".equals(value)) { +- return "ppc_64"; +- } +- if ("ppc64le".equals(value)) { +- return "ppcle_64"; +- } +- if ("s390".equals(value)) { +- return "s390_32"; +- } +- if ("s390x".equals(value)) { +- return "s390_64"; +- } +- +- return UNKNOWN; +- } +- +- private static String normalize(String value) { +- return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", ""); +- } +- +- static void releaseIfNeeded(ReferenceCounted counted) { +- if (counted.refCnt() > 0) { +- ReferenceCountUtil.safeRelease(counted); +- } +- } +-} +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 4672d00..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java ++++ /dev/null +@@ -1,79 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.internal.tcnative.CertificateVerifier; +- +-import java.security.cert.CertificateException; +- +-/** +- * A special {@link CertificateException} which allows to specify which error code is included in the +- * SSL Record. This only work when {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT} is used. +- */ +-public final class OpenSslCertificateException extends CertificateException { +- private static final long serialVersionUID = 5542675253797129798L; +- +- private final int errorCode; +- +- /** +- * Construct a new exception with the +- * error code. +- */ +- public OpenSslCertificateException(int errorCode) { +- this((String) null, errorCode); +- } +- +- /** +- * Construct a new exception with the msg and +- * error code . +- */ +- public OpenSslCertificateException(String msg, int errorCode) { +- super(msg); +- this.errorCode = checkErrorCode(errorCode); +- } +- +- /** +- * Construct a new exception with the msg, cause and +- * error code . +- */ +- public OpenSslCertificateException(String message, Throwable cause, int errorCode) { +- super(message, cause); +- this.errorCode = checkErrorCode(errorCode); +- } +- +- /** +- * Construct a new exception with the cause and +- * error code . +- */ +- public OpenSslCertificateException(Throwable cause, int errorCode) { +- this(null, cause, errorCode); +- } +- +- /** +- * Return the error code to use. +- */ +- public int errorCode() { +- return errorCode; +- } +- +- private static int checkErrorCode(int errorCode) { +- if (!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 46412e9..0000000 +--- 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: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.internal.tcnative.SSL; +- +-import java.io.File; +-import java.security.PrivateKey; +-import java.security.cert.X509Certificate; +- +-import javax.net.ssl.KeyManagerFactory; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.TrustManager; +-import javax.net.ssl.TrustManagerFactory; +- +-import static io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext; +- +-/** +- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- *

This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers +- * and manually release the native memory see {@link ReferenceCountedOpenSslClientContext}. +- */ +-public final class OpenSslClientContext extends OpenSslContext { +- private final OpenSslSessionContext sessionContext; +- +- /** +- * Creates a new instance. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslClientContext() throws SSLException { +- this((File) null, null, null, null, null, null, null, IdentityCipherSuiteFilter.INSTANCE, null, 0, 0); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format. +- * {@code null} to use the system default +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslClientContext(File certChainFile) throws SSLException { +- this(certChainFile, null); +- } +- +- /** +- * Creates a new instance. +- * +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from servers. +- * {@code null} to use the default. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws SSLException { +- this(null, trustManagerFactory); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format. +- * {@code null} to use the system default +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from servers. +- * {@code null} to use the default. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException { +- this(certChainFile, trustManagerFactory, null, null, null, null, null, +- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from servers. +- * {@code null} to use the default.. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param apn Provides a means to configure parameters related to application protocol negotiation. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable ciphers, +- ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) +- throws SSLException { +- this(certChainFile, trustManagerFactory, null, null, null, null, ciphers, IdentityCipherSuiteFilter.INSTANCE, +- apn, sessionCacheSize, sessionTimeout); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from servers. +- * {@code null} to use the default.. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * @param apn Provides a means to configure parameters related to application protocol negotiation. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(certChainFile, trustManagerFactory, null, null, null, null, +- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); +- } +- +- /** +- * Creates a new instance. +- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. +- * {@code null} to use the system default +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from servers. +- * {@code null} to use the default or the results of parsing +- * {@code trustCertCollectionFile} +- * @param keyCertChainFile an X.509 certificate chain file in PEM format. +- * This provides the public key for mutual authentication. +- * {@code null} to use the system default +- * @param keyFile a PKCS#8 private key file in PEM format. +- * This provides the private key for mutual authentication. +- * {@code null} for no mutual authentication. +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * Ignored if {@code keyFile} is {@code null}. +- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link javax.net.ssl.KeyManager}s +- * that is used to encrypt data being sent to servers. +- * {@code null} to use the default or the results of parsing +- * {@code keyCertChainFile} and {@code keyFile}. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * @param apn Application Protocol Negotiator object. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, +- File keyCertChainFile, File keyFile, String keyPassword, +- KeyManagerFactory keyManagerFactory, Iterable ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout) +- throws SSLException { +- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, +- toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), +- keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, null, sessionCacheSize, +- sessionTimeout, false); +- } +- +- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, +- KeyManagerFactory keyManagerFactory, Iterable ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols, +- long sessionCacheSize, long sessionTimeout, boolean enableOcsp) +- throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, +- ClientAuth.NONE, protocols, false, enableOcsp); +- boolean success = false; +- try { +- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, +- keyCertChain, key, keyPassword, keyManagerFactory); +- success = true; +- } finally { +- if (!success) { +- release(); +- } +- } +- } +- +- @Override +- public OpenSslSessionContext sessionContext() { +- return sessionContext; +- } +- +- @Override +- OpenSslKeyMaterialManager keyMaterialManager() { +- return null; +- } +-} +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 c4ca6b5..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java ++++ /dev/null +@@ -1,58 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.buffer.ByteBufAllocator; +- +-import java.security.cert.Certificate; +- +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +- +-/** +- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers +- * and manually release the native memory see {@link ReferenceCountedOpenSslContext}. +- */ +-public abstract class OpenSslContext extends ReferenceCountedOpenSslContext { +- OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg, +- long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain, +- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp) +- throws SSLException { +- super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain, +- clientAuth, protocols, startTls, enableOcsp, false); +- } +- +- OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, +- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, +- long sessionTimeout, int mode, Certificate[] keyCertChain, +- ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, protocols, +- startTls, enableOcsp, false); +- } +- +- @Override +- final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) { +- return new OpenSslEngine(this, alloc, peerHost, peerPort); +- } +- +- @Override +- @SuppressWarnings("FinalizeDeclaration") +- protected final void finalize() throws Throwable { +- super.finalize(); +- OpenSsl.releaseIfNeeded(this); +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java +deleted file mode 100644 +index cbc7ee4..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java ++++ /dev/null +@@ -1,40 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.buffer.ByteBufAllocator; +- +-import javax.net.ssl.SSLEngine; +- +-/** +- * Implements a {@link SSLEngine} using +- * OpenSSL BIO abstractions. +- *

+- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers +- * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}. +- */ +-public final class OpenSslEngine extends ReferenceCountedOpenSslEngine { +- OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int peerPort) { +- super(context, alloc, peerHost, peerPort, 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 02131b4..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java ++++ /dev/null +@@ -1,35 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-interface OpenSslEngineMap { +- +- /** +- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and +- * return it. +- */ +- ReferenceCountedOpenSslEngine remove(long ssl); +- +- /** +- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}. +- */ +- void add(ReferenceCountedOpenSslEngine engine); +- +- /** +- * Get the {@link OpenSslEngine} for the given {@code ssl} address. +- */ +- ReferenceCountedOpenSslEngine get(long ssl); +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java +deleted file mode 100644 +index 38f6a7f..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java ++++ /dev/null +@@ -1,40 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import javax.net.ssl.X509ExtendedKeyManager; +-import javax.security.auth.x500.X500Principal; +- +-final class OpenSslExtendedKeyMaterialManager extends OpenSslKeyMaterialManager { +- +- private final X509ExtendedKeyManager keyManager; +- +- OpenSslExtendedKeyMaterialManager(X509ExtendedKeyManager keyManager, String password) { +- super(keyManager, password); +- this.keyManager = keyManager; +- } +- +- @Override +- protected String chooseClientAlias(ReferenceCountedOpenSslEngine engine, String[] keyTypes, +- X500Principal[] issuer) { +- return keyManager.chooseEngineClientAlias(keyTypes, issuer, engine); +- } +- +- @Override +- protected String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) { +- return keyManager.chooseEngineServerAlias(type, null, engine); +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java +deleted file mode 100644 +index 2e48e8b..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java ++++ /dev/null +@@ -1,179 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.internal.tcnative.CertificateRequestedCallback; +-import io.netty.internal.tcnative.SSL; +- +-import javax.net.ssl.SSLException; +-import javax.net.ssl.X509KeyManager; +-import javax.security.auth.x500.X500Principal; +-import java.security.PrivateKey; +-import java.security.cert.X509Certificate; +-import java.util.HashMap; +-import java.util.HashSet; +-import java.util.Map; +-import java.util.Set; +- +-import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.freeBio; +-import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO; +- +-/** +- * Manages key material for {@link OpenSslEngine}s and so set the right {@link PrivateKey}s and +- * {@link X509Certificate}s. +- */ +-class OpenSslKeyMaterialManager { +- +- // Code in this class is inspired by code of conscrypts: +- // - https://android.googlesource.com/platform/external/ +- // conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java +- // - https://android.googlesource.com/platform/external/ +- // conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java +- // +- static final String KEY_TYPE_RSA = "RSA"; +- static final String KEY_TYPE_DH_RSA = "DH_RSA"; +- static final String KEY_TYPE_EC = "EC"; +- static final String KEY_TYPE_EC_EC = "EC_EC"; +- static final String KEY_TYPE_EC_RSA = "EC_RSA"; +- +- // key type mappings for types. +- private static final Map KEY_TYPES = new HashMap(); +- static { +- KEY_TYPES.put("RSA", KEY_TYPE_RSA); +- KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA); +- KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA); +- KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC); +- KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA); +- KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC); +- KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA); +- } +- +- private final X509KeyManager keyManager; +- private final String password; +- +- OpenSslKeyMaterialManager(X509KeyManager keyManager, String password) { +- this.keyManager = keyManager; +- this.password = password; +- } +- +- void setKeyMaterial(ReferenceCountedOpenSslEngine engine) throws SSLException { +- long ssl = engine.sslPointer(); +- String[] authMethods = SSL.authenticationMethods(ssl); +- Set aliases = new HashSet(authMethods.length); +- for (String authMethod : authMethods) { +- String type = KEY_TYPES.get(authMethod); +- if (type != null) { +- String alias = chooseServerAlias(engine, type); +- if (alias != null && aliases.add(alias)) { +- setKeyMaterial(ssl, alias); +- } +- } +- } +- } +- +- CertificateRequestedCallback.KeyMaterial keyMaterial(ReferenceCountedOpenSslEngine engine, String[] keyTypes, +- X500Principal[] issuer) throws SSLException { +- String alias = chooseClientAlias(engine, keyTypes, issuer); +- long keyBio = 0; +- long keyCertChainBio = 0; +- long pkey = 0; +- long certChain = 0; +- +- try { +- // TODO: Should we cache these and so not need to do a memory copy all the time ? +- X509Certificate[] certificates = keyManager.getCertificateChain(alias); +- if (certificates == null || certificates.length == 0) { +- return null; +- } +- +- PrivateKey key = keyManager.getPrivateKey(alias); +- keyCertChainBio = toBIO(certificates); +- certChain = SSL.parseX509Chain(keyCertChainBio); +- if (key != null) { +- keyBio = toBIO(key); +- pkey = SSL.parsePrivateKey(keyBio, password); +- } +- CertificateRequestedCallback.KeyMaterial material = new CertificateRequestedCallback.KeyMaterial( +- certChain, pkey); +- +- // Reset to 0 so we do not free these. This is needed as the client certificate callback takes ownership +- // of both the key and the certificate if they are returned from this method, and thus must not +- // be freed here. +- certChain = pkey = 0; +- return material; +- } catch (SSLException e) { +- throw e; +- } catch (Exception e) { +- throw new SSLException(e); +- } finally { +- freeBio(keyBio); +- freeBio(keyCertChainBio); +- SSL.freePrivateKey(pkey); +- SSL.freeX509Chain(certChain); +- } +- } +- +- private void setKeyMaterial(long ssl, String alias) throws SSLException { +- long keyBio = 0; +- long keyCertChainBio = 0; +- long keyCertChainBio2 = 0; +- +- try { +- // TODO: Should we cache these and so not need to do a memory copy all the time ? +- X509Certificate[] certificates = keyManager.getCertificateChain(alias); +- if (certificates == null || certificates.length == 0) { +- return; +- } +- +- PrivateKey key = keyManager.getPrivateKey(alias); +- +- // Only encode one time +- PemEncoded encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, certificates); +- try { +- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); +- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); +- +- if (key != null) { +- keyBio = toBIO(key); +- } +- SSL.setCertificateBio(ssl, keyCertChainBio, keyBio, password); +- +- // We may have more then one cert in the chain so add all of them now. +- SSL.setCertificateChainBio(ssl, keyCertChainBio2, true); +- } finally { +- encoded.release(); +- } +- } catch (SSLException e) { +- throw e; +- } catch (Exception e) { +- throw new SSLException(e); +- } finally { +- freeBio(keyBio); +- freeBio(keyCertChainBio); +- freeBio(keyCertChainBio2); +- } +- } +- +- protected String chooseClientAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine, +- String[] keyTypes, X500Principal[] issuer) { +- return keyManager.chooseClientAlias(keyTypes, issuer, null); +- } +- +- protected String chooseServerAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine, String type) { +- return keyManager.chooseServerAlias(type, null, null); +- } +-} +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 f57434b..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java ++++ /dev/null +@@ -1,373 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.ServerContext; +-import io.netty.internal.tcnative.SSL; +- +-import java.io.File; +-import java.security.PrivateKey; +-import java.security.cert.X509Certificate; +- +-import javax.net.ssl.KeyManager; +-import javax.net.ssl.KeyManagerFactory; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.TrustManager; +-import javax.net.ssl.TrustManagerFactory; +- +-import static io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.newSessionContext; +- +-/** +- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- *

This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers +- * and manually release the native memory see {@link ReferenceCountedOpenSslServerContext}. +- */ +-public final class OpenSslServerContext extends OpenSslContext { +- private final OpenSslServerSessionContext sessionContext; +- private final OpenSslKeyMaterialManager keyMaterialManager; +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException { +- this(certChainFile, keyFile, null); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException { +- this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE, +- ApplicationProtocolConfig.DISABLED, 0, 0); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param apn Provides a means to configure parameters related to application protocol negotiation. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, +- Iterable ciphers, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(certChainFile, keyFile, keyPassword, ciphers, IdentityCipherSuiteFilter.INSTANCE, +- apn, sessionCacheSize, sessionTimeout); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param nextProtocols the application layer protocols to accept, in the order of preference. +- * {@code null} to disable TLS NPN/ALPN extension. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, +- Iterable ciphers, Iterable nextProtocols, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(certChainFile, keyFile, keyPassword, ciphers, +- toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param config Application protocol config. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, +- Iterable ciphers, ApplicationProtocolConfig config, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers, +- toNegotiator(config), sessionCacheSize, sessionTimeout); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param apn Application protocol negotiator. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, +- Iterable ciphers, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, +- ciphers, null, apn, sessionCacheSize, sessionTimeout); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * @param apn Provides a means to configure parameters related to application protocol negotiation. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, +- Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(null, null, certChainFile, keyFile, keyPassword, null, +- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); +- } +- +- /** +- * Creates a new instance. +- * +- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. +- * This provides the certificate collection used for mutual authentication. +- * {@code null} to use the system default +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from clients. +- * {@code null} to use the default or the results of parsing +- * {@code trustCertCollectionFile}. +- * @param keyCertChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s +- * that is used to encrypt data being sent to clients. +- * {@code null} to use the default or the results of parsing +- * {@code keyCertChainFile} and {@code keyFile}. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * Only required if {@code provider} is {@link SslProvider#JDK} +- * @param config Provides a means to configure parameters related to application protocol negotiation. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, +- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory, +- ciphers, cipherFilter, toNegotiator(config), sessionCacheSize, sessionTimeout); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * @param config Application protocol config. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword, +- TrustManagerFactory trustManagerFactory, Iterable ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter, +- toNegotiator(config), sessionCacheSize, sessionTimeout); +- } +- +- /** +- * Creates a new instance. +- * +- * @param certChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * @param apn Application protocol negotiator. +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder}} +- */ +- @Deprecated +- public OpenSslServerContext( +- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, +- Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter, +- apn, sessionCacheSize, sessionTimeout); +- } +- +- /** +- * Creates a new instance. +- * +- * +- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. +- * This provides the certificate collection used for mutual authentication. +- * {@code null} to use the system default +- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s +- * that verifies the certificates sent from clients. +- * {@code null} to use the default or the results of parsing +- * {@code trustCertCollectionFile}. +- * @param keyCertChainFile an X.509 certificate chain file in PEM format +- * @param keyFile a PKCS#8 private key file in PEM format +- * @param keyPassword the password of the {@code keyFile}. +- * {@code null} if it's not password-protected. +- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s +- * that is used to encrypt data being sent to clients. +- * {@code null} to use the default or the results of parsing +- * {@code keyCertChainFile} and {@code keyFile}. +- * @param ciphers the cipher suites to enable, in the order of preference. +- * {@code null} to use the default cipher suites. +- * @param cipherFilter a filter to apply over the supplied list of ciphers +- * Only required if {@code provider} is {@link SslProvider#JDK} +- * @param apn Application Protocol Negotiator object +- * @param sessionCacheSize the size of the cache used for storing SSL session objects. +- * {@code 0} to use the default value. +- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. +- * {@code 0} to use the default value. +- * @deprecated use {@link SslContextBuilder} +- */ +- @Deprecated +- public OpenSslServerContext( +- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, +- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout) throws SSLException { +- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, +- toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), +- keyPassword, keyManagerFactory, ciphers, cipherFilter, +- apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false, false); +- } +- +- OpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp) throws SSLException { +- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, +- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, +- enableOcsp); +- } +- +- @SuppressWarnings("deprecation") +- private OpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, +- clientAuth, protocols, startTls, enableOcsp); +- // Create a new SSL_CTX and configure it. +- boolean success = false; +- try { +- ServerContext context = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, +- keyCertChain, key, keyPassword, keyManagerFactory); +- sessionContext = context.sessionContext; +- keyMaterialManager = context.keyMaterialManager; +- success = true; +- } finally { +- if (!success) { +- release(); +- } +- } +- } +- +- @Override +- public OpenSslServerSessionContext sessionContext() { +- return sessionContext; +- } +- +- @Override +- OpenSslKeyMaterialManager keyMaterialManager() { +- return keyMaterialManager; +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java +deleted file mode 100644 +index 8c92deb..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java ++++ /dev/null +@@ -1,124 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +- +-import java.util.concurrent.locks.Lock; +- +- +-/** +- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side. +- */ +-public final class OpenSslServerSessionContext extends OpenSslSessionContext { +- OpenSslServerSessionContext(ReferenceCountedOpenSslContext context) { +- super(context); +- } +- +- @Override +- public void setSessionTimeout(int seconds) { +- if (seconds < 0) { +- throw new IllegalArgumentException(); +- } +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.setSessionCacheTimeout(context.ctx, seconds); +- } finally { +- writerLock.unlock(); +- } +- } +- +- @Override +- public int getSessionTimeout() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return (int) SSLContext.getSessionCacheTimeout(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- @Override +- public void setSessionCacheSize(int size) { +- if (size < 0) { +- throw new IllegalArgumentException(); +- } +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.setSessionCacheSize(context.ctx, size); +- } finally { +- writerLock.unlock(); +- } +- } +- +- @Override +- public int getSessionCacheSize() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return (int) SSLContext.getSessionCacheSize(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- @Override +- public void setSessionCacheEnabled(boolean enabled) { +- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF; +- +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.setSessionCacheMode(context.ctx, mode); +- } finally { +- writerLock.unlock(); +- } +- } +- +- @Override +- public boolean isSessionCacheEnabled() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER; +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Set the context within which session be reused (server side only) +- * See +- * man SSL_CTX_set_session_id_context +- * +- * @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name +- * of the application and/or the hostname and/or service name +- * @return {@code true} if success, {@code false} otherwise. +- */ +- public boolean setSessionIdContext(byte[] sidCtx) { +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- return SSLContext.setSessionIdContext(context.ctx, sidCtx); +- } finally { +- writerLock.unlock(); +- } +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java +deleted file mode 100644 +index 846a968..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java ++++ /dev/null +@@ -1,137 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.util.internal.ObjectUtil; +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +-import io.netty.internal.tcnative.SessionTicketKey; +- +-import javax.net.ssl.SSLSession; +-import javax.net.ssl.SSLSessionContext; +-import java.util.Arrays; +-import java.util.Enumeration; +-import java.util.NoSuchElementException; +-import java.util.concurrent.locks.Lock; +- +-/** +- * OpenSSL specific {@link SSLSessionContext} implementation. +- */ +-public abstract class OpenSslSessionContext implements SSLSessionContext { +- private static final Enumeration EMPTY = new EmptyEnumeration(); +- +- private final OpenSslSessionStats stats; +- final ReferenceCountedOpenSslContext context; +- +- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent +- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a +- // segfault when the user calls any of the methods here that try to pass the pointer down to the native +- // level. +- OpenSslSessionContext(ReferenceCountedOpenSslContext context) { +- this.context = context; +- stats = new OpenSslSessionStats(context); +- } +- +- @Override +- public SSLSession getSession(byte[] bytes) { +- if (bytes == null) { +- throw new NullPointerException("bytes"); +- } +- return null; +- } +- +- @Override +- public Enumeration getIds() { +- return EMPTY; +- } +- +- /** +- * Sets the SSL session ticket keys of this context. +- * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}. +- */ +- @Deprecated +- public void setTicketKeys(byte[] keys) { +- if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) { +- throw new IllegalArgumentException("keys.length % " + SessionTicketKey.TICKET_KEY_SIZE + " != 0"); +- } +- SessionTicketKey[] tickets = new SessionTicketKey[keys.length / SessionTicketKey.TICKET_KEY_SIZE]; +- for (int i = 0, a = 0; i < tickets.length; i++) { +- byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE); +- a += SessionTicketKey.NAME_SIZE; +- byte[] hmacKey = Arrays.copyOfRange(keys, a, SessionTicketKey.HMAC_KEY_SIZE); +- i += SessionTicketKey.HMAC_KEY_SIZE; +- byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE); +- a += SessionTicketKey.AES_KEY_SIZE; +- tickets[i] = new SessionTicketKey(name, hmacKey, aesKey); +- } +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET); +- SSLContext.setSessionTicketKeys(context.ctx, tickets); +- } finally { +- writerLock.unlock(); +- } +- } +- +- /** +- * Sets the SSL session ticket keys of this context. +- */ +- public void setTicketKeys(OpenSslSessionTicketKey... keys) { +- ObjectUtil.checkNotNull(keys, "keys"); +- SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length]; +- for (int i = 0; i < ticketKeys.length; i++) { +- ticketKeys[i] = keys[i].key; +- } +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET); +- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys); +- } finally { +- writerLock.unlock(); +- } +- } +- +- /** +- * Enable or disable caching of SSL sessions. +- */ +- public abstract void setSessionCacheEnabled(boolean enabled); +- +- /** +- * Return {@code true} if caching of SSL sessions is enabled, {@code false} otherwise. +- */ +- public abstract boolean isSessionCacheEnabled(); +- +- /** +- * Returns the stats of this context. +- */ +- public OpenSslSessionStats stats() { +- return stats; +- } +- +- private static final class EmptyEnumeration implements Enumeration { +- @Override +- public boolean hasMoreElements() { +- return false; +- } +- +- @Override +- public byte[] nextElement() { +- throw new NoSuchElementException(); +- } +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java +deleted file mode 100644 +index f49b95f..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java ++++ /dev/null +@@ -1,253 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-package io.netty.handler.ssl; +- +-import io.netty.internal.tcnative.SSLContext; +- +-import java.util.concurrent.locks.Lock; +- +-/** +- * Stats exposed by an OpenSSL session context. +- * +- * @see SSL_CTX_sess_number +- */ +-public final class OpenSslSessionStats { +- +- private final ReferenceCountedOpenSslContext context; +- +- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent +- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a +- // segfault when the user calls any of the methods here that try to pass the pointer down to the native +- // level. +- OpenSslSessionStats(ReferenceCountedOpenSslContext context) { +- this.context = context; +- } +- +- /** +- * Returns the current number of sessions in the internal session cache. +- */ +- public long number() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionNumber(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of started SSL/TLS handshakes in client mode. +- */ +- public long connect() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionConnect(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of successfully established SSL/TLS sessions in client mode. +- */ +- public long connectGood() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionConnectGood(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of start renegotiations in client mode. +- */ +- public long connectRenegotiate() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionConnectRenegotiate(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of started SSL/TLS handshakes in server mode. +- */ +- public long accept() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionAccept(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of successfully established SSL/TLS sessions in server mode. +- */ +- public long acceptGood() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionAcceptGood(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of start renegotiations in server mode. +- */ +- public long acceptRenegotiate() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionAcceptRenegotiate(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of successfully reused sessions. In client mode, a session set with {@code SSL_set_session} +- * successfully reused is counted as a hit. In server mode, a session successfully retrieved from internal or +- * external cache is counted as a hit. +- */ +- public long hits() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionHits(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of successfully retrieved sessions from the external session cache in server mode. +- */ +- public long cbHits() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionCbHits(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of sessions proposed by clients that were not found in the internal session cache +- * in server mode. +- */ +- public long misses() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionMisses(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of sessions proposed by clients and either found in the internal or external session cache +- * in server mode, but that were invalid due to timeout. These sessions are not included in the {@link #hits()} +- * count. +- */ +- public long timeouts() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTimeouts(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of sessions that were removed because the maximum session cache size was exceeded. +- */ +- public long cacheFull() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionCacheFull(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of times a client presented a ticket that did not match any key in the list. +- */ +- public long ticketKeyFail() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTicketKeyFail(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of times a client did not present a ticket and we issued a new one +- */ +- public long ticketKeyNew() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTicketKeyNew(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of times a client presented a ticket derived from an older key, +- * and we upgraded to the primary key. +- */ +- public long ticketKeyRenew() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTicketKeyRenew(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the number of times a client presented a ticket derived from the primary key. +- */ +- public long ticketKeyResume() { +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTicketKeyResume(context.ctx); +- } finally { +- readerLock.unlock(); +- } +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java +deleted file mode 100644 +index 79f71a6..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java ++++ /dev/null +@@ -1,78 +0,0 @@ +-/* +- * Copyright 2015 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.internal.tcnative.SessionTicketKey; +- +-/** +- * Session Ticket Key +- */ +-public final class OpenSslSessionTicketKey { +- +- /** +- * Size of session ticket key name +- */ +- public static final int NAME_SIZE = SessionTicketKey.NAME_SIZE; +- /** +- * Size of session ticket key HMAC key +- */ +- public static final int HMAC_KEY_SIZE = SessionTicketKey.HMAC_KEY_SIZE; +- /** +- * Size of session ticket key AES key +- */ +- public static final int AES_KEY_SIZE = SessionTicketKey.AES_KEY_SIZE; +- /** +- * Size of session ticker key +- */ +- public static final int TICKET_KEY_SIZE = SessionTicketKey.TICKET_KEY_SIZE; +- +- final SessionTicketKey key; +- +- /** +- * Construct a OpenSslSessionTicketKey. +- * +- * @param name the name of the session ticket key +- * @param hmacKey the HMAC key of the session ticket key +- * @param aesKey the AES key of the session ticket key +- */ +- public OpenSslSessionTicketKey(byte[] name, byte[] hmacKey, byte[] aesKey) { +- key = new SessionTicketKey(name.clone(), hmacKey.clone(), aesKey.clone()); +- } +- +- /** +- * Get name. +- * @return the name of the session ticket key +- */ +- public byte[] name() { +- return key.getName().clone(); +- } +- +- /** +- * Get HMAC key. +- * @return the HMAC key of the session ticket key +- */ +- public byte[] hmacKey() { +- return key.getHmacKey().clone(); +- } +- +- /** +- * Get AES Key. +- * @return the AES key of the session ticket key +- */ +- public byte[] aesKey() { +- return key.getAesKey().clone(); +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java +deleted file mode 100644 +index b213573..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.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: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; +-import io.netty.internal.tcnative.CertificateRequestedCallback; +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +- +-import java.security.KeyStore; +-import java.security.PrivateKey; +-import java.security.cert.X509Certificate; +-import java.util.HashSet; +-import java.util.Set; +- +-import javax.net.ssl.KeyManagerFactory; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.SSLHandshakeException; +-import javax.net.ssl.TrustManagerFactory; +-import javax.net.ssl.X509ExtendedKeyManager; +-import javax.net.ssl.X509ExtendedTrustManager; +-import javax.net.ssl.X509KeyManager; +-import javax.net.ssl.X509TrustManager; +-import javax.security.auth.x500.X500Principal; +- +-/** +- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- *

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

Instances of this class must not be released before any {@link ReferenceCountedOpenSslEngine} +- * which depends upon the instance of this class is released. Otherwise if any method of +- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. +- */ +-public final class ReferenceCountedOpenSslClientContext extends ReferenceCountedOpenSslContext { +- private static final InternalLogger logger = +- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class); +- private final OpenSslSessionContext sessionContext; +- +- ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, +- KeyManagerFactory keyManagerFactory, Iterable ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- String[] protocols, long sessionCacheSize, long sessionTimeout, +- boolean enableOcsp) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, +- ClientAuth.NONE, protocols, false, enableOcsp, true); +- boolean success = false; +- try { +- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, +- keyCertChain, key, keyPassword, keyManagerFactory); +- success = true; +- } finally { +- if (!success) { +- release(); +- } +- } +- } +- +- @Override +- OpenSslKeyMaterialManager keyMaterialManager() { +- return null; +- } +- +- @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) throws SSLException { +- if (key == null && keyCertChain != null || key != null && keyCertChain == null) { +- throw new IllegalArgumentException( +- "Either both keyCertChain and key needs to be null or none of them"); +- } +- try { +- if (!OpenSsl.useKeyManagerFactory()) { +- if (keyManagerFactory != null) { +- throw new IllegalArgumentException( +- "KeyManagerFactory not supported"); +- } +- if (keyCertChain != null/* && key != null*/) { +- setKeyMaterial(ctx, keyCertChain, key, keyPassword); +- } +- } else { +- // javadocs state that keyManagerFactory has precedent over keyCertChain +- if (keyManagerFactory == null && keyCertChain != null) { +- keyManagerFactory = buildKeyManagerFactory( +- keyCertChain, key, keyPassword, keyManagerFactory); +- } +- +- if (keyManagerFactory != null) { +- X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers()); +- OpenSslKeyMaterialManager materialManager = useExtendedKeyManager(keyManager) ? +- new OpenSslExtendedKeyMaterialManager( +- (X509ExtendedKeyManager) keyManager, keyPassword) : +- new OpenSslKeyMaterialManager(keyManager, keyPassword); +- SSLContext.setCertRequestedCallback(ctx, new OpenSslCertificateRequestedCallback( +- engineMap, materialManager)); +- } +- } +- } catch (Exception e) { +- throw new SSLException("failed to set certificate and key", e); +- } +- +- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); +- +- try { +- if (trustCertCollection != null) { +- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory); +- } else if (trustManagerFactory == null) { +- trustManagerFactory = TrustManagerFactory.getInstance( +- TrustManagerFactory.getDefaultAlgorithm()); +- trustManagerFactory.init((KeyStore) null); +- } +- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); +- +- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as +- // otherwise the context can never be collected. This is because the JNI code holds +- // a global reference to the callbacks. +- // +- // See https://github.com/netty/netty/issues/5372 +- +- // Use this to prevent an error when running on java < 7 +- if (useExtendedTrustManager(manager)) { +- SSLContext.setCertVerifyCallback(ctx, +- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager)); +- } else { +- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager)); +- } +- } catch (Exception e) { +- throw new SSLException("unable to setup trustmanager", e); +- } +- return new OpenSslClientSessionContext(thiz); +- } +- +- // No cache is currently supported for client side mode. +- static final class OpenSslClientSessionContext extends OpenSslSessionContext { +- OpenSslClientSessionContext(ReferenceCountedOpenSslContext context) { +- super(context); +- } +- +- @Override +- public void setSessionTimeout(int seconds) { +- if (seconds < 0) { +- throw new IllegalArgumentException(); +- } +- } +- +- @Override +- public int getSessionTimeout() { +- return 0; +- } +- +- @Override +- public void setSessionCacheSize(int size) { +- if (size < 0) { +- throw new IllegalArgumentException(); +- } +- } +- +- @Override +- public int getSessionCacheSize() { +- return 0; +- } +- +- @Override +- public void setSessionCacheEnabled(boolean enabled) { +- // ignored +- } +- +- @Override +- public boolean isSessionCacheEnabled() { +- return false; +- } +- } +- +- 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); +- } +- } +- +- 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 OpenSslCertificateRequestedCallback implements CertificateRequestedCallback { +- private final OpenSslEngineMap engineMap; +- private final OpenSslKeyMaterialManager keyManagerHolder; +- +- OpenSslCertificateRequestedCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) { +- this.engineMap = engineMap; +- this.keyManagerHolder = keyManagerHolder; +- } +- +- @Override +- public KeyMaterial requested(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) { +- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); +- try { +- final Set keyTypesSet = supportedClientKeyTypes(keyTypeBytes); +- final String[] keyTypes = keyTypesSet.toArray(new String[keyTypesSet.size()]); +- final X500Principal[] issuers; +- if (asn1DerEncodedPrincipals == null) { +- issuers = null; +- } else { +- issuers = new X500Principal[asn1DerEncodedPrincipals.length]; +- for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) { +- issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]); +- } +- } +- return keyManagerHolder.keyMaterial(engine, keyTypes, issuers); +- } catch (Throwable cause) { +- logger.debug("request of key failed", cause); +- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem"); +- e.initCause(cause); +- engine.handshakeException = e; +- return null; +- } +- } +- +- /** +- * Gets the supported key types for client certificates. +- * +- * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server. +- * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml. +- * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and +- * {@code X509ExtendedKeyManager.chooseEngineClientAlias}. +- */ +- private static Set supportedClientKeyTypes(byte[] clientCertificateTypes) { +- Set result = new HashSet(clientCertificateTypes.length); +- for (byte keyTypeCode : clientCertificateTypes) { +- String keyType = clientKeyType(keyTypeCode); +- if (keyType == null) { +- // Unsupported client key type -- ignore +- continue; +- } +- result.add(keyType); +- } +- return result; +- } +- +- private static String clientKeyType(byte clientCertificateType) { +- // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml +- switch (clientCertificateType) { +- case CertificateRequestedCallback.TLS_CT_RSA_SIGN: +- return OpenSslKeyMaterialManager.KEY_TYPE_RSA; // RFC rsa_sign +- case CertificateRequestedCallback.TLS_CT_RSA_FIXED_DH: +- return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh +- case CertificateRequestedCallback.TLS_CT_ECDSA_SIGN: +- return OpenSslKeyMaterialManager.KEY_TYPE_EC; // RFC ecdsa_sign +- case CertificateRequestedCallback.TLS_CT_RSA_FIXED_ECDH: +- return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh +- case CertificateRequestedCallback.TLS_CT_ECDSA_FIXED_ECDH: +- return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh +- default: +- return null; +- } +- } +- } +-} +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 ee049ab..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java ++++ /dev/null +@@ -1,867 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.buffer.ByteBuf; +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.internal.tcnative.CertificateVerifier; +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +-import io.netty.util.AbstractReferenceCounted; +-import io.netty.util.ReferenceCounted; +-import io.netty.util.ResourceLeakDetector; +-import io.netty.util.ResourceLeakDetectorFactory; +-import io.netty.util.ResourceLeakTracker; +-import io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.StringUtil; +-import io.netty.util.internal.SystemPropertyUtil; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; +- +-import java.security.AccessController; +-import java.security.PrivateKey; +-import java.security.PrivilegedAction; +-import java.security.cert.CertPathValidatorException; +-import java.security.cert.Certificate; +-import java.security.cert.CertificateExpiredException; +-import java.security.cert.CertificateNotYetValidException; +-import java.security.cert.CertificateRevokedException; +-import java.security.cert.X509Certificate; +-import java.util.ArrayList; +-import java.util.Arrays; +-import java.util.Collections; +-import java.util.List; +-import java.util.Map; +- +-import java.util.concurrent.locks.Lock; +-import java.util.concurrent.locks.ReadWriteLock; +-import java.util.concurrent.locks.ReentrantReadWriteLock; +-import javax.net.ssl.KeyManager; +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.SSLHandshakeException; +-import javax.net.ssl.TrustManager; +-import javax.net.ssl.X509ExtendedKeyManager; +-import javax.net.ssl.X509ExtendedTrustManager; +-import javax.net.ssl.X509KeyManager; +-import javax.net.ssl.X509TrustManager; +- +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero; +- +-/** +- * An implementation of {@link SslContext} which works with libraries that support the +- * OpenSsl C library API. +- *

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

Instances of this class must not be released before any {@link ReferenceCountedOpenSslEngine} +- * which depends upon the instance of this class is released. Otherwise if any method of +- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. +- */ +-public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted { +- private static final InternalLogger logger = +- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class); +- /** +- * To make it easier for users to replace JDK implementation with OpenSsl version we also use +- * {@code jdk.tls.rejectClientInitiatedRenegotiation} to allow disabling client initiated renegotiation. +- * Java8+ uses this system property as well. +- *

+- * See also +- * Significant SSL/TLS improvements in Java 8 +- */ +- private static final boolean JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION = +- AccessController.doPrivileged(new PrivilegedAction() { +- @Override +- public Boolean run() { +- return SystemPropertyUtil.getBoolean("jdk.tls.rejectClientInitiatedRenegotiation", false); +- } +- }); +- +- private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE = +- AccessController.doPrivileged(new PrivilegedAction() { +- @Override +- public Integer run() { +- return Math.max(1, +- SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize", +- 2048)); +- } +- }); +- +- private static final List DEFAULT_CIPHERS; +- private static final Integer DH_KEY_LENGTH; +- private static final ResourceLeakDetector leakDetector = +- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class); +- +- // TODO: Maybe make configurable ? +- protected static final int VERIFY_DEPTH = 10; +- +- /** +- * The OpenSSL SSL_CTX object. +- * +- * {@link #ctxLock} must be hold while using ctx! +- */ +- protected long ctx; +- private final List unmodifiableCiphers; +- private final long sessionCacheSize; +- private final long sessionTimeout; +- private final OpenSslApplicationProtocolNegotiator apn; +- private final int mode; +- +- // Reference Counting +- private final ResourceLeakTracker leak; +- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { +- @Override +- public ReferenceCounted touch(Object hint) { +- if (leak != null) { +- leak.record(hint); +- } +- +- return ReferenceCountedOpenSslContext.this; +- } +- +- @Override +- protected void deallocate() { +- destroy(); +- if (leak != null) { +- boolean closed = leak.close(ReferenceCountedOpenSslContext.this); +- assert closed; +- } +- } +- }; +- +- final Certificate[] keyCertChain; +- final ClientAuth clientAuth; +- final String[] protocols; +- final boolean enableOcsp; +- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap(); +- final ReadWriteLock ctxLock = new ReentrantReadWriteLock(); +- +- private volatile boolean rejectRemoteInitiatedRenegotiation; +- private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE; +- +- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR = +- new OpenSslApplicationProtocolNegotiator() { +- @Override +- public ApplicationProtocolConfig.Protocol protocol() { +- return ApplicationProtocolConfig.Protocol.NONE; +- } +- +- @Override +- public List protocols() { +- return Collections.emptyList(); +- } +- +- @Override +- public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() { +- return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL; +- } +- +- @Override +- public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() { +- return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT; +- } +- }; +- +- static { +- List ciphers = new ArrayList(); +- // XXX: Make sure to sync this list with JdkSslEngineFactory. +- Collections.addAll( +- ciphers, +- "ECDHE-ECDSA-AES256-GCM-SHA384", +- "ECDHE-ECDSA-AES128-GCM-SHA256", +- "ECDHE-RSA-AES128-GCM-SHA256", +- "ECDHE-RSA-AES128-SHA", +- "ECDHE-RSA-AES256-SHA", +- "AES128-GCM-SHA256", +- "AES128-SHA", +- "AES256-SHA"); +- DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers); +- +- if (logger.isDebugEnabled()) { +- logger.debug("Default cipher suite (OpenSSL): " + ciphers); +- } +- +- Integer dhLen = null; +- +- try { +- String dhKeySize = AccessController.doPrivileged(new PrivilegedAction() { +- @Override +- public String run() { +- return SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize"); +- } +- }); +- if (dhKeySize != null) { +- try { +- dhLen = Integer.valueOf(dhKeySize); +- } catch (NumberFormatException e) { +- logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: " +- + dhKeySize); +- } +- } +- } catch (Throwable ignore) { +- // ignore +- } +- DH_KEY_LENGTH = dhLen; +- } +- +- ReferenceCountedOpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, +- ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout, +- int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols, +- boolean startTls, boolean enableOcsp, boolean leakDetection) throws SSLException { +- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain, +- clientAuth, protocols, startTls, enableOcsp, leakDetection); +- } +- +- ReferenceCountedOpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, +- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, +- long sessionTimeout, int mode, Certificate[] keyCertChain, +- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp, +- boolean leakDetection) throws SSLException { +- super(startTls); +- +- OpenSsl.ensureAvailability(); +- +- if (enableOcsp && !OpenSsl.isOcspSupported()) { +- throw new IllegalStateException("OCSP is not supported."); +- } +- +- if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) { +- throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT"); +- } +- leak = leakDetection ? leakDetector.track(this) : null; +- this.mode = mode; +- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE; +- this.protocols = protocols; +- this.enableOcsp = enableOcsp; +- +- if (mode == SSL.SSL_MODE_SERVER) { +- rejectRemoteInitiatedRenegotiation = +- JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION; +- } +- this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone(); +- final List convertedCiphers; +- if (ciphers == null) { +- convertedCiphers = null; +- } else { +- convertedCiphers = new ArrayList(); +- for (String c : ciphers) { +- if (c == null) { +- break; +- } +- +- String converted = CipherSuiteConverter.toOpenSsl(c); +- if (converted != null) { +- c = converted; +- } +- convertedCiphers.add(c); +- } +- } +- +- unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites( +- convertedCiphers, DEFAULT_CIPHERS, OpenSsl.availableOpenSslCipherSuites())); +- +- this.apn = checkNotNull(apn, "apn"); +- +- // Create a new SSL_CTX and configure it. +- boolean success = false; +- try { +- try { +- ctx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, mode); +- } catch (Exception e) { +- throw new SSLException("failed to create an SSL_CTX", e); +- } +- +- SSLContext.setOptions(ctx, SSLContext.getOptions(ctx) | +- SSL.SSL_OP_NO_SSLv2 | +- SSL.SSL_OP_NO_SSLv3 | +- 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); +- +- // 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 the ciphers that are permitted to negotiate. */ +- try { +- SSLContext.setCipherSuite(ctx, CipherSuiteConverter.toOpenSsl(unmodifiableCiphers)); +- } catch (SSLException e) { +- throw e; +- } catch (Exception e) { +- throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e); +- } +- +- List nextProtoList = apn.protocols(); +- /* Set next protocols for next protocol negotiation extension, if specified */ +- if (!nextProtoList.isEmpty()) { +- String[] appProtocols = nextProtoList.toArray(new String[nextProtoList.size()]); +- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior()); +- +- switch (apn.protocol()) { +- case NPN: +- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior); +- break; +- case ALPN: +- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior); +- break; +- case NPN_AND_ALPN: +- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior); +- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior); +- break; +- default: +- throw new Error(); +- } +- } +- +- /* Set session cache size, if specified */ +- if (sessionCacheSize > 0) { +- this.sessionCacheSize = sessionCacheSize; +- SSLContext.setSessionCacheSize(ctx, sessionCacheSize); +- } else { +- // Get the default session cache size using SSLContext.setSessionCacheSize() +- this.sessionCacheSize = sessionCacheSize = SSLContext.setSessionCacheSize(ctx, 20480); +- // Revert the session cache size to the default value. +- SSLContext.setSessionCacheSize(ctx, sessionCacheSize); +- } +- +- /* Set session timeout, if specified */ +- if (sessionTimeout > 0) { +- this.sessionTimeout = sessionTimeout; +- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout); +- } else { +- // Get the default session timeout using SSLContext.setSessionCacheTimeout() +- this.sessionTimeout = sessionTimeout = SSLContext.setSessionCacheTimeout(ctx, 300); +- // Revert the session timeout to the default value. +- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout); +- } +- +- if (enableOcsp) { +- SSLContext.enableOcsp(ctx, isClient()); +- } +- success = true; +- } finally { +- if (!success) { +- release(); +- } +- } +- } +- +- private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) { +- switch (behavior) { +- case NO_ADVERTISE: +- return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE; +- case CHOOSE_MY_LAST_PROTOCOL: +- return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL; +- default: +- throw new Error(); +- } +- } +- +- @Override +- public final List cipherSuites() { +- return unmodifiableCiphers; +- } +- +- @Override +- public final long sessionCacheSize() { +- return sessionCacheSize; +- } +- +- @Override +- public final long sessionTimeout() { +- return sessionTimeout; +- } +- +- @Override +- public ApplicationProtocolNegotiator applicationProtocolNegotiator() { +- return apn; +- } +- +- @Override +- public final boolean isClient() { +- return mode == SSL.SSL_MODE_CLIENT; +- } +- +- @Override +- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) { +- return newEngine0(alloc, peerHost, peerPort); +- } +- +- SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) { +- return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, true); +- } +- +- abstract OpenSslKeyMaterialManager keyMaterialManager(); +- +- /** +- * 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() { +- Lock readerLock = ctxLock.readLock(); +- readerLock.lock(); +- try { +- return ctx; +- } finally { +- readerLock.unlock(); +- } +- } +- +- /** +- * Returns the stats of this context. +- * +- * @deprecated use {@link #sessionContext#stats()} +- */ +- @Deprecated +- public final OpenSslSessionStats stats() { +- return sessionContext().stats(); +- } +- +- /** +- * 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. +- */ +- public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) { +- this.rejectRemoteInitiatedRenegotiation = rejectRemoteInitiatedRenegotiation; +- } +- +- /** +- * Returns if remote initiated renegotiation is supported or not. +- */ +- public boolean getRejectRemoteInitiatedRenegotiation() { +- return rejectRemoteInitiatedRenegotiation; +- } +- +- /** +- * 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 ctx; +- } finally { +- readerLock.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; +- } +- } finally { +- writerLock.unlock(); +- } +- } +- +- protected static X509Certificate[] certificates(byte[][] chain) { +- X509Certificate[] peerCerts = new X509Certificate[chain.length]; +- for (int i = 0; i < peerCerts.length; i++) { +- peerCerts[i] = new OpenSslX509Certificate(chain[i]); +- } +- return peerCerts; +- } +- +- protected static X509TrustManager chooseTrustManager(TrustManager[] managers) { +- for (TrustManager m : managers) { +- if (m instanceof X509TrustManager) { +- 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 +- */ +- static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) { +- if (config == null) { +- return NONE_PROTOCOL_NEGOTIATOR; +- } +- +- switch (config.protocol()) { +- case NONE: +- return NONE_PROTOCOL_NEGOTIATOR; +- case ALPN: +- case NPN: +- case NPN_AND_ALPN: +- switch (config.selectedListenerFailureBehavior()) { +- case CHOOSE_MY_LAST_PROTOCOL: +- case ACCEPT: +- switch (config.selectorFailureBehavior()) { +- case CHOOSE_MY_LAST_PROTOCOL: +- case NO_ADVERTISE: +- return new OpenSslDefaultApplicationProtocolNegotiator( +- config); +- default: +- throw new UnsupportedOperationException( +- new StringBuilder("OpenSSL provider does not support ") +- .append(config.selectorFailureBehavior()) +- .append(" behavior").toString()); +- } +- default: +- throw new UnsupportedOperationException( +- new StringBuilder("OpenSSL provider does not support ") +- .append(config.selectedListenerFailureBehavior()) +- .append(" behavior").toString()); +- } +- default: +- throw new Error(); +- } +- } +- +- static boolean useExtendedTrustManager(X509TrustManager trustManager) { +- return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager; +- } +- +- static boolean useExtendedKeyManager(X509KeyManager keyManager) { +- return PlatformDependent.javaVersion() >= 7 && keyManager instanceof X509ExtendedKeyManager; +- } +- +- @Override +- public final int refCnt() { +- return refCnt.refCnt(); +- } +- +- @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) { +- X509Certificate[] peerCerts = certificates(chain); +- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); +- try { +- verify(engine, peerCerts, auth); +- return CertificateVerifier.X509_V_OK; +- } catch (Throwable cause) { +- logger.debug("verification of certificate failed", cause); +- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem"); +- e.initCause(cause); +- engine.handshakeException = e; +- +- // Try to extract the correct error code that should be used. +- if (cause instanceof OpenSslCertificateException) { +- // This will never return a negative error code as its validated when constructing the +- // OpenSslCertificateException. +- return ((OpenSslCertificateException) cause).errorCode(); +- } +- if (cause instanceof CertificateExpiredException) { +- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED; +- } +- if (cause instanceof CertificateNotYetValidException) { +- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID; +- } +- if (PlatformDependent.javaVersion() >= 7) { +- if (cause instanceof CertificateRevokedException) { +- return CertificateVerifier.X509_V_ERR_CERT_REVOKED; +- } +- +- // 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(); +- } +- } +- +- // Could not detect a specific error code to use, so fallback to a default code. +- return CertificateVerifier.X509_V_ERR_UNSPECIFIED; +- } +- } +- +- abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, +- String auth) throws Exception; +- } +- +- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap { +- private final Map engines = PlatformDependent.newConcurrentHashMap(); +- +- @Override +- public ReferenceCountedOpenSslEngine remove(long ssl) { +- return engines.remove(ssl); +- } +- +- @Override +- public void add(ReferenceCountedOpenSslEngine engine) { +- engines.put(engine.sslPointer(), engine); +- } +- +- @Override +- public ReferenceCountedOpenSslEngine get(long ssl) { +- return engines.get(ssl); +- } +- } +- +- static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword) +- throws SSLException { +- /* Load the certificate file and private key. */ +- long keyBio = 0; +- long keyCertChainBio = 0; +- long keyCertChainBio2 = 0; +- PemEncoded encoded = null; +- try { +- // Only encode one time +- encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain); +- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); +- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); +- +- if (key != null) { +- keyBio = toBIO(key); +- } +- +- SSLContext.setCertificateBio( +- ctx, keyCertChainBio, keyBio, +- keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword); +- // We may have more then one cert in the chain so add all of them now. +- SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true); +- } catch (SSLException e) { +- throw e; +- } catch (Exception e) { +- throw new SSLException("failed to set certificate and key", e); +- } finally { +- freeBio(keyBio); +- freeBio(keyCertChainBio); +- freeBio(keyCertChainBio2); +- if (encoded != null) { +- encoded.release(); +- } +- } +- } +- +- static void freeBio(long bio) { +- if (bio != 0) { +- SSL.freeBIO(bio); +- } +- } +- +- /** +- * Return the pointer to a in-memory BIO +- * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}. +- */ +- static long toBIO(PrivateKey key) throws Exception { +- if (key == null) { +- return 0; +- } +- +- ByteBufAllocator allocator = ByteBufAllocator.DEFAULT; +- PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key); +- try { +- return toBIO(allocator, pem.retain()); +- } finally { +- pem.release(); +- } +- } +- +- /** +- * Return the pointer to a in-memory BIO +- * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}. +- */ +- static long toBIO(X509Certificate... certChain) throws Exception { +- if (certChain == null) { +- return 0; +- } +- +- if (certChain.length == 0) { +- throw new IllegalArgumentException("certChain can't be empty"); +- } +- +- ByteBufAllocator allocator = ByteBufAllocator.DEFAULT; +- 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(); +- } +- } +-} +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 27460c7..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java ++++ /dev/null +@@ -1,2037 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.buffer.ByteBuf; +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.internal.tcnative.Buffer; +-import io.netty.internal.tcnative.SSL; +-import io.netty.util.AbstractReferenceCounted; +-import io.netty.util.ReferenceCounted; +-import io.netty.util.ResourceLeakDetector; +-import io.netty.util.ResourceLeakDetectorFactory; +-import io.netty.util.ResourceLeakTracker; +-import io.netty.util.internal.EmptyArrays; +-import io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.StringUtil; +-import io.netty.util.internal.ThrowableUtil; +-import io.netty.util.internal.UnstableApi; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; +- +-import 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.HashMap; +-import java.util.List; +-import java.util.Map; +-import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +- +-import java.util.concurrent.locks.Lock; +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLEngineResult; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.SSLHandshakeException; +-import javax.net.ssl.SSLParameters; +-import javax.net.ssl.SSLPeerUnverifiedException; +-import javax.net.ssl.SSLSession; +-import javax.net.ssl.SSLSessionBindingEvent; +-import javax.net.ssl.SSLSessionBindingListener; +-import javax.net.ssl.SSLSessionContext; +-import javax.security.cert.X509Certificate; +- +-import static io.netty.handler.ssl.OpenSsl.memoryAddress; +-import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH; +-import static io.netty.util.internal.EmptyArrays.EMPTY_CERTIFICATES; +-import static io.netty.util.internal.EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES; +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import static java.lang.Math.min; +-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED; +-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP; +-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP; +-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; +-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW; +-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW; +-import static javax.net.ssl.SSLEngineResult.Status.CLOSED; +-import static javax.net.ssl.SSLEngineResult.Status.OK; +- +-/** +- * Implements a {@link SSLEngine} using +- * OpenSSL BIO abstractions. +- *

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

Instances of this class must be released before the {@link ReferenceCountedOpenSslContext} +- * the instance depends upon are released. Otherwise if any method of this class is called which uses the +- * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash. +- */ +-public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted { +- +- private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class); +- +- private static final SSLException BEGIN_HANDSHAKE_ENGINE_CLOSED = ThrowableUtil.unknownStackTrace( +- new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "beginHandshake()"); +- private static final SSLException HANDSHAKE_ENGINE_CLOSED = ThrowableUtil.unknownStackTrace( +- new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "handshake()"); +- private static final SSLException RENEGOTIATION_UNSUPPORTED = ThrowableUtil.unknownStackTrace( +- new SSLException("renegotiation unsupported"), ReferenceCountedOpenSslEngine.class, "beginHandshake()"); +- private static final ResourceLeakDetector leakDetector = +- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class); +- /** +- * The flags argument is usually 0. +- */ +- private static final int DEFAULT_HOSTNAME_VALIDATION_FLAGS = 0; +- +- static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14 +- +- /** +- * This is the maximum overhead when encrypting plaintext as defined by +- * rfc5264, +- * rfc5289 and openssl implementation itself. +- * +- * Please note that we use a padding of 16 here as openssl uses PKC#5 which uses 16 bytes while the spec itself +- * allow up to 255 bytes. 16 bytes is the max for PKC#5 (which handles it the same way as PKC#7) as we use a block +- * size of 16. See rfc5652#section-6.3. +- * +- * TLS Header (5) + 16 (IV) + 48 (MAC) + 1 (Padding_length field) + 15 (Padding) + 1 (ContentType) + +- * 2 (ProtocolVersion) + 2 (Length) +- * +- * TODO: We may need to review this calculation once TLS 1.3 becomes available. +- */ +- static final int MAX_TLS_RECORD_OVERHEAD_LENGTH = SSL_RECORD_HEADER_LENGTH + 16 + 48 + 1 + 15 + 1 + 2 + 2; +- +- static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_PLAINTEXT_LENGTH + MAX_TLS_RECORD_OVERHEAD_LENGTH; +- +- private static final AtomicIntegerFieldUpdater DESTROYED_UPDATER = +- AtomicIntegerFieldUpdater.newUpdater(ReferenceCountedOpenSslEngine.class, "destroyed"); +- +- private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL"; +- private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0); +- private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0); +- private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0); +- private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0); +- private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0); +- +- // OpenSSL state +- private long ssl; +- private long networkBIO; +- private boolean certificateSet; +- +- 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 renegotiationPending; +- private boolean receivedShutdown; +- private volatile int destroyed; +- +- // Reference Counting +- private final ResourceLeakTracker leak; +- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { +- @Override +- public ReferenceCounted touch(Object hint) { +- if (leak != null) { +- leak.record(hint); +- } +- +- return ReferenceCountedOpenSslEngine.this; +- } +- +- @Override +- protected void deallocate() { +- shutdown(); +- if (leak != null) { +- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this); +- assert closed; +- } +- } +- }; +- +- 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 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; +- +- private final boolean clientMode; +- private final ByteBufAllocator alloc; +- private final OpenSslEngineMap engineMap; +- private final OpenSslApplicationProtocolNegotiator apn; +- private final boolean rejectRemoteInitiatedRenegotiation; +- private final OpenSslSession session; +- private final Certificate[] localCerts; +- private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1]; +- private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1]; +- private final OpenSslKeyMaterialManager keyMaterialManager; +- private final boolean enableOcsp; +- +- // This is package-private as we set it from OpenSslContext if an exception is thrown during +- // the verification step. +- SSLHandshakeException handshakeException; +- +- /** +- * Create a new instance. +- * @param context Reference count release responsibility is not transferred! The callee still owns this object. +- * @param alloc The allocator to use. +- * @param peerHost The peer host name. +- * @param peerPort The peer port. +- * @param leakDetection {@code true} to enable leak detection of this object. +- */ +- ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context, ByteBufAllocator alloc, String peerHost, +- int peerPort, boolean leakDetection) { +- super(peerHost, peerPort); +- OpenSsl.ensureAvailability(); +- leak = leakDetection ? leakDetector.track(this) : null; +- this.alloc = checkNotNull(alloc, "alloc"); +- apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator(); +- session = new OpenSslSession(context.sessionContext()); +- clientMode = context.isClient(); +- engineMap = context.engineMap; +- rejectRemoteInitiatedRenegotiation = context.getRejectRemoteInitiatedRenegotiation(); +- localCerts = context.keyCertChain; +- keyMaterialManager = context.keyMaterialManager(); +- enableOcsp = context.enableOcsp; +- +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- ssl = SSL.newSSL(context.ctx, !context.isClient()); +- } finally { +- readerLock.unlock(); +- } +- try { +- networkBIO = SSL.bioNewByteBuffer(ssl, context.getBioNonApplicationBufferSize()); +- +- // Set the client auth mode, this needs to be done via setClientAuth(...) method so we actually call the +- // needed JNI methods. +- setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth); +- +- if (context.protocols != null) { +- setEnabledProtocols(context.protocols); +- } +- +- // Use SNI if peerHost was specified +- // See https://github.com/netty/netty/issues/4746 +- if (clientMode && peerHost != null) { +- SSL.setTlsExtHostName(ssl, peerHost); +- } +- +- if (enableOcsp) { +- SSL.enableOcsp(ssl); +- } +- } catch (Throwable cause) { +- SSL.freeSSL(ssl); +- PlatformDependent.throwException(cause); +- } +- } +- +- /** +- * 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) { +- 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) { +- return SSL.getOcspResponse(ssl); +- } +- } +- +- @Override +- public final int refCnt() { +- return refCnt.refCnt(); +- } +- +- @Override +- public final ReferenceCounted retain() { +- refCnt.retain(); +- return this; +- } +- +- @Override +- public final ReferenceCounted retain(int increment) { +- refCnt.retain(increment); +- return this; +- } +- +- @Override +- public final ReferenceCounted touch() { +- refCnt.touch(); +- return this; +- } +- +- @Override +- public final ReferenceCounted touch(Object hint) { +- refCnt.touch(hint); +- return this; +- } +- +- @Override +- public final boolean release() { +- return refCnt.release(); +- } +- +- @Override +- public final boolean release(int decrement) { +- return refCnt.release(decrement); +- } +- +- @Override +- public final synchronized SSLSession getHandshakeSession() { +- // Javadocs state return value should be: +- // null if this instance is not currently handshaking, or if the current handshake has not +- // progressed far enough to create a basic SSLSession. Otherwise, this method returns the +- // SSLSession currently being negotiated. +- switch(handshakeState) { +- case NOT_STARTED: +- case FINISHED: +- return null; +- default: +- return session; +- } +- } +- +- /** +- * Returns the pointer to the {@code SSL} object for this {@link ReferenceCountedOpenSslEngine}. +- * Be aware that it is freed as soon as the {@link #release()} or {@link #shutdown()} methods are called. +- * At this point {@code 0} will be returned. +- */ +- public final synchronized long sslPointer() { +- return ssl; +- } +- +- /** +- * Destroys this engine. +- */ +- public final synchronized void shutdown() { +- if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) { +- 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, Buffer.address(src) + pos, len); +- if (sslWrote > 0) { +- src.position(pos + sslWrote); +- } +- } else { +- ByteBuf buf = alloc.directBuffer(len); +- try { +- src.limit(pos + len); +- +- buf.setBytes(0, src); +- src.limit(limit); +- +- sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len); +- if (sslWrote > 0) { +- src.position(pos + sslWrote); +- } else { +- src.position(pos); +- } +- } finally { +- buf.release(); +- } +- } +- return sslWrote; +- } +- +- /** +- * Write encrypted data to the OpenSSL network BIO. +- */ +- private ByteBuf writeEncryptedData(final ByteBuffer src, int len) { +- final int pos = src.position(); +- if (src.isDirect()) { +- SSL.bioSetByteBuffer(networkBIO, Buffer.address(src) + pos, len, false); +- } else { +- final ByteBuf buf = alloc.directBuffer(len); +- try { +- final int limit = src.limit(); +- src.limit(pos + len); +- buf.writeBytes(src); +- // Restore the original position and limit because we don't want to consume from `src`. +- src.position(pos); +- src.limit(limit); +- +- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false); +- return buf; +- } catch (Throwable cause) { +- buf.release(); +- PlatformDependent.throwException(cause); +- } +- } +- return null; +- } +- +- /** +- * Read plaintext data from the OpenSSL internal BIO +- */ +- private int readPlaintextData(final ByteBuffer dst) { +- final int sslRead; +- final int pos = dst.position(); +- if (dst.isDirect()) { +- sslRead = SSL.readFromSSL(ssl, Buffer.address(dst) + pos, dst.limit() - pos); +- if (sslRead > 0) { +- dst.position(pos + sslRead); +- } +- } else { +- final int limit = dst.limit(); +- final int len = min(MAX_ENCRYPTED_PACKET_LENGTH, limit - pos); +- final ByteBuf buf = alloc.directBuffer(len); +- try { +- sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len); +- if (sslRead > 0) { +- dst.limit(pos + sslRead); +- buf.getBytes(buf.readerIndex(), dst); +- dst.limit(limit); +- } +- } finally { +- buf.release(); +- } +- } +- +- return sslRead; +- } +- +- @Override +- public final SSLEngineResult wrap( +- final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst) throws SSLException { +- // Throw required runtime exceptions +- if (srcs == null) { +- throw new IllegalArgumentException("srcs is null"); +- } +- if (dst == null) { +- throw new IllegalArgumentException("dst is null"); +- } +- +- 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, Buffer.address(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); +- +- // Explicit use outboundClosed as we want to drain any bytes that are still present. +- if (outboundClosed) { +- // There is something left to drain. +- // See https://github.com/netty/netty/issues/6260 +- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); +- if (bytesProduced <= 0) { +- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0); +- } +- // It is possible when the outbound was closed there was not enough room in the non-application +- // buffers to hold the close_notify. We should keep trying to close until we consume all the data +- // OpenSSL can give us. +- if (!doSSLShutdown()) { +- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, bytesProduced); +- } +- 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 (bytesProduced > 0 && handshakeException != null) { +- // TODO(scott): It is possible that when the handshake failed there was not enough room in the +- // non-application buffers to hold the alert. We should get all the data before progressing on. +- // However I'm not aware of a way to do this with the OpenSSL APIs. +- // See https://github.com/netty/netty/issues/6385. +- +- // We produced / consumed some data during the handshake, signal back to the caller. +- // If there is a handshake exception and we have produced data, we should send the data before +- // we allow handshake() to throw the handshake exception. +- return newResult(NEED_WRAP, 0, bytesProduced); +- } +- +- status = handshake(); +- +- if (renegotiationPending && status == FINISHED) { +- // If renegotiationPending is true that means when we attempted to start renegotiation +- // the BIO buffer didn't have enough space to hold the HelloRequest which prompts the +- // client to initiate a renegotiation. At this point the HelloRequest has been written +- // so we can actually start the handshake process. +- renegotiationPending = false; +- SSL.setState(ssl, SSL.SSL_ST_ACCEPT); +- handshakeState = HandshakeState.STARTED_EXPLICITLY; +- status = handshake(); +- } +- +- // 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 (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); +- } +- } +- +- int srcsLen = 0; +- final int endOffset = offset + length; +- for (int i = offset; i < endOffset; ++i) { +- final ByteBuffer src = srcs[i]; +- if (src == null) { +- throw new IllegalArgumentException("srcs[" + i + "] is null"); +- } +- if (srcsLen == MAX_PLAINTEXT_LENGTH) { +- continue; +- } +- +- 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; +- } +- } +- +- // we will only produce a single TLS packet, and we don't aggregate src buffers, +- // so we always fix the number of buffers to 1 when checking if the dst buffer is large enough. +- if (dst.remaining() < calculateOutNetBufSize(srcsLen, 1)) { +- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0); +- } +- +- // There was no pending data in the network BIO -- encrypt any application data +- int bytesConsumed = 0; +- // Flush any data that may have been written implicitly by OpenSSL in case a shutdown/alert occurs. +- bytesProduced = SSL.bioFlushByteBuffer(networkBIO); +- for (; offset < endOffset; ++offset) { +- final ByteBuffer src = srcs[offset]; +- final int remaining = src.remaining(); +- if (remaining == 0) { +- continue; +- } +- +- // Write plaintext application data to the SSL engine +- int bytesWritten = writePlaintextData(src, min(remaining, MAX_PLAINTEXT_LENGTH - bytesConsumed)); +- +- if (bytesWritten > 0) { +- bytesConsumed += bytesWritten; +- +- // Determine how much encrypted data was generated: +- final int pendingNow = SSL.bioLengthByteBuffer(networkBIO); +- bytesProduced += bioLengthBefore - pendingNow; +- bioLengthBefore = pendingNow; +- +- 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." +- // +- // So we attempt to drain the BIO buffer below, but if there is no data this condition +- // is undefined and we assume their is a fatal error with the openssl engine and close. +- // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html +- return newResult(NEED_WRAP, bytesConsumed, bytesProduced); +- } else { +- // Everything else is considered as error +- throw shutdownWithError("SSL_write"); +- } +- } +- } +- 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); +- } +- return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced); +- } +- +- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus hs, +- int bytesConsumed, int bytesProduced) throws SSLException { +- return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED), +- bytesConsumed, bytesProduced); +- } +- +- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status, +- SSLEngineResult.HandshakeStatus hs, +- int bytesConsumed, int bytesProduced) throws SSLException { +- return newResult(status, mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED), +- bytesConsumed, bytesProduced); +- } +- +- /** +- * Log the error, shutdown the engine and throw an exception. +- */ +- private SSLException shutdownWithError(String operations) { +- String err = SSL.getLastError(); +- return shutdownWithError(operations, err); +- } +- +- private SSLException shutdownWithError(String operation, String err) { +- if (logger.isDebugEnabled()) { +- logger.debug("{} failed: OpenSSL error: {}", operation, err); +- } +- +- // There was an internal error -- shutdown +- shutdown(); +- if (handshakeState == HandshakeState.FINISHED) { +- return new SSLException(err); +- } +- return new SSLHandshakeException(err); +- } +- +- 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 +- if (srcs == null) { +- throw new NullPointerException("srcs"); +- } +- if (srcsOffset >= srcs.length +- || srcsOffset + srcsLength > srcs.length) { +- throw new IndexOutOfBoundsException( +- "offset: " + srcsOffset + ", length: " + srcsLength + +- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))"); +- } +- if (dsts == null) { +- throw new IllegalArgumentException("dsts is null"); +- } +- if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) { +- throw new IndexOutOfBoundsException( +- "offset: " + dstsOffset + ", length: " + dstsLength + +- " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))"); +- } +- long capacity = 0; +- final int dstsEndOffset = dstsOffset + dstsLength; +- for (int i = dstsOffset; i < dstsEndOffset; i ++) { +- ByteBuffer dst = dsts[i]; +- if (dst == null) { +- throw new IllegalArgumentException("dsts[" + i + "] is null"); +- } +- if (dst.isReadOnly()) { +- throw new ReadOnlyBufferException(); +- } +- capacity += dst.remaining(); +- } +- +- final int srcsEndOffset = srcsOffset + srcsLength; +- long len = 0; +- for (int i = srcsOffset; i < srcsEndOffset; i++) { +- ByteBuffer src = srcs[i]; +- if (src == null) { +- throw new IllegalArgumentException("srcs[" + i + "] is null"); +- } +- len += src.remaining(); +- } +- +- synchronized (this) { +- if (isInboundDone()) { +- return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_WRAP_CLOSED; +- } +- +- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING; +- // Prepare OpenSSL to work in server mode and receive handshake +- if (handshakeState != HandshakeState.FINISHED) { +- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) { +- // Update accepted so we know we triggered the handshake via wrap +- handshakeState = HandshakeState.STARTED_IMPLICITLY; +- } +- +- status = handshake(); +- if (status == NEED_WRAP) { +- return NEED_WRAP_OK; +- } +- // Check if the inbound is considered to be closed if so let us try to wrap again. +- if (isInboundDone) { +- return NEED_WRAP_CLOSED; +- } +- } +- +- if (len < SSL_RECORD_HEADER_LENGTH) { +- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0); +- } +- +- int packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset); +- +- if (packetLength == SslUtils.NOT_ENCRYPTED) { +- throw new NotSslRecordException("not an SSL/TLS record"); +- } +- +- if (packetLength - SSL_RECORD_HEADER_LENGTH > capacity) { +- // No enough space in the destination buffer so signal the caller +- // that the buffer needs to be increased. +- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0); +- } +- +- if (len < packetLength) { +- // We either have no enough data to read the packet length at all or not enough for reading +- // the whole packet. +- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0); +- } +- +- // 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 { +- for (; srcsOffset < srcsEndOffset; ++srcsOffset) { +- ByteBuffer src = srcs[srcsOffset]; +- int remaining = src.remaining(); +- if (remaining == 0) { +- // We must skip empty buffers as BIO_write will return 0 if asked to write something +- // with length 0. +- continue; +- } +- // Write more encrypted data into the BIO. Ensure we only read one packet at a time as +- // stated in the SSLEngine javadocs. +- int pendingEncryptedBytes = min(packetLength, remaining); +- ByteBuf bioWriteCopyBuf = writeEncryptedData(src, pendingEncryptedBytes); +- try { +- readLoop: +- for (; dstsOffset < dstsEndOffset; ++dstsOffset) { +- ByteBuffer dst = dsts[dstsOffset]; +- if (!dst.hasRemaining()) { +- // No space left in the destination buffer, skip it. +- continue; +- } +- +- int bytesRead = readPlaintextData(dst); +- // We are directly using the ByteBuffer memory for the write, and so we only know what +- // has been consumed after we let SSL decrypt the data. At this point we should update +- // the number of bytes consumed, update the ByteBuffer position, and release temp +- // ByteBuf. +- int localBytesConsumed = pendingEncryptedBytes - SSL.bioLengthByteBuffer(networkBIO); +- bytesConsumed += localBytesConsumed; +- packetLength -= localBytesConsumed; +- pendingEncryptedBytes -= localBytesConsumed; +- src.position(src.position() + localBytesConsumed); +- +- if (bytesRead > 0) { +- bytesProduced += bytesRead; +- +- if (!dst.hasRemaining()) { +- // Move to the next dst buffer as this one is full. +- continue; +- } +- if (packetLength == 0) { +- // We read everything return now. +- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, +- bytesConsumed, bytesProduced); +- } +- // try to write again to the BIO. stop reading from it by break out of the readLoop. +- break; +- } else { +- int sslError = SSL.getError(ssl, bytesRead); +- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) { +- // break to the outer loop as we want to read more data which means we need to +- // write more to the BIO. +- break readLoop; +- } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) { +- // This means the connection was shutdown correctly, close inbound and outbound +- if (!receivedShutdown) { +- closeAll(); +- } +- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, +- bytesConsumed, bytesProduced); +- } else { +- return sslReadErrorResult(SSL.getLastErrorNumber(), bytesConsumed, +- bytesProduced); +- } +- } +- } +- +- // Either we have no more dst buffers to put the data, or no more data to generate; we are done. +- if (dstsOffset >= dstsEndOffset || packetLength == 0) { +- break; +- } +- } finally { +- if (bioWriteCopyBuf != null) { +- bioWriteCopyBuf.release(); +- } +- } +- } +- } finally { +- SSL.bioClearByteBuffer(networkBIO); +- rejectRemoteInitiatedRenegotiation(); +- } +- +- // Check to see if we received a close_notify message from the peer. +- if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) { +- closeAll(); +- } +- +- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced); +- } +- } +- +- private SSLEngineResult sslReadErrorResult(int err, int bytesConsumed, int bytesProduced) throws SSLException { +- String errStr = SSL.getErrorString(err); +- +- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the +- // BIO first or can just shutdown and throw it now. +- // This is needed so we ensure close_notify etc is correctly send to the remote peer. +- // See https://github.com/netty/netty/issues/3900 +- if (SSL.bioLengthNonApplication(networkBIO) > 0) { +- if (handshakeException == null && handshakeState != HandshakeState.FINISHED) { +- // we seems to have data left that needs to be transfered and so the user needs +- // call wrap(...). Store the error so we can pick it up later. +- handshakeException = new SSLHandshakeException(errStr); +- } +- return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced); +- } +- throw shutdownWithError("SSL_read", errStr); +- } +- +- private void closeAll() throws SSLException { +- receivedShutdown = true; +- closeOutbound(); +- closeInbound(); +- } +- +- private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException { +- if (rejectRemoteInitiatedRenegotiation && SSL.getHandshakeCount(ssl) > 1) { +- // TODO: In future versions me may also want to send a fatal_alert to the client and so notify it +- // that the renegotiation failed. +- shutdown(); +- throw new SSLHandshakeException("remote-initiated renegotiation not allowed"); +- } +- } +- +- public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException { +- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length); +- } +- +- private ByteBuffer[] singleSrcBuffer(ByteBuffer src) { +- singleSrcBuffer[0] = src; +- return singleSrcBuffer; +- } +- +- private void resetSingleSrcBuffer() { +- singleSrcBuffer[0] = null; +- } +- +- private ByteBuffer[] singleDstBuffer(ByteBuffer src) { +- singleDstBuffer[0] = src; +- return singleDstBuffer; +- } +- +- private void resetSingleDstBuffer() { +- singleDstBuffer[0] = null; +- } +- +- @Override +- public final synchronized SSLEngineResult unwrap( +- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException { +- try { +- return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length); +- } finally { +- resetSingleSrcBuffer(); +- } +- } +- +- @Override +- public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException { +- try { +- return wrap(singleSrcBuffer(src), dst); +- } finally { +- resetSingleSrcBuffer(); +- } +- } +- +- @Override +- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException { +- try { +- return unwrap(singleSrcBuffer(src), singleDstBuffer(dst)); +- } finally { +- resetSingleSrcBuffer(); +- resetSingleDstBuffer(); +- } +- } +- +- @Override +- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException { +- try { +- return unwrap(singleSrcBuffer(src), dsts); +- } finally { +- resetSingleSrcBuffer(); +- } +- } +- +- @Override +- public final Runnable getDelegatedTask() { +- // Currently, we do not delegate SSL computation tasks +- // TODO: in the future, possibly create tasks to do encrypt / decrypt async +- +- return null; +- } +- +- @Override +- public final synchronized void closeInbound() throws SSLException { +- if (isInboundDone) { +- return; +- } +- +- isInboundDone = true; +- +- if (isOutboundDone()) { +- // Only call shutdown if there is no outbound data pending. +- // See https://github.com/netty/netty/issues/6167 +- shutdown(); +- } +- +- if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown) { +- throw new SSLException( +- "Inbound closed before receiving peer's close_notify: possible truncation attack?"); +- } +- } +- +- @Override +- public final synchronized boolean isInboundDone() { +- return isInboundDone; +- } +- +- @Override +- public final synchronized void closeOutbound() { +- if (outboundClosed) { +- return; +- } +- +- outboundClosed = true; +- +- if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) { +- int mode = SSL.getShutdown(ssl); +- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) { +- doSSLShutdown(); +- } +- } else { +- // engine closing before initial handshake +- shutdown(); +- } +- } +- +- /** +- * Attempt to call {@link SSL#shutdownSSL(long)}. +- * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not attempted or returned an error. +- */ +- private boolean doSSLShutdown() { +- if (SSL.isInInit(ssl) != 0) { +- // Only try to call SSL_shutdown if we are not in the init state anymore. +- // Otherwise we will see 'error:140E0197:SSL routines:SSL_shutdown:shutdown while in init' in our logs. +- // +- // See also http://hg.nginx.org/nginx/rev/062c189fee20 +- return false; +- } +- int err = SSL.shutdownSSL(ssl); +- if (err < 0) { +- int sslErr = SSL.getError(ssl, err); +- if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) { +- if (logger.isDebugEnabled()) { +- logger.debug("SSL_shutdown failed: OpenSSL error: {}", SSL.getLastError()); +- } +- // 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[OpenSsl.AVAILABLE_CIPHER_SUITES.size()]); +- } +- +- @Override +- public final String[] getEnabledCipherSuites() { +- final String[] enabled; +- synchronized (this) { +- if (!isDestroyed()) { +- enabled = SSL.getCiphers(ssl); +- } else { +- return EmptyArrays.EMPTY_STRINGS; +- } +- } +- if (enabled == null) { +- return EmptyArrays.EMPTY_STRINGS; +- } else { +- synchronized (this) { +- for (int i = 0; i < enabled.length; i++) { +- String mapped = toJavaCipherSuite(enabled[i]); +- if (mapped != null) { +- enabled[i] = mapped; +- } +- } +- } +- return enabled; +- } +- } +- +- @Override +- public final void setEnabledCipherSuites(String[] cipherSuites) { +- checkNotNull(cipherSuites, "cipherSuites"); +- +- final StringBuilder buf = new StringBuilder(); +- for (String c: cipherSuites) { +- if (c == null) { +- break; +- } +- +- String converted = CipherSuiteConverter.toOpenSsl(c); +- if (converted == null) { +- converted = c; +- } +- +- if (!OpenSsl.isCipherSuiteAvailable(converted)) { +- throw new IllegalArgumentException("unsupported cipher suite: " + c + '(' + converted + ')'); +- } +- +- buf.append(converted); +- buf.append(':'); +- } +- +- if (buf.length() == 0) { +- throw new IllegalArgumentException("empty cipher suites"); +- } +- buf.setLength(buf.length() - 1); +- +- final String cipherSuiteSpec = buf.toString(); +- +- synchronized (this) { +- if (!isDestroyed()) { +- try { +- SSL.setCipherSuites(ssl, cipherSuiteSpec); +- } catch (Exception e) { +- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e); +- } +- } else { +- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec); +- } +- } +- } +- +- @Override +- public final String[] getSupportedProtocols() { +- return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[OpenSsl.SUPPORTED_PROTOCOLS_SET.size()]); +- } +- +- @Override +- public final String[] getEnabledProtocols() { +- List enabled = new ArrayList(6); +- // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is always enabled +- enabled.add(OpenSsl.PROTOCOL_SSL_V2_HELLO); +- +- int opts; +- synchronized (this) { +- if (!isDestroyed()) { +- opts = SSL.getOptions(ssl); +- } else { +- return enabled.toArray(new String[1]); +- } +- } +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, OpenSsl.PROTOCOL_TLS_V1)) { +- enabled.add(OpenSsl.PROTOCOL_TLS_V1); +- } +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, OpenSsl.PROTOCOL_TLS_V1_1)) { +- enabled.add(OpenSsl.PROTOCOL_TLS_V1_1); +- } +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, OpenSsl.PROTOCOL_TLS_V1_2)) { +- enabled.add(OpenSsl.PROTOCOL_TLS_V1_2); +- } +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, OpenSsl.PROTOCOL_SSL_V2)) { +- enabled.add(OpenSsl.PROTOCOL_SSL_V2); +- } +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, OpenSsl.PROTOCOL_SSL_V3)) { +- enabled.add(OpenSsl.PROTOCOL_SSL_V3); +- } +- return enabled.toArray(new String[enabled.size()]); +- } +- +- private static boolean isProtocolEnabled(int opts, int disableMask, String protocolString) { +- // We also need to check if the actual protocolString is supported as depending on the openssl API +- // implementations it may use a disableMask of 0 (BoringSSL is doing this for example). +- return (opts & disableMask) == 0 && OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString); +- } +- +- @Override +- public final void setEnabledProtocols(String[] protocols) { +- if (protocols == null) { +- // This is correct from the API docs +- throw new IllegalArgumentException(); +- } +- boolean sslv2 = false; +- boolean sslv3 = false; +- boolean tlsv1 = false; +- boolean tlsv1_1 = false; +- boolean tlsv1_2 = false; +- for (String p: protocols) { +- if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) { +- throw new IllegalArgumentException("Protocol " + p + " is not supported."); +- } +- if (p.equals(OpenSsl.PROTOCOL_SSL_V2)) { +- sslv2 = true; +- } else if (p.equals(OpenSsl.PROTOCOL_SSL_V3)) { +- sslv3 = true; +- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1)) { +- tlsv1 = true; +- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_1)) { +- tlsv1_1 = true; +- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_2)) { +- tlsv1_2 = true; +- } +- } +- synchronized (this) { +- if (!isDestroyed()) { +- // Clear out options which disable protocols +- SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 | +- SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2); +- +- int opts = 0; +- if (!sslv2) { +- opts |= SSL.SSL_OP_NO_SSLv2; +- } +- if (!sslv3) { +- opts |= SSL.SSL_OP_NO_SSLv3; +- } +- if (!tlsv1) { +- opts |= SSL.SSL_OP_NO_TLSv1; +- } +- if (!tlsv1_1) { +- opts |= SSL.SSL_OP_NO_TLSv1_1; +- } +- if (!tlsv1_2) { +- opts |= SSL.SSL_OP_NO_TLSv1_2; +- } +- +- // 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(BEGIN_HANDSHAKE_ENGINE_CLOSED); +- +- // A user did not start handshake by calling this method by him/herself, +- // but handshake has been started already by wrap() or unwrap() implicitly. +- // Because it's the user's first time to call this method, it is unfair to +- // raise an exception. From the user's standpoint, he or she never asked +- // for renegotiation. +- +- handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this method is invoked by the user, +- // we should raise an exception. +- break; +- case STARTED_EXPLICITLY: +- // Nothing to do as the handshake is not done yet. +- break; +- case FINISHED: +- if (clientMode) { +- // Only supported for server mode at the moment. +- throw RENEGOTIATION_UNSUPPORTED; +- } +- // For renegotiate on the server side we need to issue the following command sequence with openssl: +- // +- // SSL_renegotiate(ssl) +- // SSL_do_handshake(ssl) +- // ssl->state = SSL_ST_ACCEPT +- // SSL_do_handshake(ssl) +- // +- // Because of this we fall-through to call handshake() after setting the state, as this will also take +- // care of updating the internal OpenSslSession object. +- // +- // See also: +- // https://github.com/apache/httpd/blob/2.4.16/modules/ssl/ssl_engine_kernel.c#L812 +- // http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html +- int status; +- if ((status = SSL.renegotiate(ssl)) != 1 || (status = SSL.doHandshake(ssl)) != 1) { +- int err = SSL.getError(ssl, status); +- if (err == SSL.SSL_ERROR_WANT_READ || err == SSL.SSL_ERROR_WANT_WRITE) { +- // If the internal SSL buffer is small it is possible that doHandshake may "fail" because +- // there is not enough room to write, so we should wait until the renegotiation has been. +- renegotiationPending = true; +- handshakeState = HandshakeState.STARTED_EXPLICITLY; +- lastAccessed = System.currentTimeMillis(); +- return; +- } else { +- throw shutdownWithError("renegotiation failed"); +- } +- } +- +- SSL.setState(ssl, SSL.SSL_ST_ACCEPT); +- +- lastAccessed = System.currentTimeMillis(); +- +- // fall-through +- case NOT_STARTED: +- handshakeState = HandshakeState.STARTED_EXPLICITLY; +- handshake(); +- break; +- default: +- throw new Error(); +- } +- } +- +- private void checkEngineClosed(SSLException cause) throws SSLException { +- if (isDestroyed()) { +- throw cause; +- } +- } +- +- 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 handshake() throws SSLException { +- if (handshakeState == HandshakeState.FINISHED) { +- return FINISHED; +- } +- checkEngineClosed(HANDSHAKE_ENGINE_CLOSED); +- +- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the +- // BIO first or can just shutdown and throw it now. +- // This is needed so we ensure close_notify etc is correctly send to the remote peer. +- // See https://github.com/netty/netty/issues/3900 +- SSLHandshakeException exception = handshakeException; +- if (exception != null) { +- if (SSL.bioLengthNonApplication(networkBIO) > 0) { +- // There is something pending, we need to consume it first via a WRAP so we don't loose anything. +- return NEED_WRAP; +- } +- // No more data left to send to the remote peer, so null out the exception field, shutdown and throw +- // the exception. +- handshakeException = null; +- shutdown(); +- throw exception; +- } +- +- // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the AbstractCertificateVerifier. +- engineMap.add(this); +- if (lastAccessed == -1) { +- lastAccessed = System.currentTimeMillis(); +- } +- +- if (!certificateSet && keyMaterialManager != null) { +- certificateSet = true; +- keyMaterialManager.setKeyMaterial(this); +- } +- +- int code = SSL.doHandshake(ssl); +- if (code <= 0) { +- // Check if we have a pending exception that was created during the handshake and if so throw it after +- // shutdown the connection. +- if (handshakeException != null) { +- exception = handshakeException; +- handshakeException = null; +- shutdown(); +- throw exception; +- } +- +- int sslError = SSL.getError(ssl, code); +- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) { +- return pendingStatus(SSL.bioLengthNonApplication(networkBIO)); +- } else { +- // Everything else is considered as error +- throw shutdownWithError("SSL_do_handshake"); +- } +- } +- // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means the handshake was finished. +- session.handshakeFinished(); +- engineMap.remove(ssl); +- return FINISHED; +- } +- +- private SSLEngineResult.HandshakeStatus mayFinishHandshake(SSLEngineResult.HandshakeStatus status) +- throws SSLException { +- if (status == NOT_HANDSHAKING && handshakeState != HandshakeState.FINISHED) { +- // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call +- // SSL_do_handshake() again +- return handshake(); +- } +- return status; +- } +- +- @Override +- public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() { +- // Check if we are in the initial handshake phase or shutdown phase +- return needPendingStatus() ? pendingStatus(SSL.bioLengthNonApplication(networkBIO)) : NOT_HANDSHAKING; +- } +- +- private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) { +- // Check if we are in the initial handshake phase or shutdown phase +- return needPendingStatus() ? pendingStatus(pending) : 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 prefix = toJavaCipherSuitePrefix(SSL.getVersion(ssl)); +- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix); +- } +- +- /** +- * Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string. +- */ +- private static String toJavaCipherSuitePrefix(String protocolVersion) { +- final char c; +- if (protocolVersion == null || protocolVersion.isEmpty()) { +- c = 0; +- } else { +- c = protocolVersion.charAt(0); +- } +- +- switch (c) { +- case 'T': +- return "TLS"; +- case 'S': +- return "SSL"; +- default: +- return "UNKNOWN"; +- } +- } +- +- @Override +- public final void setUseClientMode(boolean clientMode) { +- if (clientMode != this.clientMode) { +- throw new UnsupportedOperationException(); +- } +- } +- +- @Override +- public final boolean getUseClientMode() { +- return clientMode; +- } +- +- @Override +- public final void setNeedClientAuth(boolean b) { +- setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE); +- } +- +- @Override +- public final boolean getNeedClientAuth() { +- return clientAuth == ClientAuth.REQUIRE; +- } +- +- @Override +- public final void setWantClientAuth(boolean b) { +- setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE); +- } +- +- @Override +- public final boolean getWantClientAuth() { +- return clientAuth == ClientAuth.OPTIONAL; +- } +- +- /** +- * See SSL_set_verify and +- * {@link SSL#setVerify(long, int, int)}. +- */ +- @UnstableApi +- public final synchronized void setVerify(int verifyMode, int depth) { +- 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; +- } +- 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; +- } +- +- @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; +- } +- +- @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."); +- } +- +- if (version >= 8) { +- if (!isDestroyed()) { +- if (clientMode) { +- final List sniHostNames = Java8SslUtils.getSniHostNames(sslParameters); +- for (String name: sniHostNames) { +- SSL.setTlsExtHostName(ssl, name); +- } +- this.sniHostNames = sniHostNames; +- } +- if (Java8SslUtils.getUseCipherSuitesOrder(sslParameters)) { +- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); +- } else { +- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); +- } +- } +- matchers = sslParameters.getSNIMatchers(); +- } +- +- final String endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm(); +- final boolean endPointVerificationEnabled = endPointIdentificationAlgorithm != null && +- !endPointIdentificationAlgorithm.isEmpty(); +- SSL.setHostNameValidation(ssl, DEFAULT_HOSTNAME_VALIDATION_FLAGS, +- endPointVerificationEnabled ? getPeerHost() : null); +- // If the user asks for hostname verification we must ensure we verify the peer. +- // If the user disables hostname verification we leave it up to the user to change the mode manually. +- if (clientMode && endPointVerificationEnabled) { +- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1); +- } +- +- this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm; +- algorithmConstraints = sslParameters.getAlgorithmConstraints(); +- } +- super.setSSLParameters(sslParameters); +- } +- +- private boolean isDestroyed() { +- return destroyed != 0; +- } +- +- static int calculateOutNetBufSize(int pendingBytes, int numComponents) { +- return (int) min(MAX_ENCRYPTED_PACKET_LENGTH, +- pendingBytes + (long) MAX_TLS_RECORD_OVERHEAD_LENGTH * numComponents); +- } +- +- final boolean checkSniHostnameMatch(String hostname) { +- return Java8SslUtils.checkSniHostnameMatch(matchers, hostname); +- } +- +- private final class OpenSslSession implements SSLSession, ApplicationProtocolAccessor { +- private final OpenSslSessionContext sessionContext; +- +- // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any +- // thread. +- private X509Certificate[] x509PeerCerts; +- private Certificate[] peerCerts; +- private String protocol; +- private String applicationProtocol; +- private String cipher; +- private byte[] id; +- private long creationTime; +- +- // lazy init for memory reasons +- private Map values; +- +- OpenSslSession(OpenSslSessionContext sessionContext) { +- this.sessionContext = sessionContext; +- } +- +- @Override +- public byte[] getId() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (id == null) { +- return EmptyArrays.EMPTY_BYTES; +- } +- return id.clone(); +- } +- } +- +- @Override +- public SSLSessionContext getSessionContext() { +- return sessionContext; +- } +- +- @Override +- public long getCreationTime() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (creationTime == 0 && !isDestroyed()) { +- creationTime = SSL.getTime(ssl) * 1000L; +- } +- } +- return creationTime; +- } +- +- @Override +- public long getLastAccessedTime() { +- long lastAccessed = ReferenceCountedOpenSslEngine.this.lastAccessed; +- // if lastAccessed is -1 we will just return the creation time as the handshake was not started yet. +- return lastAccessed == -1 ? getCreationTime() : lastAccessed; +- } +- +- @Override +- public void invalidate() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (!isDestroyed()) { +- SSL.setTimeout(ssl, 0); +- } +- } +- } +- +- @Override +- public boolean isValid() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (!isDestroyed()) { +- return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L) < (SSL.getTime(ssl) * 1000L); +- } +- } +- return false; +- } +- +- @Override +- public void putValue(String name, Object value) { +- if (name == null) { +- throw new NullPointerException("name"); +- } +- if (value == null) { +- throw new NullPointerException("value"); +- } +- Map values = this.values; +- if (values == null) { +- // Use size of 2 to keep the memory overhead small +- values = this.values = new HashMap(2); +- } +- Object old = values.put(name, value); +- if (value instanceof SSLSessionBindingListener) { +- ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name)); +- } +- notifyUnbound(old, name); +- } +- +- @Override +- public Object getValue(String name) { +- if (name == null) { +- throw new NullPointerException("name"); +- } +- if (values == null) { +- return null; +- } +- return values.get(name); +- } +- +- @Override +- public void removeValue(String name) { +- if (name == null) { +- throw new NullPointerException("name"); +- } +- Map values = this.values; +- if (values == null) { +- return; +- } +- Object old = values.remove(name); +- notifyUnbound(old, name); +- } +- +- @Override +- public String[] getValueNames() { +- Map values = this.values; +- if (values == null || values.isEmpty()) { +- return EmptyArrays.EMPTY_STRINGS; +- } +- return values.keySet().toArray(new String[values.size()]); +- } +- +- private void notifyUnbound(Object value, String name) { +- if (value instanceof SSLSessionBindingListener) { +- ((SSLSessionBindingListener) value).valueUnbound(new SSLSessionBindingEvent(this, name)); +- } +- } +- +- /** +- * Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by +- * the user. +- */ +- void handshakeFinished() throws SSLException { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (!isDestroyed()) { +- id = SSL.getSessionId(ssl); +- cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl)); +- protocol = SSL.getVersion(ssl); +- +- initPeerCerts(); +- selectApplicationProtocol(); +- +- handshakeState = HandshakeState.FINISHED; +- } else { +- throw new SSLException("Already closed"); +- } +- } +- } +- +- /** +- * Init peer certificates that can be obtained via {@link #getPeerCertificateChain()} +- * and {@link #getPeerCertificates()}. +- */ +- private void initPeerCerts() { +- // Return the full chain from the JNI layer. +- byte[][] chain = SSL.getPeerCertChain(ssl); +- if (clientMode) { +- if (isEmpty(chain)) { +- peerCerts = EMPTY_CERTIFICATES; +- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES; +- } else { +- peerCerts = new Certificate[chain.length]; +- x509PeerCerts = new X509Certificate[chain.length]; +- initCerts(chain, 0); +- } +- } else { +- // if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer +- // certificate. We use SSL_get_peer_certificate to get it in this case and add it to our +- // array later. +- // +- // See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html +- byte[] clientCert = SSL.getPeerCertificate(ssl); +- if (isEmpty(clientCert)) { +- peerCerts = EMPTY_CERTIFICATES; +- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES; +- } else { +- if (isEmpty(chain)) { +- peerCerts = new Certificate[] {new OpenSslX509Certificate(clientCert)}; +- x509PeerCerts = new X509Certificate[] {new OpenSslJavaxX509Certificate(clientCert)}; +- } else { +- peerCerts = new Certificate[chain.length + 1]; +- x509PeerCerts = new X509Certificate[chain.length + 1]; +- peerCerts[0] = new OpenSslX509Certificate(clientCert); +- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert); +- initCerts(chain, 1); +- } +- } +- } +- } +- +- private void initCerts(byte[][] chain, int startPos) { +- for (int i = 0; i < chain.length; i++) { +- int certPos = startPos + i; +- peerCerts[certPos] = new OpenSslX509Certificate(chain[i]); +- x509PeerCerts[certPos] = new OpenSslJavaxX509Certificate(chain[i]); +- } +- } +- +- /** +- * Select the application protocol used. +- */ +- private void selectApplicationProtocol() throws SSLException { +- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior = apn.selectedListenerFailureBehavior(); +- List protocols = apn.protocols(); +- String applicationProtocol; +- switch (apn.protocol()) { +- case NONE: +- break; +- // We always need to check for applicationProtocol == null as the remote peer may not support +- // the TLS extension or may have returned an empty selection. +- case ALPN: +- applicationProtocol = SSL.getAlpnSelected(ssl); +- if (applicationProtocol != null) { +- this.applicationProtocol = selectApplicationProtocol( +- protocols, behavior, applicationProtocol); +- } +- break; +- case NPN: +- applicationProtocol = SSL.getNextProtoNegotiated(ssl); +- if (applicationProtocol != null) { +- this.applicationProtocol = selectApplicationProtocol( +- protocols, behavior, applicationProtocol); +- } +- break; +- case NPN_AND_ALPN: +- applicationProtocol = SSL.getAlpnSelected(ssl); +- if (applicationProtocol == null) { +- applicationProtocol = SSL.getNextProtoNegotiated(ssl); +- } +- if (applicationProtocol != null) { +- this.applicationProtocol = selectApplicationProtocol( +- protocols, behavior, applicationProtocol); +- } +- break; +- default: +- throw new Error(); +- } +- } +- +- private String selectApplicationProtocol(List protocols, +- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior, +- String applicationProtocol) throws SSLException { +- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) { +- return applicationProtocol; +- } else { +- int size = protocols.size(); +- assert size > 0; +- if (protocols.contains(applicationProtocol)) { +- return applicationProtocol; +- } else { +- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) { +- return protocols.get(size - 1); +- } else { +- throw new SSLException("unknown protocol " + applicationProtocol); +- } +- } +- } +- } +- +- @Override +- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (isEmpty(peerCerts)) { +- throw new SSLPeerUnverifiedException("peer not verified"); +- } +- return peerCerts.clone(); +- } +- } +- +- @Override +- public Certificate[] getLocalCertificates() { +- 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 = localCerts; +- if (local == null || local.length == 0) { +- return null; +- } +- return ((java.security.cert.X509Certificate) local[0]).getIssuerX500Principal(); +- } +- +- @Override +- public String getCipherSuite() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- if (cipher == null) { +- return 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 getApplicationProtocol() { +- synchronized (ReferenceCountedOpenSslEngine.this) { +- return applicationProtocol; +- } +- } +- +- @Override +- public String getPeerHost() { +- return ReferenceCountedOpenSslEngine.this.getPeerHost(); +- } +- +- @Override +- public int getPeerPort() { +- return ReferenceCountedOpenSslEngine.this.getPeerPort(); +- } +- +- @Override +- public int getPacketBufferSize() { +- return MAX_ENCRYPTED_PACKET_LENGTH; +- } +- +- @Override +- public int getApplicationBufferSize() { +- return MAX_PLAINTEXT_LENGTH; +- } +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java +deleted file mode 100644 +index 4c9df31..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java ++++ /dev/null +@@ -1,239 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +-import io.netty.internal.tcnative.SniHostNameMatcher; +-import io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; +- +-import java.security.KeyStore; +-import java.security.PrivateKey; +-import java.security.cert.X509Certificate; +-import javax.net.ssl.KeyManagerFactory; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.TrustManagerFactory; +-import javax.net.ssl.X509ExtendedKeyManager; +-import javax.net.ssl.X509ExtendedTrustManager; +-import javax.net.ssl.X509KeyManager; +-import javax.net.ssl.X509TrustManager; +- +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +- +-/** +- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. +- *

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

Instances of this class must not be released before any {@link ReferenceCountedOpenSslEngine} +- * which depends upon the instance of this class is released. Otherwise if any method of +- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. +- */ +-public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext { +- private static final InternalLogger logger = +- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class); +- private static final byte[] ID = {'n', 'e', 't', 't', 'y'}; +- private final OpenSslServerSessionContext sessionContext; +- private final OpenSslKeyMaterialManager keyMaterialManager; +- +- ReferenceCountedOpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp) throws SSLException { +- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, +- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, +- enableOcsp); +- } +- +- private ReferenceCountedOpenSslServerContext( +- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, +- Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, +- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, +- clientAuth, protocols, startTls, enableOcsp, true); +- // Create a new SSL_CTX and configure it. +- boolean success = false; +- try { +- ServerContext context = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, +- keyCertChain, key, keyPassword, keyManagerFactory); +- sessionContext = context.sessionContext; +- keyMaterialManager = context.keyMaterialManager; +- success = true; +- } finally { +- if (!success) { +- release(); +- } +- } +- } +- +- @Override +- public OpenSslServerSessionContext sessionContext() { +- return sessionContext; +- } +- +- @Override +- OpenSslKeyMaterialManager keyMaterialManager() { +- return keyMaterialManager; +- } +- +- static final class ServerContext { +- OpenSslServerSessionContext sessionContext; +- OpenSslKeyMaterialManager keyMaterialManager; +- } +- +- static ServerContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx, OpenSslEngineMap engineMap, +- X509Certificate[] trustCertCollection, +- TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, +- String keyPassword, KeyManagerFactory keyManagerFactory) +- throws SSLException { +- ServerContext result = new ServerContext(); +- try { +- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); +- if (!OpenSsl.useKeyManagerFactory()) { +- if (keyManagerFactory != null) { +- throw new IllegalArgumentException( +- "KeyManagerFactory not supported"); +- } +- checkNotNull(keyCertChain, "keyCertChain"); +- +- setKeyMaterial(ctx, keyCertChain, key, keyPassword); +- } else { +- // javadocs state that keyManagerFactory has precedent over keyCertChain, and we must have a +- // keyManagerFactory for the server so build one if it is not specified. +- if (keyManagerFactory == null) { +- keyManagerFactory = buildKeyManagerFactory( +- keyCertChain, key, keyPassword, keyManagerFactory); +- } +- X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers()); +- result.keyMaterialManager = useExtendedKeyManager(keyManager) ? +- new OpenSslExtendedKeyMaterialManager( +- (X509ExtendedKeyManager) keyManager, keyPassword) : +- new OpenSslKeyMaterialManager(keyManager, keyPassword); +- } +- } catch (Exception e) { +- throw new SSLException("failed to set certificate and key", e); +- } +- try { +- if (trustCertCollection != null) { +- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory); +- } else if (trustManagerFactory == null) { +- // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works +- trustManagerFactory = TrustManagerFactory.getInstance( +- TrustManagerFactory.getDefaultAlgorithm()); +- trustManagerFactory.init((KeyStore) null); +- } +- +- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); +- +- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as +- // otherwise the context can never be collected. This is because the JNI code holds +- // a global reference to the callbacks. +- // +- // See https://github.com/netty/netty/issues/5372 +- +- // Use this to prevent an error when running on java < 7 +- if (useExtendedTrustManager(manager)) { +- SSLContext.setCertVerifyCallback(ctx, +- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager)); +- } else { +- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager)); +- } +- +- X509Certificate[] issuers = manager.getAcceptedIssuers(); +- if (issuers != null && issuers.length > 0) { +- long bio = 0; +- try { +- bio = toBIO(issuers); +- if (!SSLContext.setCACertificateBio(ctx, bio)) { +- throw new SSLException("unable to setup accepted issuers for trustmanager " + manager); +- } +- } 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); +- } +- +- result.sessionContext = new OpenSslServerSessionContext(thiz); +- result.sessionContext.setSessionIdContext(ID); +- return result; +- } +- +- 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); +- } +- } +- +- 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) { +- return engine.checkSniHostnameMatch(hostname); +- } +- logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl); +- return false; +- } +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java +index 4998d0d..8dbc3cf 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java ++++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java +@@ -115,11 +115,7 @@ public abstract class SslContext { + } + + private static SslProvider defaultProvider() { +- if (OpenSsl.isAvailable()) { +- return SslProvider.OPENSSL; +- } else { +- return SslProvider.JDK; +- } ++ return SslProvider.JDK; + } + + /** +@@ -416,18 +412,6 @@ public abstract class SslContext { + trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, + keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, + clientAuth, protocols, startTls); +- case OPENSSL: +- verifyNullSslContextProvider(provider, sslContextProvider); +- return new OpenSslServerContext( +- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, +- clientAuth, protocols, startTls, enableOcsp); +- case OPENSSL_REFCNT: +- verifyNullSslContextProvider(provider, sslContextProvider); +- return new ReferenceCountedOpenSslServerContext( +- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, +- clientAuth, protocols, startTls, enableOcsp); + default: + throw new Error(provider.toString()); + } +@@ -770,18 +754,6 @@ public abstract class SslContext { + return new JdkSslClientContext(sslContextProvider, + trustCert, trustManagerFactory, keyCertChain, key, keyPassword, + keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout); +- case OPENSSL: +- verifyNullSslContextProvider(provider, sslContextProvider); +- return new OpenSslClientContext( +- trustCert, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, +- enableOcsp); +- case OPENSSL_REFCNT: +- verifyNullSslContextProvider(provider, sslContextProvider); +- return new ReferenceCountedOpenSslClientContext( +- trustCert, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, +- enableOcsp); + default: + throw new Error(provider.toString()); + } +diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +index c054964..05c451a 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java ++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +@@ -159,6 +159,12 @@ import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength; + * #832 in our issue tracker. + */ + public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler { ++ private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14 ++ private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024; ++ private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024; ++ // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256) ++ static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256; ++ static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = MAX_ENCRYPTED_PACKET_LENGTH - MAX_PLAINTEXT_LENGTH; + + private static final InternalLogger logger = + InternalLoggerFactory.getInstance(SslHandler.class); +@@ -181,40 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + new ClosedChannelException(), SslHandler.class, "channelInactive(...)"); + + private enum SslEngineType { +- TCNATIVE(true, COMPOSITE_CUMULATOR) { +- @Override +- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) +- throws SSLException { +- int nioBufferCount = in.nioBufferCount(); +- int writerIndex = out.writerIndex(); +- final SSLEngineResult result; +- if (nioBufferCount > 1) { +- /* +- * If {@link OpenSslEngine} is in use, +- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method +- * that accepts multiple {@link ByteBuffer}s without additional memory copies. +- */ +- ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine; +- try { +- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, +- out.writableBytes()); +- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer); +- } finally { +- handler.singleBuffer[0] = null; +- } +- } else { +- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len), +- toByteBuffer(out, writerIndex, out.writableBytes())); +- } +- out.writerIndex(writerIndex + result.bytesProduced()); +- return result; +- } +- +- @Override +- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) { +- return ReferenceCountedOpenSslEngine.calculateOutNetBufSize(pendingBytes, numComponents); +- } +- }, + CONSCRYPT(true, COMPOSITE_CUMULATOR) { + @Override + SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) +@@ -265,9 +237,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + }; + + static SslEngineType forEngine(SSLEngine engine) { +- if (engine instanceof ReferenceCountedOpenSslEngine) { +- return TCNATIVE; +- } + if (engine instanceof ConscryptAlpnSslEngine) { + return CONSCRYPT; + } +@@ -1034,7 +1003,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + + boolean nonSslRecord = false; + +- while (totalLength < ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { ++ while (totalLength < MAX_ENCRYPTED_PACKET_LENGTH) { + final int readableBytes = endOffset - offset; + if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) { + break; +@@ -1055,7 +1024,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + } + + int newTotalLength = totalLength + packetLength; +- if (newTotalLength > ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { ++ if (newTotalLength > MAX_ENCRYPTED_PACKET_LENGTH) { + // Don't read too much. + break; + } +diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java +deleted file mode 100644 +index aff0949..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java ++++ /dev/null +@@ -1,65 +0,0 @@ +-/* +- * Copyright 2017 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl.ocsp; +- +-import io.netty.channel.ChannelHandlerContext; +-import io.netty.channel.ChannelInboundHandlerAdapter; +-import io.netty.handler.ssl.ReferenceCountedOpenSslContext; +-import io.netty.handler.ssl.ReferenceCountedOpenSslEngine; +-import io.netty.handler.ssl.SslHandshakeCompletionEvent; +-import io.netty.util.internal.ObjectUtil; +-import io.netty.util.internal.ThrowableUtil; +-import io.netty.util.internal.UnstableApi; +- +-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 static final SSLHandshakeException OCSP_VERIFICATION_EXCEPTION = ThrowableUtil.unknownStackTrace( +- new SSLHandshakeException("Bad OCSP response"), OcspClientHandler.class, "verify(...)"); +- +- 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 OCSP_VERIFICATION_EXCEPTION; +- } +- } +- +- 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 2883ff4..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java ++++ /dev/null +@@ -1,23 +0,0 @@ +-/* +- * Copyright 2017 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-/** +- * OCSP stapling, +- * formally known as the TLS Certificate Status Request extension, is an +- * alternative approach to the Online Certificate Status Protocol (OCSP) +- * for checking the revocation status of X.509 digital certificates. +- */ +-package io.netty.handler.ssl.ocsp; +diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java +deleted file mode 100644 +index d696d6b..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java ++++ /dev/null +@@ -1,108 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import org.junit.BeforeClass; +-import org.junit.Test; +-import org.junit.runner.RunWith; +-import org.junit.runners.Parameterized; +- +-import java.util.ArrayList; +-import java.util.Collection; +-import java.util.List; +- +-import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory; +-import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED; +-import static org.junit.Assume.assumeTrue; +- +-@RunWith(Parameterized.class) +-public class JdkOpenSslEngineInteroptTest extends SSLEngineTest { +- +- @Parameterized.Parameters(name = "{index}: bufferType = {0}") +- public static Collection data() { +- List params = new ArrayList(); +- for (BufferType type: BufferType.values()) { +- params.add(type); +- } +- return params; +- } +- +- public JdkOpenSslEngineInteroptTest(BufferType type) { +- super(type); +- } +- +- @BeforeClass +- public static void checkOpenSsl() { +- assumeTrue(OpenSsl.isAvailable()); +- } +- +- @Override +- protected SslProvider sslClientProvider() { +- return SslProvider.JDK; +- } +- +- @Override +- protected SslProvider sslServerProvider() { +- return SslProvider.OPENSSL; +- } +- +- @Override +- @Test +- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth(); +- } +- +- @Override +- @Test +- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth(); +- } +- +- @Override +- @Test +- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth(); +- } +- +- @Override +- @Test +- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth(); +- } +- +- @Override +- @Test +- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth(); +- } +- +- @Override +- protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) { +- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) handler.engine(); +- engine.setVerify(SSL_CVERIFY_IGNORED, 1); +- } +- +- @Override +- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) { +- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. +- return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java +deleted file mode 100644 +index 229e853..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java ++++ /dev/null +@@ -1,49 +0,0 @@ +-/* +- * Copyright 2017 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.internal.tcnative.CertificateVerifier; +-import org.junit.Assert; +-import org.junit.Assume; +-import org.junit.BeforeClass; +-import org.junit.Test; +- +-import java.lang.reflect.Field; +- +-public class OpenSslCertificateExceptionTest { +- +- @BeforeClass +- public static void assumeOpenSsl() { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- } +- +- @Test +- public void testValidErrorCode() throws Exception { +- Field[] fields = CertificateVerifier.class.getFields(); +- for (Field field : fields) { +- if (field.isAccessible()) { +- int errorCode = field.getInt(null); +- OpenSslCertificateException exception = new OpenSslCertificateException(errorCode); +- Assert.assertEquals(errorCode, exception.errorCode()); +- } +- } +- } +- +- @Test(expected = IllegalArgumentException.class) +- public void testNonValidErrorCode() { +- new OpenSslCertificateException(Integer.MIN_VALUE); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java +deleted file mode 100644 +index 6011cf7..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java ++++ /dev/null +@@ -1,38 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +-import org.junit.BeforeClass; +- +-import javax.net.ssl.SSLException; +-import java.io.File; +- +-import static org.junit.Assume.assumeTrue; +- +-public class OpenSslClientContextTest extends SslContextTest { +- +- @BeforeClass +- public static void checkOpenSsl() { +- assumeTrue(OpenSsl.isAvailable()); +- } +- +- @Override +- protected SslContext newServerContext(File crtFile, File keyFile, String pass) throws SSLException { +- return new OpenSslClientContext(crtFile, InsecureTrustManagerFactory.INSTANCE, crtFile, keyFile, pass, +- null, null, IdentityCipherSuiteFilter.INSTANCE, ApplicationProtocolConfig.DISABLED, 0, 0); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java +deleted file mode 100644 +index 5939b66..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java ++++ /dev/null +@@ -1,661 +0,0 @@ +-/* +- * Copyright 2015 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.buffer.UnpooledByteBufAllocator; +-import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; +-import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior; +-import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; +-import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +-import io.netty.handler.ssl.util.SelfSignedCertificate; +-import io.netty.util.internal.PlatformDependent; +-import org.junit.Assume; +-import org.junit.BeforeClass; +-import org.junit.Test; +-import org.junit.runner.RunWith; +-import org.junit.runners.Parameterized; +- +-import java.nio.ByteBuffer; +-import java.security.AlgorithmConstraints; +-import java.security.AlgorithmParameters; +-import java.security.CryptoPrimitive; +-import java.security.Key; +-import java.util.ArrayList; +-import java.util.Collection; +-import java.util.List; +-import java.util.Set; +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLEngineResult; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.SSLParameters; +- +-import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory; +-import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH; +-import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH; +-import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_PLAINTEXT_LENGTH; +-import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED; +-import static java.lang.Integer.MAX_VALUE; +-import static org.junit.Assert.assertEquals; +-import static org.junit.Assert.assertFalse; +-import static org.junit.Assert.assertNull; +-import static org.junit.Assert.assertSame; +-import static org.junit.Assert.assertTrue; +-import static org.junit.Assume.assumeTrue; +- +-@RunWith(Parameterized.class) +-public class OpenSslEngineTest extends SSLEngineTest { +- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2"; +- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1"; +- +- @Parameterized.Parameters(name = "{index}: bufferType = {0}") +- public static Collection data() { +- List params = new ArrayList(); +- for (BufferType type: BufferType.values()) { +- params.add(type); +- } +- return params; +- } +- +- public OpenSslEngineTest(BufferType type) { +- super(type); +- } +- +- @BeforeClass +- public static void checkOpenSsl() { +- assumeTrue(OpenSsl.isAvailable()); +- } +- +- @Override +- @Test +- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth(); +- } +- +- @Override +- @Test +- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth(); +- } +- +- @Override +- @Test +- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth(); +- } +- +- @Override +- @Test +- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth(); +- } +- +- @Override +- @Test +- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth(); +- } +- +- @Override +- @Test +- public void testClientHostnameValidationSuccess() throws InterruptedException, SSLException { +- assumeTrue(OpenSsl.supportsHostnameValidation()); +- super.testClientHostnameValidationSuccess(); +- } +- +- @Override +- @Test +- public void testClientHostnameValidationFail() throws InterruptedException, SSLException { +- assumeTrue(OpenSsl.supportsHostnameValidation()); +- super.testClientHostnameValidationFail(); +- } +- +- @Test +- public void testNpn() throws Exception { +- ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.NPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- setupHandlers(apn); +- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- } +- +- @Test +- public void testAlpn() throws Exception { +- assumeTrue(OpenSsl.isAlpnSupported()); +- ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.ALPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- setupHandlers(apn); +- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- } +- +- @Test +- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception { +- assumeTrue(OpenSsl.isAlpnSupported()); +- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN, +- FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL); +- setupHandlers(serverApn, clientApn); +- assertNull(serverException); +- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- } +- +- @Test +- public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception { +- testEnablingAnAlreadyDisabledSslProtocol(new String[]{PROTOCOL_SSL_V2_HELLO}, +- new String[]{PROTOCOL_SSL_V2_HELLO, PROTOCOL_TLS_V1_2}); +- } +- @Test +- public void testWrapBuffersNoWritePendingError() throws Exception { +- clientSslCtx = SslContextBuilder.forClient() +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .sslProvider(sslClientProvider()) +- .build(); +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslServerProvider()) +- .build(); +- SSLEngine clientEngine = null; +- SSLEngine serverEngine = null; +- try { +- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- handshake(clientEngine, serverEngine); +- +- ByteBuffer src = allocateBuffer(1024 * 10); +- byte[] data = new byte[src.capacity()]; +- PlatformDependent.threadLocalRandom().nextBytes(data); +- src.put(data).flip(); +- ByteBuffer dst = allocateBuffer(1); +- // Try to wrap multiple times so we are more likely to hit the issue. +- for (int i = 0; i < 100; i++) { +- src.position(0); +- dst.position(0); +- assertSame(SSLEngineResult.Status.BUFFER_OVERFLOW, clientEngine.wrap(src, dst).getStatus()); +- } +- } finally { +- cleanupClientSslEngine(clientEngine); +- cleanupServerSslEngine(serverEngine); +- } +- } +- +- @Test +- public void testOnlySmallBufferNeededForWrap() throws Exception { +- clientSslCtx = SslContextBuilder.forClient() +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .sslProvider(sslClientProvider()) +- .build(); +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslServerProvider()) +- .build(); +- SSLEngine clientEngine = null; +- SSLEngine serverEngine = null; +- try { +- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- handshake(clientEngine, serverEngine); +- +- // Allocate a buffer which is small enough and set the limit to the capacity to mark its whole content +- // as readable. +- int srcLen = 1024; +- ByteBuffer src = allocateBuffer(srcLen); +- +- ByteBuffer dstTooSmall = allocateBuffer( +- src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH - 1); +- ByteBuffer dst = allocateBuffer( +- src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH); +- +- // Check that we fail to wrap if the dst buffers capacity is not at least +- // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH +- SSLEngineResult result = clientEngine.wrap(src, dstTooSmall); +- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); +- assertEquals(0, result.bytesConsumed()); +- assertEquals(0, result.bytesProduced()); +- assertEquals(src.remaining(), src.capacity()); +- assertEquals(dst.remaining(), dst.capacity()); +- +- // Check that we can wrap with a dst buffer that has the capacity of +- // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH +- result = clientEngine.wrap(src, dst); +- assertEquals(SSLEngineResult.Status.OK, result.getStatus()); +- assertEquals(srcLen, result.bytesConsumed()); +- assertEquals(0, src.remaining()); +- assertTrue(result.bytesProduced() > srcLen); +- assertEquals(src.capacity() - result.bytesConsumed(), src.remaining()); +- assertEquals(dst.capacity() - result.bytesProduced(), dst.remaining()); +- } finally { +- cleanupClientSslEngine(clientEngine); +- cleanupServerSslEngine(serverEngine); +- } +- } +- +- @Test +- public void testNeededDstCapacityIsCorrectlyCalculated() throws Exception { +- clientSslCtx = SslContextBuilder.forClient() +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .sslProvider(sslClientProvider()) +- .build(); +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslServerProvider()) +- .build(); +- SSLEngine clientEngine = null; +- SSLEngine serverEngine = null; +- try { +- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- handshake(clientEngine, serverEngine); +- +- ByteBuffer src = allocateBuffer(1024); +- ByteBuffer src2 = src.duplicate(); +- +- ByteBuffer dst = allocateBuffer(src.capacity() +- + MAX_TLS_RECORD_OVERHEAD_LENGTH); +- +- SSLEngineResult result = clientEngine.wrap(new ByteBuffer[] { src, src2 }, dst); +- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); +- assertEquals(0, src.position()); +- assertEquals(0, src2.position()); +- assertEquals(0, dst.position()); +- assertEquals(0, result.bytesConsumed()); +- assertEquals(0, result.bytesProduced()); +- } finally { +- cleanupClientSslEngine(clientEngine); +- cleanupServerSslEngine(serverEngine); +- } +- } +- +- @Test +- public void testSrcsLenOverFlowCorrectlyHandled() throws Exception { +- clientSslCtx = SslContextBuilder.forClient() +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .sslProvider(sslClientProvider()) +- .build(); +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslServerProvider()) +- .build(); +- SSLEngine clientEngine = null; +- SSLEngine serverEngine = null; +- try { +- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- handshake(clientEngine, serverEngine); +- +- ByteBuffer src = allocateBuffer(1024); +- List srcList = new ArrayList(); +- long srcsLen = 0; +- long maxLen = ((long) MAX_VALUE) * 2; +- +- while (srcsLen < maxLen) { +- ByteBuffer dup = src.duplicate(); +- srcList.add(dup); +- srcsLen += dup.capacity(); +- } +- +- ByteBuffer[] srcs = srcList.toArray(new ByteBuffer[srcList.size()]); +- +- ByteBuffer dst = allocateBuffer(MAX_ENCRYPTED_PACKET_LENGTH - 1); +- +- SSLEngineResult result = clientEngine.wrap(srcs, dst); +- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); +- +- for (ByteBuffer buffer : srcs) { +- assertEquals(0, buffer.position()); +- } +- assertEquals(0, dst.position()); +- assertEquals(0, result.bytesConsumed()); +- assertEquals(0, result.bytesProduced()); +- } finally { +- cleanupClientSslEngine(clientEngine); +- cleanupServerSslEngine(serverEngine); +- } +- } +- +- @Test +- public void testCalculateOutNetBufSizeOverflow() { +- assertEquals(MAX_ENCRYPTED_PACKET_LENGTH, +- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_VALUE, 1)); +- } +- +- @Test +- public void testCalculateOutNetBufSize0() { +- assertEquals(MAX_TLS_RECORD_OVERHEAD_LENGTH, +- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(0, 1)); +- } +- +- @Test +- public void testCalculateOutNetBufSizeMaxEncryptedPacketLength() { +- assertEquals(MAX_ENCRYPTED_PACKET_LENGTH, +- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_ENCRYPTED_PACKET_LENGTH + 1, 2)); +- } +- +- @Override +- protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) { +- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) handler.engine(); +- engine.setVerify(SSL_CVERIFY_IGNORED, 1); +- } +- +- @Test +- public void testWrapWithDifferentSizesTLSv1() throws Exception { +- clientSslCtx = SslContextBuilder.forClient() +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .sslProvider(sslClientProvider()) +- .build(); +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslServerProvider()) +- .build(); +- +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-MD5"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "EDH-RSA-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-RC4-MD5"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "IDEA-CBC-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-RC4-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-RC4-SHA"); +- } +- +- @Test +- public void testWrapWithDifferentSizesTLSv1_1() throws Exception { +- clientSslCtx = SslContextBuilder.forClient() +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .sslProvider(sslClientProvider()) +- .build(); +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslServerProvider()) +- .build(); +- +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "IDEA-CBC-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-RC4-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-RC4-MD5"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "RC4-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "EDH-RSA-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DES-CBC3-SHA"); +- } +- +- @Test +- public void testWrapWithDifferentSizesTLSv1_2() throws Exception { +- clientSslCtx = SslContextBuilder.forClient() +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .sslProvider(sslClientProvider()) +- .build(); +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslServerProvider()) +- .build(); +- +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-GCM-SHA384"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-GCM-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-GCM-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-SHA384"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-GCM-SHA384"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-GCM-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-MD5"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "EDH-RSA-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-RC4-MD5"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "IDEA-CBC-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-GCM-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-RC4-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-GCM-SHA384"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-GCM-SHA384"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-SHA256"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-RC4-SHA"); +- } +- +- @Test +- public void testWrapWithDifferentSizesSSLv3() throws Exception { +- clientSslCtx = SslContextBuilder.forClient() +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .sslProvider(sslClientProvider()) +- .build(); +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslServerProvider()) +- .build(); +- +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-MD5"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "EDH-RSA-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-RC4-MD5"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "IDEA-CBC-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-AES128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-RC4-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-SEED-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-AES256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ECDHE-RSA-DES-CBC3-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-CAMELLIA256-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-CAMELLIA128-SHA"); +- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ECDHE-RSA-RC4-SHA"); +- } +- +- private void testWrapWithDifferentSizes(String protocol, String cipher) throws Exception { +- assumeTrue(OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocol)); +- if (!OpenSsl.isCipherSuiteAvailable(cipher)) { +- return; +- } +- +- SSLEngine clientEngine = null; +- SSLEngine serverEngine = null; +- try { +- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- clientEngine.setEnabledCipherSuites(new String[] { cipher }); +- clientEngine.setEnabledProtocols(new String[] { protocol }); +- serverEngine.setEnabledCipherSuites(new String[] { cipher }); +- serverEngine.setEnabledProtocols(new String[] { protocol }); +- +- try { +- handshake(clientEngine, serverEngine); +- } catch (SSLException e) { +- if (e.getMessage().contains("unsupported protocol")) { +- Assume.assumeNoException(protocol + " not supported with cipher " + cipher, e); +- } +- throw e; +- } +- +- int srcLen = 64; +- do { +- testWrapDstBigEnough(clientEngine, srcLen); +- srcLen += 64; +- } while (srcLen < MAX_PLAINTEXT_LENGTH); +- +- testWrapDstBigEnough(clientEngine, MAX_PLAINTEXT_LENGTH); +- } finally { +- cleanupClientSslEngine(clientEngine); +- cleanupServerSslEngine(serverEngine); +- } +- } +- +- private void testWrapDstBigEnough(SSLEngine engine, int srcLen) throws SSLException { +- ByteBuffer src = allocateBuffer(srcLen); +- ByteBuffer dst = allocateBuffer(srcLen + MAX_TLS_RECORD_OVERHEAD_LENGTH); +- +- SSLEngineResult result = engine.wrap(src, dst); +- assertEquals(SSLEngineResult.Status.OK, result.getStatus()); +- int consumed = result.bytesConsumed(); +- int produced = result.bytesProduced(); +- assertEquals(srcLen, consumed); +- assertTrue(produced > consumed); +- +- dst.flip(); +- assertEquals(produced, dst.remaining()); +- assertFalse(src.hasRemaining()); +- } +- +- @Test +- public void testSNIMatchersDoesNotThrow() throws Exception { +- assumeTrue(PlatformDependent.javaVersion() >= 8); +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslServerProvider()) +- .build(); +- +- SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- try { +- SSLParameters parameters = new SSLParameters(); +- Java8SslTestUtils.setSNIMatcher(parameters); +- engine.setSSLParameters(parameters); +- } finally { +- cleanupServerSslEngine(engine); +- ssc.delete(); +- } +- } +- +- @Test(expected = IllegalArgumentException.class) +- public void testAlgorithmConstraintsThrows() throws Exception { +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslServerProvider()) +- .build(); +- +- SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); +- try { +- SSLParameters parameters = new SSLParameters(); +- parameters.setAlgorithmConstraints(new AlgorithmConstraints() { +- @Override +- public boolean permits( +- Set primitives, String algorithm, AlgorithmParameters parameters) { +- return false; +- } +- +- @Override +- public boolean permits(Set primitives, Key key) { +- return false; +- } +- +- @Override +- public boolean permits( +- Set primitives, String algorithm, Key key, AlgorithmParameters parameters) { +- return false; +- } +- }); +- engine.setSSLParameters(parameters); +- } finally { +- cleanupServerSslEngine(engine); +- ssc.delete(); +- } +- } +- +- @Override +- protected SslProvider sslClientProvider() { +- return SslProvider.OPENSSL; +- } +- +- @Override +- protected SslProvider sslServerProvider() { +- return SslProvider.OPENSSL; +- } +- +- private static ApplicationProtocolConfig acceptingNegotiator(Protocol protocol, +- String... supportedProtocols) { +- return new ApplicationProtocolConfig(protocol, +- SelectorFailureBehavior.NO_ADVERTISE, +- SelectedListenerFailureBehavior.ACCEPT, +- supportedProtocols); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java +deleted file mode 100644 +index f63a16f..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java ++++ /dev/null +@@ -1,114 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import org.junit.BeforeClass; +-import org.junit.Ignore; +-import org.junit.Test; +- +-import javax.net.ssl.SSLException; +-import org.junit.runner.RunWith; +-import org.junit.runners.Parameterized; +- +-import java.util.ArrayList; +-import java.util.Collection; +-import java.util.List; +- +-import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory; +-import static org.junit.Assume.assumeTrue; +- +-@RunWith(Parameterized.class) +-public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest { +- +- @Parameterized.Parameters(name = "{index}: bufferType = {0}") +- public static Collection data() { +- List params = new ArrayList(); +- for (BufferType type: BufferType.values()) { +- params.add(type); +- } +- return params; +- } +- +- public OpenSslJdkSslEngineInteroptTest(BufferType type) { +- super(type); +- } +- +- @BeforeClass +- public static void checkOpenSsl() { +- assumeTrue(OpenSsl.isAvailable()); +- } +- +- @Override +- protected SslProvider sslClientProvider() { +- return SslProvider.OPENSSL; +- } +- +- @Override +- protected SslProvider sslServerProvider() { +- return SslProvider.JDK; +- } +- +- @Ignore /* Does the JDK support a "max certificate chain length"? */ +- @Override +- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { +- } +- +- @Ignore /* Does the JDK support a "max certificate chain length"? */ +- @Override +- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { +- } +- +- @Override +- @Test +- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth(); +- } +- +- @Override +- @Test +- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth(); +- } +- +- @Override +- @Test +- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception { +- checkShouldUseKeyManagerFactory(); +- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth(); +- } +- +- @Override +- @Test +- public void testClientHostnameValidationSuccess() throws InterruptedException, SSLException { +- assumeTrue(OpenSsl.supportsHostnameValidation()); +- super.testClientHostnameValidationSuccess(); +- } +- +- @Override +- @Test +- public void testClientHostnameValidationFail() throws InterruptedException, SSLException { +- assumeTrue(OpenSsl.supportsHostnameValidation()); +- super.testClientHostnameValidationFail(); +- } +- +- @Override +- protected boolean mySetupMutualAuthServerIsValidServerException(Throwable cause) { +- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. +- return super.mySetupMutualAuthServerIsValidServerException(cause) || causedBySSLException(cause); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java +deleted file mode 100644 +index 3959e64..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java ++++ /dev/null +@@ -1,23 +0,0 @@ +-/* +- * Copyright 2017 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-public class OpenSslRenegotiateSmallBIOTest extends OpenSslRenegotiateTest { +- @Override +- protected void initSslServerContext(SslContext context) { +- ((ReferenceCountedOpenSslContext) context).setBioNonApplicationBufferSize(1); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java +deleted file mode 100644 +index 8f3dfee..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java ++++ /dev/null +@@ -1,36 +0,0 @@ +-/* +- * Copyright 2015 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import org.junit.BeforeClass; +- +-import static org.junit.Assume.assumeFalse; +-import static org.junit.Assume.assumeTrue; +- +-public class OpenSslRenegotiateTest extends RenegotiateTest { +- +- @BeforeClass +- public static void checkOpenSsl() { +- assumeTrue(OpenSsl.isAvailable()); +- // BoringSSL does not support renegotiation intentionally. +- assumeFalse("BoringSSL".equals(OpenSsl.versionString())); +- } +- +- @Override +- protected SslProvider serverSslProvider() { +- return SslProvider.OPENSSL; +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java +deleted file mode 100644 +index f22d045..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java ++++ /dev/null +@@ -1,39 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-package io.netty.handler.ssl; +- +-import org.junit.Assume; +-import org.junit.BeforeClass; +- +-import javax.net.ssl.SSLException; +-import java.io.File; +- +-import static org.junit.Assume.assumeTrue; +- +-public class OpenSslServerContextTest extends SslContextTest { +- +- @BeforeClass +- public static void checkOpenSsl() { +- assumeTrue(OpenSsl.isAvailable()); +- } +- +- @Override +- protected SslContext newServerContext(File crtFile, File keyFile, String pass) throws SSLException { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- return new OpenSslServerContext(crtFile, keyFile, pass); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java +deleted file mode 100644 +index 7882a61..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* +- * Copyright 2017 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import static org.junit.Assume.assumeTrue; +- +-final class OpenSslTestUtils { +- private OpenSslTestUtils() { +- } +- +- static void checkShouldUseKeyManagerFactory() { +- assumeTrue(OpenSsl.supportsKeyManagerFactory() && OpenSsl.useKeyManagerFactory()); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java b/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java +deleted file mode 100644 +index 793f772..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java ++++ /dev/null +@@ -1,95 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-package io.netty.handler.ssl; +- +-import static org.junit.Assert.assertEquals; +-import static org.junit.Assert.assertTrue; +-import static org.junit.Assume.assumeFalse; +-import static org.junit.Assume.assumeTrue; +- +-import java.io.ByteArrayOutputStream; +-import java.io.File; +-import java.io.FileInputStream; +- +-import org.junit.Test; +- +-import io.netty.handler.ssl.util.SelfSignedCertificate; +-import io.netty.util.ReferenceCountUtil; +- +-public class PemEncodedTest { +- +- @Test +- public void testPemEncodedOpenSsl() throws Exception { +- testPemEncoded(SslProvider.OPENSSL); +- } +- +- @Test +- public void testPemEncodedOpenSslRef() throws Exception { +- testPemEncoded(SslProvider.OPENSSL_REFCNT); +- } +- +- private static void testPemEncoded(SslProvider provider) throws Exception { +- assumeTrue(OpenSsl.isAvailable()); +- assumeFalse(OpenSsl.useKeyManagerFactory()); +- PemPrivateKey pemKey; +- PemX509Certificate pemCert; +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- try { +- pemKey = PemPrivateKey.valueOf(toByteArray(ssc.privateKey())); +- pemCert = PemX509Certificate.valueOf(toByteArray(ssc.certificate())); +- } finally { +- ssc.delete(); +- } +- +- SslContext context = SslContextBuilder.forServer(pemKey, pemCert) +- .sslProvider(provider) +- .build(); +- assertEquals(1, pemKey.refCnt()); +- assertEquals(1, pemCert.refCnt()); +- try { +- assertTrue(context instanceof ReferenceCountedOpenSslContext); +- } finally { +- ReferenceCountUtil.release(context); +- assertRelease(pemKey); +- assertRelease(pemCert); +- } +- } +- +- private static void assertRelease(PemEncoded encoded) { +- assertTrue(encoded.release()); +- } +- +- private static byte[] toByteArray(File file) throws Exception { +- FileInputStream in = new FileInputStream(file); +- try { +- ByteArrayOutputStream baos = new ByteArrayOutputStream(); +- try { +- byte[] buf = new byte[1024]; +- int len; +- while ((len = in.read(buf)) != -1) { +- baos.write(buf, 0, len); +- } +- } finally { +- baos.close(); +- } +- +- return baos.toByteArray(); +- } finally { +- in.close(); +- } +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java +deleted file mode 100644 +index 6d38940..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java ++++ /dev/null +@@ -1,57 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.util.ReferenceCountUtil; +- +-import javax.net.ssl.SSLEngine; +- +-public class ReferenceCountedOpenSslEngineTest extends OpenSslEngineTest { +- +- public ReferenceCountedOpenSslEngineTest(BufferType type) { +- super(type); +- } +- +- @Override +- protected SslProvider sslClientProvider() { +- return SslProvider.OPENSSL_REFCNT; +- } +- +- @Override +- protected SslProvider sslServerProvider() { +- return SslProvider.OPENSSL_REFCNT; +- } +- +- @Override +- protected void cleanupClientSslContext(SslContext ctx) { +- ReferenceCountUtil.release(ctx); +- } +- +- @Override +- protected void cleanupClientSslEngine(SSLEngine engine) { +- ReferenceCountUtil.release(engine); +- } +- +- @Override +- protected void cleanupServerSslContext(SslContext ctx) { +- ReferenceCountUtil.release(ctx); +- } +- +- @Override +- protected void cleanupServerSslEngine(SSLEngine engine) { +- ReferenceCountUtil.release(engine); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java +deleted file mode 100644 +index 3193d20..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java ++++ /dev/null +@@ -1,161 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.bootstrap.Bootstrap; +-import io.netty.bootstrap.ServerBootstrap; +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.channel.Channel; +-import io.netty.channel.ChannelInitializer; +-import io.netty.channel.DefaultEventLoopGroup; +-import io.netty.channel.EventLoopGroup; +-import io.netty.channel.local.LocalAddress; +-import io.netty.channel.local.LocalChannel; +-import io.netty.channel.local.LocalServerChannel; +-import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +-import io.netty.handler.ssl.util.SelfSignedCertificate; +-import io.netty.util.Mapping; +-import io.netty.util.concurrent.Promise; +-import io.netty.util.internal.PlatformDependent; +-import org.junit.Assert; +-import org.junit.Assume; +-import org.junit.Test; +- +-import java.nio.channels.ClosedChannelException; +- +-public class SniClientTest { +- +- @Test(timeout = 30000) +- public void testSniClientJdkSslServerJdkSsl() throws Exception { +- testSniClient(SslProvider.JDK, SslProvider.JDK); +- } +- +- @Test(timeout = 30000) +- public void testSniClientOpenSslServerOpenSsl() throws Exception { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL); +- } +- +- @Test(timeout = 30000) +- public void testSniClientJdkSslServerOpenSsl() throws Exception { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- testSniClient(SslProvider.JDK, SslProvider.OPENSSL); +- } +- +- @Test(timeout = 30000) +- public void testSniClientOpenSslServerJdkSsl() throws Exception { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- testSniClient(SslProvider.OPENSSL, SslProvider.JDK); +- } +- +- @Test(timeout = 30000) +- public void testSniSNIMatcherMatchesClientJdkSslServerJdkSsl() throws Exception { +- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); +- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, true); +- } +- +- @Test(timeout = 30000, expected = ClosedChannelException.class) +- public void testSniSNIMatcherDoesNotMatchClientJdkSslServerJdkSsl() throws Exception { +- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); +- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, false); +- } +- +- @Test(timeout = 30000) +- public void testSniSNIMatcherMatchesClientOpenSslServerOpenSsl() throws Exception { +- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); +- Assume.assumeTrue(OpenSsl.isAvailable()); +- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL, true); +- } +- +- @Test(timeout = 30000, expected = ClosedChannelException.class) +- public void testSniSNIMatcherDoesNotMatchClientOpenSslServerOpenSsl() throws Exception { +- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); +- Assume.assumeTrue(OpenSsl.isAvailable()); +- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL, false); +- } +- +- @Test(timeout = 30000) +- public void testSniSNIMatcherMatchesClientJdkSslServerOpenSsl() throws Exception { +- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); +- Assume.assumeTrue(OpenSsl.isAvailable()); +- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL, true); +- } +- +- @Test(timeout = 30000, expected = ClosedChannelException.class) +- public void testSniSNIMatcherDoesNotMatchClientJdkSslServerOpenSsl() throws Exception { +- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); +- Assume.assumeTrue(OpenSsl.isAvailable()); +- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL, false); +- } +- +- @Test(timeout = 30000) +- public void testSniSNIMatcherMatchesClientOpenSslServerJdkSsl() throws Exception { +- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); +- Assume.assumeTrue(OpenSsl.isAvailable()); +- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK, true); +- } +- +- @Test(timeout = 30000, expected = ClosedChannelException.class) +- public void testSniSNIMatcherDoesNotMatchClientOpenSslServerJdkSsl() throws Exception { +- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); +- Assume.assumeTrue(OpenSsl.isAvailable()); +- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK, false); +- } +- +- private static void testSniClient(SslProvider sslClientProvider, SslProvider sslServerProvider) throws Exception { +- final String sniHost = "sni.netty.io"; +- LocalAddress address = new LocalAddress("test"); +- EventLoopGroup group = new DefaultEventLoopGroup(1); +- Channel sc = null; +- Channel cc = null; +- try { +- SelfSignedCertificate cert = new SelfSignedCertificate(); +- final SslContext sslServerContext = SslContextBuilder.forServer(cert.key(), cert.cert()) +- .sslProvider(sslServerProvider).build(); +- +- final Promise promise = group.next().newPromise(); +- ServerBootstrap sb = new ServerBootstrap(); +- sc = sb.group(group).channel(LocalServerChannel.class).childHandler(new ChannelInitializer() { +- @Override +- protected void initChannel(Channel ch) throws Exception { +- ch.pipeline().addFirst(new SniHandler(new Mapping() { +- @Override +- public SslContext map(String input) { +- promise.setSuccess(input); +- return sslServerContext; +- } +- })); +- } +- }).bind(address).syncUninterruptibly().channel(); +- +- SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE) +- .sslProvider(sslClientProvider).build(); +- Bootstrap cb = new Bootstrap(); +- cc = cb.group(group).channel(LocalChannel.class).handler(new SslHandler( +- sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost, -1))) +- .connect(address).syncUninterruptibly().channel(); +- Assert.assertEquals(sniHost, promise.syncUninterruptibly().getNow()); +- } finally { +- if (cc != null) { +- cc.close().syncUninterruptibly(); +- } +- if (sc != null) { +- sc.close().syncUninterruptibly(); +- } +- group.shutdownGracefully(); +- } +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java b/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java +deleted file mode 100644 +index 07c87c6..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java ++++ /dev/null +@@ -1,496 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-package io.netty.handler.ssl; +- +-import static org.hamcrest.CoreMatchers.is; +-import static org.hamcrest.CoreMatchers.nullValue; +-import static org.junit.Assert.assertEquals; +-import static org.junit.Assert.assertThat; +-import static org.junit.Assert.assertTrue; +-import static org.junit.Assume.assumeTrue; +- +-import java.io.File; +-import java.net.InetSocketAddress; +-import java.util.ArrayList; +-import java.util.List; +-import java.util.concurrent.CountDownLatch; +-import java.util.concurrent.TimeUnit; +- +-import javax.net.ssl.SSLEngine; +- +-import org.junit.Test; +- +-import io.netty.bootstrap.Bootstrap; +-import io.netty.bootstrap.ServerBootstrap; +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.buffer.Unpooled; +-import io.netty.channel.Channel; +-import io.netty.channel.ChannelFuture; +-import io.netty.channel.ChannelHandlerContext; +-import io.netty.channel.ChannelInitializer; +-import io.netty.channel.ChannelPipeline; +-import io.netty.channel.DefaultEventLoopGroup; +-import io.netty.channel.EventLoopGroup; +-import io.netty.channel.embedded.EmbeddedChannel; +-import io.netty.channel.local.LocalAddress; +-import io.netty.channel.local.LocalChannel; +-import io.netty.channel.local.LocalServerChannel; +-import io.netty.channel.nio.NioEventLoopGroup; +-import io.netty.channel.socket.nio.NioServerSocketChannel; +-import io.netty.channel.socket.nio.NioSocketChannel; +-import io.netty.handler.codec.DecoderException; +-import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +-import io.netty.handler.ssl.util.SelfSignedCertificate; +-import io.netty.util.DomainNameMapping; +-import io.netty.util.DomainNameMappingBuilder; +-import io.netty.util.Mapping; +-import io.netty.util.ReferenceCountUtil; +-import io.netty.util.ReferenceCounted; +-import io.netty.util.concurrent.Promise; +-import io.netty.util.internal.ObjectUtil; +-import io.netty.util.internal.StringUtil; +-import org.junit.runner.RunWith; +-import org.junit.runners.Parameterized; +- +-@RunWith(Parameterized.class) +-public class SniHandlerTest { +- +- private static ApplicationProtocolConfig newApnConfig() { +- return new ApplicationProtocolConfig( +- ApplicationProtocolConfig.Protocol.ALPN, +- // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers. +- ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, +- // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers. +- ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, +- "myprotocol"); +- } +- +- private static void assumeApnSupported(SslProvider provider) { +- switch (provider) { +- case OPENSSL: +- case OPENSSL_REFCNT: +- assumeTrue(OpenSsl.isAlpnSupported()); +- break; +- case JDK: +- assumeTrue(JettyAlpnSslEngine.isAvailable()); +- break; +- default: +- throw new Error(); +- } +- } +- +- private static SslContext makeSslContext(SslProvider provider, boolean apn) throws Exception { +- if (apn) { +- assumeApnSupported(provider); +- } +- +- File keyFile = new File(SniHandlerTest.class.getResource("test_encrypted.pem").getFile()); +- File crtFile = new File(SniHandlerTest.class.getResource("test.crt").getFile()); +- +- SslContextBuilder sslCtxBuilder = SslContextBuilder.forServer(crtFile, keyFile, "12345") +- .sslProvider(provider); +- if (apn) { +- sslCtxBuilder.applicationProtocolConfig(newApnConfig()); +- } +- return sslCtxBuilder.build(); +- } +- +- private static SslContext makeSslClientContext(SslProvider provider, boolean apn) throws Exception { +- if (apn) { +- assumeApnSupported(provider); +- } +- +- File crtFile = new File(SniHandlerTest.class.getResource("test.crt").getFile()); +- +- SslContextBuilder sslCtxBuilder = SslContextBuilder.forClient().trustManager(crtFile).sslProvider(provider); +- if (apn) { +- sslCtxBuilder.applicationProtocolConfig(newApnConfig()); +- } +- return sslCtxBuilder.build(); +- } +- +- @Parameterized.Parameters(name = "{index}: sslProvider={0}") +- public static Iterable data() { +- List params = new ArrayList(3); +- if (OpenSsl.isAvailable()) { +- params.add(SslProvider.OPENSSL); +- params.add(SslProvider.OPENSSL_REFCNT); +- } +- params.add(SslProvider.JDK); +- return params; +- } +- +- private final SslProvider provider; +- +- public SniHandlerTest(SslProvider provider) { +- this.provider = provider; +- } +- +- @Test +- public void testServerNameParsing() throws Exception { +- SslContext nettyContext = makeSslContext(provider, false); +- SslContext leanContext = makeSslContext(provider, false); +- SslContext leanContext2 = makeSslContext(provider, false); +- +- try { +- DomainNameMapping mapping = new DomainNameMappingBuilder(nettyContext) +- .add("*.netty.io", nettyContext) +- // input with custom cases +- .add("*.LEANCLOUD.CN", leanContext) +- // a hostname conflict with previous one, since we are using order-sensitive config, +- // the engine won't be used with the handler. +- .add("chat4.leancloud.cn", leanContext2) +- .build(); +- +- SniHandler handler = new SniHandler(mapping); +- EmbeddedChannel ch = new EmbeddedChannel(handler); +- +- try { +- // hex dump of a client hello packet, which contains hostname "CHAT4.LEANCLOUD.CN" +- String tlsHandshakeMessageHex1 = "16030100"; +- // part 2 +- String tlsHandshakeMessageHex = "c6010000c20303bb0855d66532c05a0ef784f7c384feeafa68b3" + +- "b655ac7288650d5eed4aa3fb52000038c02cc030009fcca9cca8ccaac02b" + +- "c02f009ec024c028006bc023c0270067c00ac0140039c009c0130033009d" + +- "009c003d003c0035002f00ff010000610000001700150000124348415434" + +- "2e4c45414e434c4f55442e434e000b000403000102000a000a0008001d00" + +- "170019001800230000000d0020001e060106020603050105020503040104" + +- "0204030301030203030201020202030016000000170000"; +- +- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1))); +- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex))); +- +- // This should produce an alert +- assertTrue(ch.finish()); +- +- assertThat(handler.hostname(), is("chat4.leancloud.cn")); +- assertThat(handler.sslContext(), is(leanContext)); +- } finally { +- ch.finishAndReleaseAll(); +- } +- } finally { +- releaseAll(leanContext, leanContext2, nettyContext); +- } +- } +- +- @Test(expected = DecoderException.class) +- public void testNonAsciiServerNameParsing() throws Exception { +- SslContext nettyContext = makeSslContext(provider, false); +- SslContext leanContext = makeSslContext(provider, false); +- SslContext leanContext2 = makeSslContext(provider, false); +- +- try { +- DomainNameMapping mapping = new DomainNameMappingBuilder(nettyContext) +- .add("*.netty.io", nettyContext) +- // input with custom cases +- .add("*.LEANCLOUD.CN", leanContext) +- // a hostname conflict with previous one, since we are using order-sensitive config, +- // the engine won't be used with the handler. +- .add("chat4.leancloud.cn", leanContext2) +- .build(); +- +- SniHandler handler = new SniHandler(mapping); +- EmbeddedChannel ch = new EmbeddedChannel(handler); +- +- try { +- // hex dump of a client hello packet, which contains an invalid hostname "CHAT4。LEANCLOUD。CN" +- String tlsHandshakeMessageHex1 = "16030100"; +- // part 2 +- String tlsHandshakeMessageHex = "bd010000b90303a74225676d1814ba57faff3b366" + +- "3656ed05ee9dbb2a4dbb1bb1c32d2ea5fc39e0000000100008c0000001700150000164348" + +- "415434E380824C45414E434C4F5544E38082434E000b000403000102000a00340032000e0" + +- "00d0019000b000c00180009000a0016001700080006000700140015000400050012001300" + +- "0100020003000f0010001100230000000d0020001e0601060206030501050205030401040" + +- "20403030103020303020102020203000f00010133740000"; +- +- // Push the handshake message. +- // Decode should fail because of the badly encoded "HostName" string in the SNI extension +- // that isn't ASCII as per RFC 6066 - https://tools.ietf.org/html/rfc6066#page-6 +- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1))); +- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex))); +- } finally { +- ch.finishAndReleaseAll(); +- } +- } finally { +- releaseAll(leanContext, leanContext2, nettyContext); +- } +- } +- +- @Test +- public void testFallbackToDefaultContext() throws Exception { +- SslContext nettyContext = makeSslContext(provider, false); +- SslContext leanContext = makeSslContext(provider, false); +- SslContext leanContext2 = makeSslContext(provider, false); +- +- try { +- DomainNameMapping mapping = new DomainNameMappingBuilder(nettyContext) +- .add("*.netty.io", nettyContext) +- // input with custom cases +- .add("*.LEANCLOUD.CN", leanContext) +- // a hostname conflict with previous one, since we are using order-sensitive config, +- // the engine won't be used with the handler. +- .add("chat4.leancloud.cn", leanContext2) +- .build(); +- +- SniHandler handler = new SniHandler(mapping); +- EmbeddedChannel ch = new EmbeddedChannel(handler); +- +- // invalid +- byte[] message = {22, 3, 1, 0, 0}; +- +- try { +- // Push the handshake message. +- ch.writeInbound(Unpooled.wrappedBuffer(message)); +- } catch (Exception e) { +- // expected +- } +- +- assertThat(ch.finish(), is(false)); +- assertThat(handler.hostname(), nullValue()); +- assertThat(handler.sslContext(), is(nettyContext)); +- } finally { +- releaseAll(leanContext, leanContext2, nettyContext); +- } +- } +- +- @Test +- public void testSniWithApnHandler() throws Exception { +- SslContext nettyContext = makeSslContext(provider, true); +- SslContext sniContext = makeSslContext(provider, true); +- final SslContext clientContext = makeSslClientContext(provider, true); +- try { +- final CountDownLatch serverApnDoneLatch = new CountDownLatch(1); +- final CountDownLatch clientApnDoneLatch = new CountDownLatch(1); +- +- final DomainNameMapping mapping = new DomainNameMappingBuilder(nettyContext) +- .add("*.netty.io", nettyContext) +- .add("sni.fake.site", sniContext).build(); +- final SniHandler handler = new SniHandler(mapping); +- EventLoopGroup group = new NioEventLoopGroup(2); +- Channel serverChannel = null; +- Channel clientChannel = null; +- try { +- ServerBootstrap sb = new ServerBootstrap(); +- sb.group(group); +- sb.channel(NioServerSocketChannel.class); +- sb.childHandler(new ChannelInitializer() { +- @Override +- protected void initChannel(Channel ch) throws Exception { +- ChannelPipeline p = ch.pipeline(); +- // Server side SNI. +- p.addLast(handler); +- // Catch the notification event that APN has completed successfully. +- p.addLast(new ApplicationProtocolNegotiationHandler("foo") { +- @Override +- protected void configurePipeline(ChannelHandlerContext ctx, String protocol) { +- serverApnDoneLatch.countDown(); +- } +- }); +- } +- }); +- +- Bootstrap cb = new Bootstrap(); +- cb.group(group); +- cb.channel(NioSocketChannel.class); +- cb.handler(new ChannelInitializer() { +- @Override +- protected void initChannel(Channel ch) throws Exception { +- ch.pipeline().addLast(new SslHandler(clientContext.newEngine( +- ch.alloc(), "sni.fake.site", -1))); +- // Catch the notification event that APN has completed successfully. +- ch.pipeline().addLast(new ApplicationProtocolNegotiationHandler("foo") { +- @Override +- protected void configurePipeline(ChannelHandlerContext ctx, String protocol) { +- clientApnDoneLatch.countDown(); +- } +- }); +- } +- }); +- +- serverChannel = sb.bind(new InetSocketAddress(0)).sync().channel(); +- +- ChannelFuture ccf = cb.connect(serverChannel.localAddress()); +- assertTrue(ccf.awaitUninterruptibly().isSuccess()); +- clientChannel = ccf.channel(); +- +- assertTrue(serverApnDoneLatch.await(5, TimeUnit.SECONDS)); +- assertTrue(clientApnDoneLatch.await(5, TimeUnit.SECONDS)); +- assertThat(handler.hostname(), is("sni.fake.site")); +- assertThat(handler.sslContext(), is(sniContext)); +- } finally { +- if (serverChannel != null) { +- serverChannel.close().sync(); +- } +- if (clientChannel != null) { +- clientChannel.close().sync(); +- } +- group.shutdownGracefully(0, 0, TimeUnit.MICROSECONDS); +- } +- } finally { +- releaseAll(clientContext, nettyContext, sniContext); +- } +- } +- +- @Test(timeout = 30000) +- public void testReplaceHandler() throws Exception { +- switch (provider) { +- case OPENSSL: +- case OPENSSL_REFCNT: +- final String sniHost = "sni.netty.io"; +- LocalAddress address = new LocalAddress("testReplaceHandler-" + Math.random()); +- EventLoopGroup group = new DefaultEventLoopGroup(1); +- Channel sc = null; +- Channel cc = null; +- SslContext sslContext = null; +- +- SelfSignedCertificate cert = new SelfSignedCertificate(); +- +- try { +- final SslContext sslServerContext = SslContextBuilder +- .forServer(cert.key(), cert.cert()) +- .sslProvider(provider) +- .build(); +- +- final Mapping mapping = new Mapping() { +- @Override +- public SslContext map(String input) { +- return sslServerContext; +- } +- }; +- +- final Promise releasePromise = group.next().newPromise(); +- +- final SniHandler handler = new SniHandler(mapping) { +- @Override +- protected void replaceHandler(ChannelHandlerContext ctx, +- String hostname, final SslContext sslContext) +- throws Exception { +- +- boolean success = false; +- try { +- // The SniHandler's replaceHandler() method allows us to implement custom behavior. +- // As an example, we want to release() the SslContext upon channelInactive() or rather +- // when the SslHandler closes it's SslEngine. If you take a close look at SslHandler +- // you'll see that it's doing it in the #handlerRemoved0() method. +- +- SSLEngine sslEngine = sslContext.newEngine(ctx.alloc()); +- try { +- SslHandler customSslHandler = new CustomSslHandler(sslContext, sslEngine) { +- @Override +- public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { +- try { +- super.handlerRemoved0(ctx); +- } finally { +- releasePromise.trySuccess(null); +- } +- } +- }; +- ctx.pipeline().replace(this, CustomSslHandler.class.getName(), customSslHandler); +- success = true; +- } finally { +- if (!success) { +- ReferenceCountUtil.safeRelease(sslEngine); +- } +- } +- } finally { +- if (!success) { +- ReferenceCountUtil.safeRelease(sslContext); +- releasePromise.cancel(true); +- } +- } +- } +- }; +- +- ServerBootstrap sb = new ServerBootstrap(); +- sc = sb.group(group).channel(LocalServerChannel.class) +- .childHandler(new ChannelInitializer() { +- @Override +- protected void initChannel(Channel ch) throws Exception { +- ch.pipeline().addFirst(handler); +- } +- }).bind(address).syncUninterruptibly().channel(); +- +- sslContext = SslContextBuilder.forClient().sslProvider(provider) +- .trustManager(InsecureTrustManagerFactory.INSTANCE).build(); +- +- Bootstrap cb = new Bootstrap(); +- cc = cb.group(group).channel(LocalChannel.class).handler(new SslHandler( +- sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost, -1))) +- .connect(address).syncUninterruptibly().channel(); +- +- cc.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes())) +- .syncUninterruptibly(); +- +- // Notice how the server's SslContext refCnt is 1 +- assertEquals(1, ((ReferenceCounted) sslServerContext).refCnt()); +- +- // The client disconnects +- cc.close().syncUninterruptibly(); +- if (!releasePromise.awaitUninterruptibly(10L, TimeUnit.SECONDS)) { +- throw new IllegalStateException("It doesn't seem #replaceHandler() got called."); +- } +- +- // We should have successfully release() the SslContext +- assertEquals(0, ((ReferenceCounted) sslServerContext).refCnt()); +- } finally { +- if (cc != null) { +- cc.close().syncUninterruptibly(); +- } +- if (sc != null) { +- sc.close().syncUninterruptibly(); +- } +- if (sslContext != null) { +- ReferenceCountUtil.release(sslContext); +- } +- group.shutdownGracefully(); +- +- cert.delete(); +- } +- case JDK: +- return; +- default: +- throw new Error(); +- } +- } +- +- /** +- * This is a {@link SslHandler} that will call {@code release()} on the {@link SslContext} when +- * the client disconnects. +- * +- * @see SniHandlerTest#testReplaceHandler() +- */ +- private static class CustomSslHandler extends SslHandler { +- private final SslContext sslContext; +- +- public CustomSslHandler(SslContext sslContext, SSLEngine sslEngine) { +- super(sslEngine); +- this.sslContext = ObjectUtil.checkNotNull(sslContext, "sslContext"); +- } +- +- @Override +- public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { +- super.handlerRemoved0(ctx); +- ReferenceCountUtil.release(sslContext); +- } +- } +- +- private static void releaseAll(SslContext... contexts) { +- for (SslContext ctx: contexts) { +- ReferenceCountUtil.release(ctx); +- } +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java b/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java +deleted file mode 100644 +index 752424c..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java ++++ /dev/null +@@ -1,132 +0,0 @@ +-/* +- * Copyright 2015 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import static org.junit.Assert.assertFalse; +-import static org.junit.Assert.assertTrue; +- +-import io.netty.buffer.UnpooledByteBufAllocator; +-import io.netty.handler.ssl.util.SelfSignedCertificate; +-import org.junit.Assume; +-import org.junit.Test; +- +-import javax.net.ssl.SSLEngine; +- +-public class SslContextBuilderTest { +- +- @Test +- public void testClientContextFromFileJdk() throws Exception { +- testClientContextFromFile(SslProvider.JDK); +- } +- +- @Test +- public void testClientContextFromFileOpenssl() throws Exception { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- testClientContextFromFile(SslProvider.OPENSSL); +- } +- +- @Test +- public void testClientContextJdk() throws Exception { +- testClientContext(SslProvider.JDK); +- } +- +- @Test +- public void testClientContextOpenssl() throws Exception { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- testClientContext(SslProvider.OPENSSL); +- } +- +- @Test +- public void testServerContextFromFileJdk() throws Exception { +- testServerContextFromFile(SslProvider.JDK); +- } +- +- @Test +- public void testServerContextFromFileOpenssl() throws Exception { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- testServerContextFromFile(SslProvider.OPENSSL); +- } +- +- @Test +- public void testServerContextJdk() throws Exception { +- testServerContext(SslProvider.JDK); +- } +- +- @Test +- public void testServerContextOpenssl() throws Exception { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- testServerContext(SslProvider.OPENSSL); +- } +- +- private static void testClientContextFromFile(SslProvider provider) throws Exception { +- SelfSignedCertificate cert = new SelfSignedCertificate(); +- SslContextBuilder builder = SslContextBuilder.forClient() +- .sslProvider(provider) +- .keyManager(cert.certificate(), +- cert.privateKey()) +- .trustManager(cert.certificate()) +- .clientAuth(ClientAuth.OPTIONAL); +- SslContext context = builder.build(); +- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); +- assertFalse(engine.getWantClientAuth()); +- assertFalse(engine.getNeedClientAuth()); +- engine.closeInbound(); +- engine.closeOutbound(); +- } +- +- private static void testClientContext(SslProvider provider) throws Exception { +- SelfSignedCertificate cert = new SelfSignedCertificate(); +- SslContextBuilder builder = SslContextBuilder.forClient() +- .sslProvider(provider) +- .keyManager(cert.key(), cert.cert()) +- .trustManager(cert.cert()) +- .clientAuth(ClientAuth.OPTIONAL); +- SslContext context = builder.build(); +- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); +- assertFalse(engine.getWantClientAuth()); +- assertFalse(engine.getNeedClientAuth()); +- engine.closeInbound(); +- engine.closeOutbound(); +- } +- +- private static void testServerContextFromFile(SslProvider provider) throws Exception { +- SelfSignedCertificate cert = new SelfSignedCertificate(); +- SslContextBuilder builder = SslContextBuilder.forServer(cert.certificate(), cert.privateKey()) +- .sslProvider(provider) +- .trustManager(cert.certificate()) +- .clientAuth(ClientAuth.OPTIONAL); +- SslContext context = builder.build(); +- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); +- assertTrue(engine.getWantClientAuth()); +- assertFalse(engine.getNeedClientAuth()); +- engine.closeInbound(); +- engine.closeOutbound(); +- } +- +- private static void testServerContext(SslProvider provider) throws Exception { +- SelfSignedCertificate cert = new SelfSignedCertificate(); +- SslContextBuilder builder = SslContextBuilder.forServer(cert.key(), cert.cert()) +- .sslProvider(provider) +- .trustManager(cert.cert()) +- .clientAuth(ClientAuth.REQUIRE); +- SslContext context = builder.build(); +- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); +- assertFalse(engine.getWantClientAuth()); +- assertTrue(engine.getNeedClientAuth()); +- engine.closeInbound(); +- engine.closeOutbound(); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java b/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java +deleted file mode 100644 +index aacdb69..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java ++++ /dev/null +@@ -1,255 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import io.netty.bootstrap.Bootstrap; +-import io.netty.bootstrap.ServerBootstrap; +-import io.netty.channel.Channel; +-import io.netty.channel.ChannelHandlerContext; +-import io.netty.channel.ChannelInboundHandlerAdapter; +-import io.netty.channel.ChannelInitializer; +-import io.netty.channel.EventLoopGroup; +-import io.netty.channel.nio.NioEventLoopGroup; +-import io.netty.channel.socket.nio.NioServerSocketChannel; +-import io.netty.channel.socket.nio.NioSocketChannel; +-import io.netty.handler.logging.LogLevel; +-import io.netty.handler.logging.LoggingHandler; +-import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +-import io.netty.handler.ssl.util.SelfSignedCertificate; +-import io.netty.handler.ssl.util.SimpleTrustManagerFactory; +-import io.netty.util.ReferenceCountUtil; +-import io.netty.util.concurrent.Promise; +-import io.netty.util.internal.EmptyArrays; +-import org.junit.Assume; +-import org.junit.Test; +-import org.junit.runner.RunWith; +-import org.junit.runners.Parameterized; +- +-import javax.net.ssl.ManagerFactoryParameters; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.TrustManager; +-import javax.net.ssl.X509TrustManager; +-import javax.security.auth.x500.X500Principal; +-import java.io.File; +-import java.security.KeyStore; +-import java.security.cert.CRLReason; +-import java.security.cert.CertPathValidatorException; +-import java.security.cert.CertificateException; +-import java.security.cert.CertificateExpiredException; +-import java.security.cert.CertificateNotYetValidException; +-import java.security.cert.CertificateRevokedException; +-import java.security.cert.Extension; +-import java.security.cert.X509Certificate; +-import java.util.ArrayList; +-import java.util.Collection; +-import java.util.Collections; +-import java.util.Date; +-import java.util.List; +-import java.util.Locale; +- +- +-@RunWith(Parameterized.class) +-public class SslErrorTest { +- +- @Parameterized.Parameters(name = "{index}: serverProvider = {0}, clientProvider = {1}, exception = {2}") +- public static Collection data() { +- List serverProviders = new ArrayList(2); +- List clientProviders = new ArrayList(3); +- +- if (OpenSsl.isAvailable()) { +- serverProviders.add(SslProvider.OPENSSL); +- serverProviders.add(SslProvider.OPENSSL_REFCNT); +- clientProviders.add(SslProvider.OPENSSL); +- clientProviders.add(SslProvider.OPENSSL_REFCNT); +- } +- // We not test with SslProvider.JDK on the server side as the JDK implementation currently just send the same +- // alert all the time, sigh..... +- clientProviders.add(SslProvider.JDK); +- +- List exceptions = new ArrayList(6); +- exceptions.add(new CertificateExpiredException()); +- exceptions.add(new CertificateNotYetValidException()); +- exceptions.add(new CertificateRevokedException( +- new Date(), CRLReason.AA_COMPROMISE, new X500Principal(""), +- Collections.emptyMap())); +- +- // Also use wrapped exceptions as this is what the JDK implementation of X509TrustManagerFactory is doing. +- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.EXPIRED)); +- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.NOT_YET_VALID)); +- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.REVOKED)); +- +- List params = new ArrayList(); +- for (SslProvider serverProvider: serverProviders) { +- for (SslProvider clientProvider: clientProviders) { +- for (CertificateException exception: exceptions) { +- params.add(new Object[] { serverProvider, clientProvider, exception}); +- } +- } +- } +- return params; +- } +- +- private static CertificateException newCertificateException(CertPathValidatorException.Reason reason) { +- return new TestCertificateException( +- new CertPathValidatorException("x", null, null, -1, reason)); +- } +- +- private final SslProvider serverProvider; +- private final SslProvider clientProvider; +- private final CertificateException exception; +- +- public SslErrorTest(SslProvider serverProvider, SslProvider clientProvider, CertificateException exception) { +- this.serverProvider = serverProvider; +- this.clientProvider = clientProvider; +- this.exception = exception; +- } +- +- @Test(timeout = 30000) +- public void testCorrectAlert() throws Exception { +- // As this only works correctly at the moment when OpenSslEngine is used on the server-side there is +- // no need to run it if there is no openssl is available at all. +- Assume.assumeTrue(OpenSsl.isAvailable()); +- +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- final SslContext sslServerCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(serverProvider) +- .trustManager(new SimpleTrustManagerFactory() { +- @Override +- protected void engineInit(KeyStore keyStore) { } +- @Override +- protected void engineInit(ManagerFactoryParameters managerFactoryParameters) { } +- +- @Override +- protected TrustManager[] engineGetTrustManagers() { +- return new TrustManager[] { new X509TrustManager() { +- +- @Override +- public void checkClientTrusted(X509Certificate[] x509Certificates, String s) +- throws CertificateException { +- throw exception; +- } +- +- @Override +- public void checkServerTrusted(X509Certificate[] x509Certificates, String s) +- throws CertificateException { +- // NOOP +- } +- +- @Override +- public X509Certificate[] getAcceptedIssuers() { +- return EmptyArrays.EMPTY_X509_CERTIFICATES; +- } +- } }; +- } +- }).clientAuth(ClientAuth.REQUIRE).build(); +- +- final SslContext sslClientCtx = SslContextBuilder.forClient() +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .keyManager(new File(getClass().getResource("test.crt").getFile()), +- new File(getClass().getResource("test_unencrypted.pem").getFile())) +- .sslProvider(clientProvider).build(); +- +- Channel serverChannel = null; +- Channel clientChannel = null; +- EventLoopGroup group = new NioEventLoopGroup(); +- try { +- serverChannel = new ServerBootstrap().group(group) +- .channel(NioServerSocketChannel.class) +- .handler(new LoggingHandler(LogLevel.INFO)) +- .childHandler(new ChannelInitializer() { +- @Override +- protected void initChannel(Channel ch) throws Exception { +- ch.pipeline().addLast(sslServerCtx.newHandler(ch.alloc())); +- ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { +- +- @Override +- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { +- ctx.close(); +- } +- }); +- } +- }).bind(0).sync().channel(); +- +- final Promise promise = group.next().newPromise(); +- +- clientChannel = new Bootstrap().group(group) +- .channel(NioSocketChannel.class) +- .handler(new ChannelInitializer() { +- @Override +- protected void initChannel(Channel ch) throws Exception { +- ch.pipeline().addLast(sslClientCtx.newHandler(ch.alloc())); +- ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { +- @Override +- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { +- // Unwrap as its wrapped by a DecoderException +- Throwable unwrappedCause = cause.getCause(); +- if (unwrappedCause instanceof SSLException) { +- if (exception instanceof TestCertificateException) { +- CertPathValidatorException.Reason reason = +- ((CertPathValidatorException) exception.getCause()).getReason(); +- if (reason == CertPathValidatorException.BasicReason.EXPIRED) { +- verifyException(unwrappedCause, "expired", promise); +- } else if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) { +- verifyException(unwrappedCause, "bad", promise); +- } else if (reason == CertPathValidatorException.BasicReason.REVOKED) { +- verifyException(unwrappedCause, "revoked", promise); +- } +- } else if (exception instanceof CertificateExpiredException) { +- verifyException(unwrappedCause, "expired", promise); +- } else if (exception instanceof CertificateNotYetValidException) { +- verifyException(unwrappedCause, "bad", promise); +- } else if (exception instanceof CertificateRevokedException) { +- verifyException(unwrappedCause, "revoked", promise); +- } +- } +- } +- }); +- } +- }).connect(serverChannel.localAddress()).syncUninterruptibly().channel(); +- // Block until we received the correct exception +- promise.syncUninterruptibly(); +- } finally { +- if (clientChannel != null) { +- clientChannel.close().syncUninterruptibly(); +- } +- if (serverChannel != null) { +- serverChannel.close().syncUninterruptibly(); +- } +- group.shutdownGracefully(); +- +- ReferenceCountUtil.release(sslServerCtx); +- ReferenceCountUtil.release(sslClientCtx); +- } +- } +- +- // Its a bit hacky to verify against the message that is part of the exception but there is no other way +- // at the moment as there are no different exceptions for the different alerts. +- private static void verifyException(Throwable cause, String messagePart, Promise promise) { +- String message = cause.getMessage(); +- if (message.toLowerCase(Locale.UK).contains(messagePart.toLowerCase(Locale.UK))) { +- promise.setSuccess(null); +- } else { +- promise.setFailure(new AssertionError("message not contains '" + messagePart + "': " + message)); +- } +- } +- +- private static final class TestCertificateException extends CertificateException { +- +- public TestCertificateException(Throwable cause) { +- super(cause); +- } +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java +index 5ef43de..52c4d22 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java ++++ b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java +@@ -121,35 +121,6 @@ public class SslHandlerTest { + } + } + +- @Test +- public void testReleaseSslEngine() throws Exception { +- assumeTrue(OpenSsl.isAvailable()); +- +- SelfSignedCertificate cert = new SelfSignedCertificate(); +- try { +- SslContext sslContext = SslContextBuilder.forServer(cert.certificate(), cert.privateKey()) +- .sslProvider(SslProvider.OPENSSL) +- .build(); +- try { +- SSLEngine sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT); +- EmbeddedChannel ch = new EmbeddedChannel(new SslHandler(sslEngine)); +- +- assertEquals(1, ((ReferenceCounted) sslContext).refCnt()); +- assertEquals(1, ((ReferenceCounted) sslEngine).refCnt()); +- +- assertTrue(ch.finishAndReleaseAll()); +- ch.close().syncUninterruptibly(); +- +- assertEquals(1, ((ReferenceCounted) sslContext).refCnt()); +- assertEquals(0, ((ReferenceCounted) sslEngine).refCnt()); +- } finally { +- ReferenceCountUtil.release(sslContext); +- } +- } finally { +- cert.delete(); +- } +- } +- + private static final class TlsReadTest extends ChannelOutboundHandlerAdapter { + private volatile boolean readIssued; + +@@ -279,13 +250,6 @@ public class SslHandlerTest { + testAlertProducedAndSend(SslProvider.JDK); + } + +- @Test(timeout = 30000) +- public void testAlertProducedAndSendOpenSsl() throws Exception { +- assumeTrue(OpenSsl.isAvailable()); +- testAlertProducedAndSend(SslProvider.OPENSSL); +- testAlertProducedAndSend(SslProvider.OPENSSL_REFCNT); +- } +- + private void testAlertProducedAndSend(SslProvider provider) throws Exception { + SelfSignedCertificate ssc = new SelfSignedCertificate(); + +@@ -425,12 +389,6 @@ public class SslHandlerTest { + testCloseNotify(SslProvider.JDK, 5000, false); + } + +- @Test(timeout = 30000) +- public void testCloseNotifyReceivedOpenSsl() throws Exception { +- assumeTrue(OpenSsl.isAvailable()); +- testCloseNotify(SslProvider.OPENSSL, 5000, false); +- testCloseNotify(SslProvider.OPENSSL_REFCNT, 5000, false); +- } + + @Test(timeout = 30000) + public void testCloseNotifyReceivedJdkTimeout() throws Exception { +@@ -438,24 +396,10 @@ public class SslHandlerTest { + } + + @Test(timeout = 30000) +- public void testCloseNotifyReceivedOpenSslTimeout() throws Exception { +- assumeTrue(OpenSsl.isAvailable()); +- testCloseNotify(SslProvider.OPENSSL, 100, true); +- testCloseNotify(SslProvider.OPENSSL_REFCNT, 100, true); +- } +- +- @Test(timeout = 30000) + public void testCloseNotifyNotWaitForResponseJdk() throws Exception { + testCloseNotify(SslProvider.JDK, 0, false); + } + +- @Test(timeout = 30000) +- public void testCloseNotifyNotWaitForResponseOpenSsl() throws Exception { +- assumeTrue(OpenSsl.isAvailable()); +- testCloseNotify(SslProvider.OPENSSL, 0, false); +- testCloseNotify(SslProvider.OPENSSL_REFCNT, 0, false); +- } +- + private static void testCloseNotify(SslProvider provider, final long closeNotifyReadTimeout, final boolean timeout) + throws Exception { + SelfSignedCertificate ssc = new SelfSignedCertificate(); +@@ -720,7 +664,7 @@ public class SslHandlerTest { + switch (provider) { + case OPENSSL: + case OPENSSL_REFCNT: +- return OpenSsl.isAvailable(); ++ return false; + default: + return true; + } +diff --git a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java b/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java +deleted file mode 100644 +index 4aecc74..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java ++++ /dev/null +@@ -1,501 +0,0 @@ +-/* +- * Copyright 2017 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-package io.netty.handler.ssl.ocsp; +- +-import io.netty.bootstrap.Bootstrap; +-import io.netty.bootstrap.ServerBootstrap; +-import io.netty.buffer.ByteBufAllocator; +-import io.netty.buffer.Unpooled; +-import io.netty.channel.Channel; +-import io.netty.channel.ChannelHandler; +-import io.netty.channel.ChannelHandlerContext; +-import io.netty.channel.ChannelInboundHandlerAdapter; +-import io.netty.channel.ChannelInitializer; +-import io.netty.channel.ChannelPipeline; +-import io.netty.channel.DefaultEventLoopGroup; +-import io.netty.channel.EventLoopGroup; +-import io.netty.channel.local.LocalAddress; +-import io.netty.channel.local.LocalChannel; +-import io.netty.channel.local.LocalServerChannel; +-import io.netty.handler.ssl.OpenSsl; +-import io.netty.handler.ssl.ReferenceCountedOpenSslEngine; +-import io.netty.handler.ssl.SslContext; +-import io.netty.handler.ssl.SslContextBuilder; +-import io.netty.handler.ssl.SslHandler; +-import io.netty.handler.ssl.SslProvider; +-import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +-import io.netty.handler.ssl.util.SelfSignedCertificate; +-import io.netty.util.CharsetUtil; +-import io.netty.util.ReferenceCountUtil; +- +-import java.net.SocketAddress; +-import java.util.concurrent.CountDownLatch; +-import java.util.concurrent.TimeUnit; +-import java.util.concurrent.TimeoutException; +-import java.util.concurrent.atomic.AtomicReference; +- +-import javax.net.ssl.SSLHandshakeException; +- +-import org.junit.BeforeClass; +-import org.junit.Test; +- +-import static org.junit.Assert.assertArrayEquals; +-import static org.junit.Assert.assertNotNull; +-import static org.junit.Assert.assertNotSame; +-import static org.junit.Assert.assertNull; +-import static org.junit.Assert.assertSame; +-import static org.junit.Assert.assertTrue; +-import static org.junit.Assume.assumeTrue; +- +-public class OcspTest { +- +- @BeforeClass +- public static void checkOcspSupported() { +- assumeTrue(OpenSsl.isOcspSupported()); +- } +- +- @Test(expected = IllegalArgumentException.class) +- public void testJdkClientEnableOcsp() throws Exception { +- SslContextBuilder.forClient() +- .sslProvider(SslProvider.JDK) +- .enableOcsp(true) +- .build(); +- } +- +- @Test(expected = IllegalArgumentException.class) +- public void testJdkServerEnableOcsp() throws Exception { +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- try { +- SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(SslProvider.JDK) +- .enableOcsp(true) +- .build(); +- } finally { +- ssc.delete(); +- } +- } +- +- @Test(expected = IllegalStateException.class) +- public void testClientOcspNotEnabledOpenSsl() throws Exception { +- testClientOcspNotEnabled(SslProvider.OPENSSL); +- } +- +- @Test(expected = IllegalStateException.class) +- public void testClientOcspNotEnabledOpenSslRefCnt() throws Exception { +- testClientOcspNotEnabled(SslProvider.OPENSSL_REFCNT); +- } +- +- private void testClientOcspNotEnabled(SslProvider sslProvider) throws Exception { +- SslContext context = SslContextBuilder.forClient() +- .sslProvider(sslProvider) +- .build(); +- try { +- SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT); +- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); +- try { +- engine.getOcspResponse(); +- } finally { +- engine.release(); +- } +- } finally { +- ReferenceCountUtil.release(context); +- } +- } +- +- @Test(expected = IllegalStateException.class) +- public void testServerOcspNotEnabledOpenSsl() throws Exception { +- testServerOcspNotEnabled(SslProvider.OPENSSL); +- } +- +- @Test(expected = IllegalStateException.class) +- public void testServerOcspNotEnabledOpenSslRefCnt() throws Exception { +- testServerOcspNotEnabled(SslProvider.OPENSSL_REFCNT); +- } +- +- private void testServerOcspNotEnabled(SslProvider sslProvider) throws Exception { +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- try { +- SslContext context = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslProvider) +- .build(); +- try { +- SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT); +- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); +- try { +- engine.setOcspResponse(new byte[] { 1, 2, 3 }); +- } finally { +- engine.release(); +- } +- } finally { +- ReferenceCountUtil.release(context); +- } +- } finally { +- ssc.delete(); +- } +- } +- +- @Test(timeout = 10000L) +- public void testClientAcceptingOcspStapleOpenSsl() throws Exception { +- testClientAcceptingOcspStaple(SslProvider.OPENSSL); +- } +- +- @Test(timeout = 10000L) +- public void testClientAcceptingOcspStapleOpenSslRefCnt() throws Exception { +- testClientAcceptingOcspStaple(SslProvider.OPENSSL_REFCNT); +- } +- +- /** +- * The Server provides an OCSP staple and the Client accepts it. +- */ +- private void testClientAcceptingOcspStaple(SslProvider sslProvider) throws Exception { +- final CountDownLatch latch = new CountDownLatch(1); +- ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter() { +- @Override +- public void channelActive(ChannelHandlerContext ctx) throws Exception { +- ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes())); +- ctx.fireChannelActive(); +- } +- }; +- +- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { +- @Override +- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { +- try { +- ReferenceCountUtil.release(msg); +- } finally { +- latch.countDown(); +- } +- } +- }; +- +- byte[] response = newOcspResponse(); +- TestClientOcspContext callback = new TestClientOcspContext(true); +- +- handshake(sslProvider, latch, serverHandler, response, clientHandler, callback); +- +- byte[] actual = callback.response(); +- +- assertNotNull(actual); +- assertNotSame(response, actual); +- assertArrayEquals(response, actual); +- } +- +- @Test(timeout = 10000L) +- public void testClientRejectingOcspStapleOpenSsl() throws Exception { +- testClientRejectingOcspStaple(SslProvider.OPENSSL); +- } +- +- @Test(timeout = 10000L) +- public void testClientRejectingOcspStapleOpenSslRefCnt() throws Exception { +- testClientRejectingOcspStaple(SslProvider.OPENSSL_REFCNT); +- } +- +- /** +- * The Server provides an OCSP staple and the Client rejects it. +- */ +- private void testClientRejectingOcspStaple(SslProvider sslProvider) throws Exception { +- final AtomicReference causeRef = new AtomicReference(); +- final CountDownLatch latch = new CountDownLatch(1); +- +- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { +- @Override +- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { +- try { +- causeRef.set(cause); +- } finally { +- latch.countDown(); +- } +- } +- }; +- +- byte[] response = newOcspResponse(); +- TestClientOcspContext callback = new TestClientOcspContext(false); +- +- handshake(sslProvider, latch, null, response, clientHandler, callback); +- +- byte[] actual = callback.response(); +- +- assertNotNull(actual); +- assertNotSame(response, actual); +- assertArrayEquals(response, actual); +- +- Throwable cause = causeRef.get(); +- assertTrue("" + cause, cause instanceof SSLHandshakeException); +- } +- +- @Test(timeout = 10000L) +- public void testServerHasNoStapleOpenSsl() throws Exception { +- testServerHasNoStaple(SslProvider.OPENSSL); +- } +- +- @Test(timeout = 10000L) +- public void testServerHasNoStapleOpenSslRefCnt() throws Exception { +- testServerHasNoStaple(SslProvider.OPENSSL_REFCNT); +- } +- +- /** +- * The server has OCSP stapling enabled but doesn't provide a staple. +- */ +- private void testServerHasNoStaple(SslProvider sslProvider) throws Exception { +- final CountDownLatch latch = new CountDownLatch(1); +- ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter() { +- @Override +- public void channelActive(ChannelHandlerContext ctx) throws Exception { +- ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes())); +- ctx.fireChannelActive(); +- } +- }; +- +- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { +- @Override +- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { +- try { +- ReferenceCountUtil.release(msg); +- } finally { +- latch.countDown(); +- } +- } +- }; +- +- byte[] response = null; +- TestClientOcspContext callback = new TestClientOcspContext(true); +- +- handshake(sslProvider, latch, serverHandler, response, clientHandler, callback); +- +- byte[] actual = callback.response(); +- +- assertNull(response); +- assertNull(actual); +- } +- +- @Test(timeout = 10000L) +- public void testClientExceptionOpenSsl() throws Exception { +- testClientException(SslProvider.OPENSSL); +- } +- +- @Test(timeout = 10000L) +- public void testClientExceptionOpenSslRefCnt() throws Exception { +- testClientException(SslProvider.OPENSSL_REFCNT); +- } +- +- /** +- * Testing what happens if the {@link OcspClientCallback} throws an {@link Exception}. +- * +- * The exception should bubble up on the client side and the connection should get closed. +- */ +- private void testClientException(SslProvider sslProvider) throws Exception { +- final AtomicReference causeRef = new AtomicReference(); +- final CountDownLatch latch = new CountDownLatch(1); +- +- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { +- @Override +- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { +- try { +- causeRef.set(cause); +- } finally { +- latch.countDown(); +- } +- } +- }; +- +- final OcspTestException clientException = new OcspTestException("testClientException"); +- byte[] response = newOcspResponse(); +- OcspClientCallback callback = new OcspClientCallback() { +- @Override +- public boolean verify(byte[] response) throws Exception { +- throw clientException; +- } +- }; +- +- handshake(sslProvider, latch, null, response, clientHandler, callback); +- +- assertSame(clientException, causeRef.get()); +- } +- +- private static void handshake(SslProvider sslProvider, CountDownLatch latch, ChannelHandler serverHandler, +- byte[] response, ChannelHandler clientHandler, OcspClientCallback callback) throws Exception { +- +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- try { +- SslContext serverSslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) +- .sslProvider(sslProvider) +- .enableOcsp(true) +- .build(); +- +- try { +- SslContext clientSslContext = SslContextBuilder.forClient() +- .sslProvider(sslProvider) +- .enableOcsp(true) +- .trustManager(InsecureTrustManagerFactory.INSTANCE) +- .build(); +- +- try { +- EventLoopGroup group = new DefaultEventLoopGroup(); +- try { +- LocalAddress address = new LocalAddress("handshake-" + Math.random()); +- Channel server = newServer(group, address, serverSslContext, response, serverHandler); +- Channel client = newClient(group, address, clientSslContext, callback, clientHandler); +- try { +- assertTrue("Something went wrong.", latch.await(10L, TimeUnit.SECONDS)); +- } finally { +- client.close().syncUninterruptibly(); +- server.close().syncUninterruptibly(); +- } +- } finally { +- group.shutdownGracefully(1L, 1L, TimeUnit.SECONDS); +- } +- } finally { +- ReferenceCountUtil.release(clientSslContext); +- } +- } finally { +- ReferenceCountUtil.release(serverSslContext); +- } +- } finally { +- ssc.delete(); +- } +- } +- +- private static Channel newServer(EventLoopGroup group, SocketAddress address, +- SslContext context, byte[] response, ChannelHandler handler) { +- +- ServerBootstrap bootstrap = new ServerBootstrap() +- .channel(LocalServerChannel.class) +- .group(group) +- .childHandler(newServerHandler(context, response, handler)); +- +- return bootstrap.bind(address) +- .syncUninterruptibly() +- .channel(); +- } +- +- private static Channel newClient(EventLoopGroup group, SocketAddress address, +- SslContext context, OcspClientCallback callback, ChannelHandler handler) { +- +- Bootstrap bootstrap = new Bootstrap() +- .channel(LocalChannel.class) +- .group(group) +- .handler(newClientHandler(context, callback, handler)); +- +- return bootstrap.connect(address) +- .syncUninterruptibly() +- .channel(); +- } +- +- private static ChannelHandler newServerHandler(final SslContext context, +- final byte[] response, final ChannelHandler handler) { +- return new ChannelInitializer() { +- @Override +- protected void initChannel(Channel ch) throws Exception { +- ChannelPipeline pipeline = ch.pipeline(); +- SslHandler sslHandler = context.newHandler(ch.alloc()); +- +- if (response != null) { +- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); +- engine.setOcspResponse(response); +- } +- +- pipeline.addLast(sslHandler); +- +- if (handler != null) { +- pipeline.addLast(handler); +- } +- } +- }; +- } +- +- private static ChannelHandler newClientHandler(final SslContext context, +- final OcspClientCallback callback, final ChannelHandler handler) { +- return new ChannelInitializer() { +- @Override +- protected void initChannel(Channel ch) throws Exception { +- ChannelPipeline pipeline = ch.pipeline(); +- +- SslHandler sslHandler = context.newHandler(ch.alloc()); +- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); +- +- pipeline.addLast(sslHandler); +- pipeline.addLast(new OcspClientCallbackHandler(engine, callback)); +- +- if (handler != null) { +- pipeline.addLast(handler); +- } +- } +- }; +- } +- +- private static byte[] newOcspResponse() { +- // Assume we got the OCSP staple from somewhere. Using a bogus byte[] +- // in the test because getting a true staple from the CA is quite involved. +- // It requires HttpCodec and Bouncycastle and the test may be very unreliable +- // because the OCSP responder servers are basically being DDoS'd by the +- // Internet. +- +- return "I am a bogus OCSP staple. OpenSSL does not care about the format of the byte[]!" +- .getBytes(CharsetUtil.US_ASCII); +- } +- +- private interface OcspClientCallback { +- boolean verify(byte[] staple) throws Exception; +- } +- +- private static final class TestClientOcspContext implements OcspClientCallback { +- +- private final CountDownLatch latch = new CountDownLatch(1); +- private final boolean valid; +- +- private volatile byte[] response; +- +- public TestClientOcspContext(boolean valid) { +- this.valid = valid; +- } +- +- public byte[] response() throws InterruptedException, TimeoutException { +- assertTrue(latch.await(10L, TimeUnit.SECONDS)); +- return response; +- } +- +- @Override +- public boolean verify(byte[] response) throws Exception { +- this.response = response; +- latch.countDown(); +- +- return valid; +- } +- } +- +- private static final class OcspClientCallbackHandler extends OcspClientHandler { +- +- private final OcspClientCallback callback; +- +- public OcspClientCallbackHandler(ReferenceCountedOpenSslEngine engine, OcspClientCallback callback) { +- super(engine); +- this.callback = callback; +- } +- +- @Override +- protected boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception { +- byte[] response = engine.getOcspResponse(); +- return callback.verify(response); +- } +- } +- +- private static final class OcspTestException extends IllegalStateException { +- public OcspTestException(String message) { +- super(message); +- } +- } +-} +-- +2.9.4 + diff --git a/SOURCES/0002-Remove-NPN.patch b/SOURCES/0002-Remove-NPN.patch new file mode 100644 index 0000000..77a340a --- /dev/null +++ b/SOURCES/0002-Remove-NPN.patch @@ -0,0 +1,353 @@ +From f7b8e27b5f55c4a21cf84fb56a616b8bfd4af8da Mon Sep 17 00:00:00 2001 +From: Michael Simacek +Date: Fri, 7 Jul 2017 16:07:23 +0200 +Subject: [PATCH 2/3] Remove NPN + +--- + handler/pom.xml | 5 - + .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 -------------------- + .../java/io/netty/handler/ssl/JdkSslContext.java | 30 ----- + .../io/netty/handler/ssl/JettyNpnSslEngine.java | 122 --------------------- + .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +- + 5 files changed, 1 insertion(+), 278 deletions(-) + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java + +diff --git a/handler/pom.xml b/handler/pom.xml +index d0ed1bc..52e63ca 100644 +--- a/handler/pom.xml ++++ b/handler/pom.xml +@@ -55,11 +55,6 @@ + true + + +- org.eclipse.jetty.npn +- npn-api +- true +- +- + org.eclipse.jetty.alpn + alpn-api + true +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java +deleted file mode 100644 +index 06b29b7..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java ++++ /dev/null +@@ -1,120 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import javax.net.ssl.SSLEngine; +- +-/** +- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}. +- */ +-public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { +- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() { +- { +- if (!JettyNpnSslEngine.isAvailable()) { +- throw new RuntimeException("NPN unsupported. Is your classpath configured correctly?" +- + " See https://wiki.eclipse.org/Jetty/Feature/NPN"); +- } +- } +- +- @Override +- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, +- boolean isServer) { +- return new JettyNpnSslEngine(engine, applicationNegotiator, isServer); +- } +- }; +- +- /** +- * Create a new instance. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(Iterable protocols) { +- this(false, protocols); +- } +- +- /** +- * Create a new instance. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(String... protocols) { +- this(false, protocols); +- } +- +- /** +- * Create a new instance. +- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable protocols) { +- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); +- } +- +- /** +- * Create a new instance. +- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) { +- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); +- } +- +- /** +- * Create a new instance. +- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. +- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, +- boolean serverFailIfNoCommonProtocols, Iterable protocols) { +- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, +- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, +- protocols); +- } +- +- /** +- * Create a new instance. +- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. +- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, +- boolean serverFailIfNoCommonProtocols, String... protocols) { +- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, +- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, +- protocols); +- } +- +- /** +- * Create a new instance. +- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. +- * @param listenerFactory The factory which provides to be notified of which protocol was selected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, +- ProtocolSelectionListenerFactory listenerFactory, Iterable protocols) { +- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols); +- } +- +- /** +- * Create a new instance. +- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. +- * @param listenerFactory The factory which provides to be notified of which protocol was selected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, +- ProtocolSelectionListenerFactory listenerFactory, String... protocols) { +- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols); +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java +index 0ad6639..d5b86ff 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java ++++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java +@@ -288,47 +288,17 @@ public class JdkSslContext extends SslContext { + case ALPN: + if (isServer) { + switch(config.selectorFailureBehavior()) { +- case FATAL_ALERT: +- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); +- case NO_ADVERTISE: +- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); + default: + throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") + .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); + } + } else { + switch(config.selectedListenerFailureBehavior()) { +- case ACCEPT: +- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); +- case FATAL_ALERT: +- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); + default: + throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") + .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); + } + } +- case NPN: +- if (isServer) { +- switch(config.selectedListenerFailureBehavior()) { +- case ACCEPT: +- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); +- case FATAL_ALERT: +- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); +- default: +- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") +- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); +- } +- } else { +- switch(config.selectorFailureBehavior()) { +- case FATAL_ALERT: +- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); +- case NO_ADVERTISE: +- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); +- default: +- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") +- .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); +- } +- } + default: + throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") + .append(config.protocol()).append(" protocol").toString()); +diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java +deleted file mode 100644 +index 77e7366..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java ++++ /dev/null +@@ -1,122 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-package io.netty.handler.ssl; +- +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +-import io.netty.util.internal.PlatformDependent; +- +-import java.util.LinkedHashSet; +-import java.util.List; +- +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +- +-import org.eclipse.jetty.npn.NextProtoNego; +-import org.eclipse.jetty.npn.NextProtoNego.ClientProvider; +-import org.eclipse.jetty.npn.NextProtoNego.ServerProvider; +- +-final class JettyNpnSslEngine extends JdkSslEngine { +- private static boolean available; +- +- static boolean isAvailable() { +- updateAvailability(); +- return available; +- } +- +- private static void updateAvailability() { +- if (available) { +- return; +- } +- try { +- // Always use bootstrap class loader. +- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null); +- available = true; +- } catch (Exception ignore) { +- // npn-boot was not loaded. +- } +- } +- +- JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) { +- super(engine); +- checkNotNull(applicationNegotiator, "applicationNegotiator"); +- +- if (server) { +- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator +- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), +- "protocolListener"); +- NextProtoNego.put(engine, new ServerProvider() { +- @Override +- public void unsupported() { +- protocolListener.unsupported(); +- } +- +- @Override +- public List protocols() { +- return applicationNegotiator.protocols(); +- } +- +- @Override +- public void protocolSelected(String protocol) { +- try { +- protocolListener.selected(protocol); +- } catch (Throwable t) { +- PlatformDependent.throwException(t); +- } +- } +- }); +- } else { +- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() +- .newSelector(this, new LinkedHashSet(applicationNegotiator.protocols())), +- "protocolSelector"); +- NextProtoNego.put(engine, new ClientProvider() { +- @Override +- public boolean supports() { +- return true; +- } +- +- @Override +- public void unsupported() { +- protocolSelector.unsupported(); +- } +- +- @Override +- public String selectProtocol(List protocols) { +- try { +- return protocolSelector.select(protocols); +- } catch (Throwable t) { +- PlatformDependent.throwException(t); +- return null; +- } +- } +- }); +- } +- } +- +- @Override +- public void closeInbound() throws SSLException { +- NextProtoNego.remove(getWrappedEngine()); +- super.closeInbound(); +- } +- +- @Override +- public void closeOutbound() { +- NextProtoNego.remove(getWrappedEngine()); +- super.closeOutbound(); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +index d6cd94d..4489b16 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java ++++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +@@ -46,7 +46,7 @@ public class JdkSslEngineTest extends SSLEngineTest { + NPN_DEFAULT { + @Override + boolean isAvailable() { +- return JettyNpnSslEngine.isAvailable(); ++ return false; + } + + @Override +-- +2.9.4 + diff --git a/SOURCES/0003-Remove-conscrypt-ALPN.patch b/SOURCES/0003-Remove-conscrypt-ALPN.patch new file mode 100644 index 0000000..e71ba5a --- /dev/null +++ b/SOURCES/0003-Remove-conscrypt-ALPN.patch @@ -0,0 +1,511 @@ +From 039534e20546221c3466d1ceb663625c59edb0e7 Mon Sep 17 00:00:00 2001 +From: Michael Simacek +Date: Tue, 11 Jul 2017 13:37:22 +0200 +Subject: [PATCH 3/3] Remove conscrypt ALPN + +--- + handler/pom.xml | 6 - + .../netty/handler/ssl/ConscryptAlpnSslEngine.java | 176 --------------------- + .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 6 +- + .../main/java/io/netty/handler/ssl/SslHandler.java | 35 ---- + .../ssl/ConscryptJdkSslEngineInteropTest.java | 76 --------- + .../io/netty/handler/ssl/Java8SslTestUtils.java | 7 - + .../ssl/JdkConscryptSslEngineInteropTest.java | 86 ---------- + .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +- + 8 files changed, 2 insertions(+), 392 deletions(-) + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java + +diff --git a/handler/pom.xml b/handler/pom.xml +index 52e63ca..69af32a 100644 +--- a/handler/pom.xml ++++ b/handler/pom.xml +@@ -60,12 +60,6 @@ + true + + +- ${conscrypt.groupId} +- ${conscrypt.artifactId} +- ${conscrypt.classifier} +- true +- +- + org.mockito + mockito-core + +diff --git a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java +deleted file mode 100644 +index 8e7a544..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java ++++ /dev/null +@@ -1,176 +0,0 @@ +-/* +- * Copyright 2017 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException; +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import static java.lang.Math.min; +- +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +-import java.lang.reflect.Method; +-import java.nio.ByteBuffer; +-import java.util.Collections; +-import java.util.LinkedHashSet; +-import java.util.List; +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLEngineResult; +-import javax.net.ssl.SSLException; +- +-import io.netty.util.internal.PlatformDependent; +-import org.conscrypt.Conscrypt; +-import org.conscrypt.HandshakeListener; +- +-/** +- * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN. +- */ +-abstract class ConscryptAlpnSslEngine extends JdkSslEngine { +- private static final Class ENGINES_CLASS = getEnginesClass(); +- +- /** +- * Indicates whether or not conscrypt is available on the current system. +- */ +- static boolean isAvailable() { +- return ENGINES_CLASS != null && PlatformDependent.javaVersion() >= 8; +- } +- +- static boolean isEngineSupported(SSLEngine engine) { +- return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS); +- } +- +- static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- return new ClientEngine(engine, applicationNegotiator); +- } +- +- static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- return new ServerEngine(engine, applicationNegotiator); +- } +- +- private ConscryptAlpnSslEngine(SSLEngine engine, List protocols) { +- super(engine); +- +- // Set the list of supported ALPN protocols on the engine. +- Conscrypt.Engines.setAlpnProtocols(engine, protocols.toArray(new String[protocols.size()])); +- } +- +- /** +- * Calculates the maximum size of the encrypted output buffer required to wrap the given plaintext bytes. Assumes +- * as a worst case that there is one TLS record per buffer. +- * +- * @param plaintextBytes the number of plaintext bytes to be wrapped. +- * @param numBuffers the number of buffers that the plaintext bytes are spread across. +- * @return the maximum size of the encrypted output buffer required for the wrap operation. +- */ +- final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) { +- // Assuming a max of one frame per component in a composite buffer. +- long maxOverhead = (long) Conscrypt.Engines.maxSealOverhead(getWrappedEngine()) * numBuffers; +- // TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of Integer.MAX_VALUE +- return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead); +- } +- +- final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws SSLException { +- return Conscrypt.Engines.unwrap(getWrappedEngine(), srcs, dests); +- } +- +- private static final class ClientEngine extends ConscryptAlpnSslEngine { +- private final ProtocolSelectionListener protocolListener; +- +- ClientEngine(SSLEngine engine, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- super(engine, applicationNegotiator.protocols()); +- // Register for completion of the handshake. +- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() { +- @Override +- public void onHandshakeFinished() throws SSLException { +- selectProtocol(); +- } +- }); +- +- protocolListener = checkNotNull(applicationNegotiator +- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), +- "protocolListener"); +- } +- +- private void selectProtocol() throws SSLException { +- String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine()); +- try { +- protocolListener.selected(protocol); +- } catch (Throwable e) { +- throw toSSLHandshakeException(e); +- } +- } +- } +- +- private static final class ServerEngine extends ConscryptAlpnSslEngine { +- private final ProtocolSelector protocolSelector; +- +- ServerEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator) { +- super(engine, applicationNegotiator.protocols()); +- +- // Register for completion of the handshake. +- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() { +- @Override +- public void onHandshakeFinished() throws SSLException { +- selectProtocol(); +- } +- }); +- +- protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() +- .newSelector(this, +- new LinkedHashSet(applicationNegotiator.protocols())), +- "protocolSelector"); +- } +- +- private void selectProtocol() throws SSLException { +- try { +- String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine()); +- protocolSelector.select(protocol != null ? Collections.singletonList(protocol) +- : Collections.emptyList()); +- } catch (Throwable e) { +- throw toSSLHandshakeException(e); +- } +- } +- } +- +- private static Class getEnginesClass() { +- try { +- // Always use bootstrap class loader. +- Class engineClass = Class.forName("org.conscrypt.Conscrypt$Engines", true, +- ConscryptAlpnSslEngine.class.getClassLoader()); +- // Ensure that it also has the isConscrypt method. +- getIsConscryptMethod(engineClass); +- return engineClass; +- } catch (Throwable ignore) { +- // Conscrypt was not loaded. +- return null; +- } +- } +- +- private static boolean isConscryptEngine(SSLEngine engine, Class enginesClass) { +- try { +- Method method = getIsConscryptMethod(enginesClass); +- return (Boolean) method.invoke(null, engine); +- } catch (Throwable ignore) { +- return false; +- } +- } +- +- private static Method getIsConscryptMethod(Class enginesClass) throws NoSuchMethodException { +- return enginesClass.getMethod("isConscrypt", SSLEngine.class); +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +index f82c7da..9c4ab9e 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java ++++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine; + * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}. + */ + public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { +- private static final boolean AVAILABLE = ConscryptAlpnSslEngine.isAvailable() || JettyAlpnSslEngine.isAvailable(); ++ private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable(); + private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper(); + + /** +@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati + @Override + public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, + boolean isServer) { +- if (ConscryptAlpnSslEngine.isEngineSupported(engine)) { +- return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, applicationNegotiator) +- : ConscryptAlpnSslEngine.newClientEngine(engine, applicationNegotiator); +- } + if (JettyAlpnSslEngine.isAvailable()) { + return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator) + : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator); +diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +index 05c451a..8693011 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java ++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +@@ -187,38 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + new ClosedChannelException(), SslHandler.class, "channelInactive(...)"); + + private enum SslEngineType { +- CONSCRYPT(true, COMPOSITE_CUMULATOR) { +- @Override +- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) +- throws SSLException { +- int nioBufferCount = in.nioBufferCount(); +- int writerIndex = out.writerIndex(); +- final SSLEngineResult result; +- if (nioBufferCount > 1) { +- /* +- * Use a special unwrap method without additional memory copies. +- */ +- try { +- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes()); +- result = ((ConscryptAlpnSslEngine) handler.engine).unwrap( +- in.nioBuffers(readerIndex, len), +- handler.singleBuffer); +- } finally { +- handler.singleBuffer[0] = null; +- } +- } else { +- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len), +- toByteBuffer(out, writerIndex, out.writableBytes())); +- } +- out.writerIndex(writerIndex + result.bytesProduced()); +- return result; +- } +- +- @Override +- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) { +- return ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents); +- } +- }, + JDK(false, MERGE_CUMULATOR) { + @Override + SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) +@@ -237,9 +205,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + }; + + static SslEngineType forEngine(SSLEngine engine) { +- if (engine instanceof ConscryptAlpnSslEngine) { +- return CONSCRYPT; +- } + return JDK; + } + +diff --git a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java +deleted file mode 100644 +index e217136..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import java.security.Provider; +-import org.junit.BeforeClass; +-import org.junit.Ignore; +- +-import org.junit.runner.RunWith; +-import org.junit.runners.Parameterized; +- +-import java.util.ArrayList; +-import java.util.Collection; +-import java.util.List; +- +-import static org.junit.Assume.assumeTrue; +- +-@RunWith(Parameterized.class) +-public class ConscryptJdkSslEngineInteropTest extends SSLEngineTest { +- +- @Parameterized.Parameters(name = "{index}: bufferType = {0}") +- public static Collection data() { +- List params = new ArrayList(); +- for (BufferType type: BufferType.values()) { +- params.add(type); +- } +- return params; +- } +- +- public ConscryptJdkSslEngineInteropTest(BufferType type) { +- super(type); +- } +- +- @BeforeClass +- public static void checkConscrypt() { +- assumeTrue(ConscryptAlpnSslEngine.isAvailable()); +- } +- +- @Override +- protected SslProvider sslClientProvider() { +- return SslProvider.JDK; +- } +- +- @Override +- protected SslProvider sslServerProvider() { +- return SslProvider.JDK; +- } +- +- @Override +- protected Provider clientSslContextProvider() { +- return Java8SslTestUtils.conscryptProvider(); +- } +- +- @Ignore /* Does the JDK support a "max certificate chain length"? */ +- @Override +- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { +- } +- +- @Ignore /* Does the JDK support a "max certificate chain length"? */ +- @Override +- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java +index cc2e6c6..f9cf771 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java ++++ b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java +@@ -16,12 +16,9 @@ + + package io.netty.handler.ssl; + +-import org.conscrypt.OpenSSLProvider; +- + import javax.net.ssl.SNIMatcher; + import javax.net.ssl.SNIServerName; + import javax.net.ssl.SSLParameters; +-import java.security.Provider; + import java.util.Collections; + + final class Java8SslTestUtils { +@@ -37,8 +34,4 @@ final class Java8SslTestUtils { + }; + parameters.setSNIMatchers(Collections.singleton(matcher)); + } +- +- static Provider conscryptProvider() { +- return new OpenSSLProvider(); +- } + } +diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java +deleted file mode 100644 +index 0625f7a..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java ++++ /dev/null +@@ -1,86 +0,0 @@ +-/* +- * Copyright 2017 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import java.security.Provider; +-import org.junit.BeforeClass; +-import org.junit.Ignore; +-import org.junit.Test; +-import org.junit.runner.RunWith; +-import org.junit.runners.Parameterized; +- +-import java.util.ArrayList; +-import java.util.Collection; +-import java.util.List; +- +-import static org.junit.Assume.assumeTrue; +- +-@RunWith(Parameterized.class) +-public class JdkConscryptSslEngineInteropTest extends SSLEngineTest { +- +- @Parameterized.Parameters(name = "{index}: bufferType = {0}") +- public static Collection data() { +- List params = new ArrayList(); +- for (BufferType type: BufferType.values()) { +- params.add(type); +- } +- return params; +- } +- +- public JdkConscryptSslEngineInteropTest(BufferType type) { +- super(type); +- } +- +- @BeforeClass +- public static void checkConscrypt() { +- assumeTrue(ConscryptAlpnSslEngine.isAvailable()); +- } +- +- @Override +- protected SslProvider sslClientProvider() { +- return SslProvider.JDK; +- } +- +- @Override +- protected SslProvider sslServerProvider() { +- return SslProvider.JDK; +- } +- +- @Override +- protected Provider serverSslContextProvider() { +- return Java8SslTestUtils.conscryptProvider(); +- } +- +- @Override +- @Test +- @Ignore("TODO: Make this work with Conscrypt") +- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { +- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth(); +- } +- +- @Override +- @Test +- @Ignore("TODO: Make this work with Conscrypt") +- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { +- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth(); +- } +- +- @Override +- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) { +- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. +- return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +index 4489b16..e32fa0d 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java ++++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +@@ -81,7 +81,7 @@ public class JdkSslEngineTest extends SSLEngineTest { + + @Override + boolean isAvailable() { +- return ConscryptAlpnSslEngine.isAvailable(); ++ return false; + } + + @Override +-- +2.9.4 + diff --git a/SOURCES/0004-Remove-jetty-ALPN.patch b/SOURCES/0004-Remove-jetty-ALPN.patch new file mode 100644 index 0000000..42b5415 --- /dev/null +++ b/SOURCES/0004-Remove-jetty-ALPN.patch @@ -0,0 +1,217 @@ +diff --git a/handler/pom.xml b/handler/pom.xml +index 69af32a..b9e5596 100644 +--- a/handler/pom.xml ++++ b/handler/pom.xml +@@ -54,11 +54,6 @@ + bcpkix-jdk15on + true + +- +- org.eclipse.jetty.alpn +- alpn-api +- true +- + + org.mockito + mockito-core +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +index 9c4ab9e..5cc1ab7 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java ++++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine; + * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}. + */ + public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { +- private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable(); ++ private static final boolean AVAILABLE = false; + private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper(); + + /** +@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati + @Override + public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, + boolean isServer) { +- if (JettyAlpnSslEngine.isAvailable()) { +- return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator) +- : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator); +- } + throw new RuntimeException("Unable to wrap SSLEngine of type " + engine.getClass().getName()); + } + } +diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java +deleted file mode 100644 +index 624719a..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java ++++ /dev/null +@@ -1,158 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException; +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +- +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +- +-import java.util.LinkedHashSet; +-import java.util.List; +- +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +- +-import io.netty.util.internal.PlatformDependent; +-import org.eclipse.jetty.alpn.ALPN; +- +-abstract class JettyAlpnSslEngine extends JdkSslEngine { +- private static final boolean available = initAvailable(); +- +- static boolean isAvailable() { +- return available; +- } +- +- private static boolean initAvailable() { +- // TODO: Add support for ALPN when using Java9 and still be able to configure it the Netty way. +- if (PlatformDependent.javaVersion() <= 8) { +- try { +- // Always use bootstrap class loader. +- Class.forName("sun.security.ssl.ALPNExtension", true, null); +- return true; +- } catch (Throwable ignore) { +- // alpn-boot was not loaded. +- } +- } +- return false; +- } +- +- static JettyAlpnSslEngine newClientEngine(SSLEngine engine, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- return new ClientEngine(engine, applicationNegotiator); +- } +- +- static JettyAlpnSslEngine newServerEngine(SSLEngine engine, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- return new ServerEngine(engine, applicationNegotiator); +- } +- +- private JettyAlpnSslEngine(SSLEngine engine) { +- super(engine); +- } +- +- private static final class ClientEngine extends JettyAlpnSslEngine { +- ClientEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) { +- super(engine); +- checkNotNull(applicationNegotiator, "applicationNegotiator"); +- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator +- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), +- "protocolListener"); +- ALPN.put(engine, new ALPN.ClientProvider() { +- @Override +- public List protocols() { +- return applicationNegotiator.protocols(); +- } +- +- @Override +- public void selected(String protocol) throws SSLException { +- try { +- protocolListener.selected(protocol); +- } catch (Throwable t) { +- throw toSSLHandshakeException(t); +- } +- } +- +- @Override +- public void unsupported() { +- protocolListener.unsupported(); +- } +- }); +- } +- +- @Override +- public void closeInbound() throws SSLException { +- try { +- ALPN.remove(getWrappedEngine()); +- } finally { +- super.closeInbound(); +- } +- } +- +- @Override +- public void closeOutbound() { +- try { +- ALPN.remove(getWrappedEngine()); +- } finally { +- super.closeOutbound(); +- } +- } +- } +- +- private static final class ServerEngine extends JettyAlpnSslEngine { +- ServerEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) { +- super(engine); +- checkNotNull(applicationNegotiator, "applicationNegotiator"); +- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() +- .newSelector(this, new LinkedHashSet(applicationNegotiator.protocols())), +- "protocolSelector"); +- ALPN.put(engine, new ALPN.ServerProvider() { +- @Override +- public String select(List protocols) throws SSLException { +- try { +- return protocolSelector.select(protocols); +- } catch (Throwable t) { +- throw toSSLHandshakeException(t); +- } +- } +- +- @Override +- public void unsupported() { +- protocolSelector.unsupported(); +- } +- }); +- } +- +- @Override +- public void closeInbound() throws SSLException { +- try { +- ALPN.remove(getWrappedEngine()); +- } finally { +- super.closeInbound(); +- } +- } +- +- @Override +- public void closeOutbound() { +- try { +- ALPN.remove(getWrappedEngine()); +- } finally { +- super.closeOutbound(); +- } +- } +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +index e32fa0d..a8014e5 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java ++++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +@@ -62,7 +62,7 @@ public class JdkSslEngineTest extends SSLEngineTest { + ALPN_DEFAULT { + @Override + boolean isAvailable() { +- return JettyAlpnSslEngine.isAvailable(); ++ return false; + } + + @Override diff --git a/SOURCES/codegen.bash b/SOURCES/codegen.bash new file mode 100755 index 0000000..f9837e4 --- /dev/null +++ b/SOURCES/codegen.bash @@ -0,0 +1,22 @@ +#!/bin/bash +for type in byte char short int long; do + case $type in + int) object=Integer ;; + char) object=Character ;; + *) object=${type^} ;; + esac + hash='(int) key' + if [ $type = long ]; then + hash='(int) (key ^ (key >>> 32))' + fi + mkdir -p target/generated-sources/collections/java + for file in `find src/main/templates -name '*.template'`; do + filename=$(basename $file | sed "s/K/${type^}/;s/\.template/.java/") + sed -e "s/@k@/${type}/g" \ + -e "s/@K@/${type^}/g" \ + -e "s/@O@/${object}/g" \ + -e "s/@KEY_NUMBER_METHOD@/${type}Value/g" \ + -e "s/@HASH_CODE@/${hash}/g" \ + $file > target/generated-sources/collections/java/$filename + done +done diff --git a/SPECS/netty.spec b/SPECS/netty.spec new file mode 100644 index 0000000..c48d9f0 --- /dev/null +++ b/SPECS/netty.spec @@ -0,0 +1,378 @@ +# Disable generation of debuginfo package +%global debug_package %{nil} +%global namedreltag .Final +%global namedversion %{version}%{?namedreltag} + +%bcond_with jp_minimal + +Name: netty +Version: 4.1.13 +Release: 5%{?dist} +Summary: An asynchronous event-driven network application framework and tools for Java +License: ASL 2.0 +URL: https://netty.io/ +Source0: https://github.com/netty/netty/archive/netty-%{namedversion}.tar.gz +# Upsteam uses a simple template generator script written in groovy and run with gmaven +# We don't have the plugin and want to avoid groovy dependency +# This script is written in bash+sed and performs the same task +Source1: codegen.bash +Patch0: 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch +Patch1: 0002-Remove-NPN.patch +Patch2: 0003-Remove-conscrypt-ALPN.patch +Patch3: 0004-Remove-jetty-ALPN.patch + +BuildRequires: maven-local +BuildRequires: mvn(ant-contrib:ant-contrib) +BuildRequires: mvn(com.jcraft:jzlib) +BuildRequires: mvn(commons-logging:commons-logging) +BuildRequires: mvn(kr.motd.maven:os-maven-plugin) +BuildRequires: mvn(log4j:log4j:1.2.17) +BuildRequires: mvn(org.apache.felix:maven-bundle-plugin) +BuildRequires: mvn(org.apache.maven.plugins:maven-antrun-plugin) +BuildRequires: mvn(org.apache.maven.plugins:maven-dependency-plugin) +BuildRequires: mvn(org.apache.maven.plugins:maven-remote-resources-plugin) +BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin) +BuildRequires: mvn(org.codehaus.mojo:exec-maven-plugin) +BuildRequires: mvn(org.fusesource.hawtjni:maven-hawtjni-plugin) +BuildRequires: mvn(org.javassist:javassist) +BuildRequires: mvn(org.jctools:jctools-core) +BuildRequires: mvn(org.slf4j:slf4j-api) +BuildRequires: mvn(org.sonatype.oss:oss-parent:pom:) +%if %{without jp_minimal} +BuildRequires: mvn(com.fasterxml:aalto-xml) +BuildRequires: mvn(com.github.jponge:lzma-java) +BuildRequires: mvn(com.google.protobuf.nano:protobuf-javanano) +BuildRequires: mvn(com.google.protobuf:protobuf-java) +BuildRequires: mvn(com.ning:compress-lzf) +BuildRequires: mvn(net.jpountz.lz4:lz4) +BuildRequires: mvn(org.apache.logging.log4j:log4j-api) +BuildRequires: mvn(org.bouncycastle:bcpkix-jdk15on) +BuildRequires: mvn(org.jboss.marshalling:jboss-marshalling) +BuildRequires: mvn(org.eclipse.jetty.alpn:alpn-api) +%endif + +%description +Netty is a NIO client server framework which enables quick and easy +development of network applications such as protocol servers and +clients. It greatly simplifies and streamlines network programming +such as TCP and UDP socket server. + +'Quick and easy' doesn't mean that a resulting application will suffer +from a maintainability or a performance issue. Netty has been designed +carefully with the experiences earned from the implementation of a lot +of protocols such as FTP, SMTP, HTTP, and various binary and +text-based legacy protocols. As a result, Netty has succeeded to find +a way to achieve ease of development, performance, stability, and +flexibility without a compromise. + +%package javadoc +Summary: API documentation for %{name} + +%description javadoc +%{summary}. + +%prep +%setup -q -n netty-netty-%{namedversion} + +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%if %{with jp_minimal} +%patch3 -p1 +%endif + +# Missing Mavenized rxtx +%pom_disable_module "transport-rxtx" +%pom_remove_dep ":netty-transport-rxtx" all +# Missing com.barchart.udt:barchart-udt-bundle:jar:2.3.0 +%pom_disable_module "transport-udt" +%pom_remove_dep ":netty-transport-udt" all +%pom_remove_dep ":netty-build" all +# Not needed +%pom_disable_module "example" +%pom_remove_dep ":netty-example" all +%pom_disable_module "testsuite" +%pom_disable_module "testsuite-autobahn" +%pom_disable_module "testsuite-osgi" +%pom_disable_module "tarball" +%pom_disable_module "microbench" + +%pom_xpath_inject 'pom:plugin[pom:artifactId="maven-remote-resources-plugin"]' ' + + +io.netty +netty-dev-tools +${project.version} + +' + +%pom_remove_plugin :maven-antrun-plugin +%pom_remove_plugin :maven-dependency-plugin +# style checker +%pom_remove_plugin :xml-maven-plugin +%pom_remove_plugin -r :maven-checkstyle-plugin +%pom_remove_plugin -r :animal-sniffer-maven-plugin +%pom_remove_plugin -r :maven-enforcer-plugin +%pom_remove_plugin -r :maven-shade-plugin +%pom_remove_plugin -r :maven-release-plugin +%pom_remove_plugin -r :maven-clean-plugin +%pom_remove_plugin -r :maven-source-plugin +%pom_remove_plugin -r :maven-deploy-plugin +%pom_remove_plugin -r :maven-jxr-plugin +%pom_remove_plugin -r :maven-javadoc-plugin +%pom_remove_plugin -r :forbiddenapis + +cp %{SOURCE1} common/codegen.bash +%pom_add_plugin org.codehaus.mojo:exec-maven-plugin common ' + + + generate-collections + generate-sources + + exec + + + common/codegen.bash + + + +' +%pom_remove_plugin :groovy-maven-plugin common + +%if %{with jp_minimal} +%pom_remove_dep -r "com.google.protobuf:protobuf-java" +%pom_remove_dep -r "com.google.protobuf.nano:protobuf-javanano" +rm codec/src/main/java/io/netty/handler/codec/protobuf/* +sed -i '/import.*protobuf/d' codec/src/main/java/io/netty/handler/codec/DatagramPacket*.java +%pom_remove_dep -r "org.jboss.marshalling:jboss-marshalling" +rm codec/src/main/java/io/netty/handler/codec/marshalling/* +%pom_remove_dep -r org.bouncycastle +rm handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java +sed -i '/BouncyCastleSelfSignedCertGenerator/s/.*/throw new UnsupportedOperationException();/' \ + handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java +%pom_remove_dep -r com.fasterxml:aalto-xml +%pom_disable_module codec-xml +%pom_remove_dep :netty-codec-xml all +%pom_remove_dep -r com.github.jponge:lzma-java +rm codec/src/*/java/io/netty/handler/codec/compression/Lzma*.java +%pom_remove_dep -r com.ning:compress-lzf +rm codec/src/*/java/io/netty/handler/codec/compression/Lzf*.java +%pom_remove_dep -r net.jpountz.lz4:lz4 +rm codec/src/*/java/io/netty/handler/codec/compression/Lz4*.java +%pom_remove_dep -r org.apache.logging.log4j: +rm common/*/main/java/io/netty/util/internal/logging/Log4J2*.java + +%endif # jp_minimal + +sed -i 's|taskdef|taskdef classpathref="maven.plugin.classpath"|' all/pom.xml + +%pom_xpath_inject "pom:plugins/pom:plugin[pom:artifactId = 'maven-antrun-plugin']" 'ant-contribant-contrib1.0b3' all/pom.xml +%pom_xpath_inject "pom:execution[pom:id = 'build-native-lib']/pom:configuration" 'true' transport-native-epoll/pom.xml + +# Upstream has jctools bundled. +%pom_xpath_remove "pom:build/pom:plugins/pom:plugin[pom:artifactId = 'maven-bundle-plugin']/pom:executions/pom:execution[pom:id = 'generate-manifest']/pom:configuration/pom:instructions/pom:Import-Package" common/pom.xml + +# Tell xmvn to install attached artifact, which it does not +# do by default. In this case install all attached artifacts with +# the linux classifier. +%mvn_package ":::linux*:" + +%mvn_package ':*-tests' __noinstall + +%build +export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS" +%mvn_build -f + +%install +%mvn_install + +%files -f .mfiles +%doc LICENSE.txt NOTICE.txt + +%files javadoc -f .mfiles-javadoc +%doc LICENSE.txt NOTICE.txt + +%changelog +* Wed Apr 25 2018 Michael Simacek - 4.1.13-5 +- Remove log4j from jp_minimal build + +* Tue Apr 24 2018 mskalick@redhat.com - 4.1.13-4 +- Remove org.eclipse.jetty.alpn dependency for jp_minimal + +* Tue Apr 24 2018 Michael Simacek - 4.1.13-3 +- Don't package test artifacts + +* Thu Feb 08 2018 Fedora Release Engineering - 4.1.13-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Mon Aug 14 2017 Michael Simacek - 4.1.13-1 +- Update to upstream version 4.1.13 + +* Thu Aug 03 2017 Fedora Release Engineering - 4.0.42-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 4.0.42-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Wed Mar 29 2017 Michael Simacek - 4.0.42-5 +- Keep Import-Package default value + +* Thu Mar 16 2017 Michael Simacek - 4.0.42-4 +- Remove maven-javadoc-plugin from POM + +* Wed Mar 15 2017 Michael Simacek - 4.0.42-3 +- Add jp_minimal conditional + +* Mon Feb 06 2017 Michael Simacek - 4.0.42-2 +- Remove useless plugins + +* Thu Oct 20 2016 Severin Gehwolf - 4.0.42-1 +- Remove old netty4 provides/obsoletes. + +* Thu Oct 20 2016 Severin Gehwolf - 4.0.42-1 +- Update to upstream 4.0.42 release. +- Resolves RHBZ#1380921 + +* Thu Feb 04 2016 Fedora Release Engineering - 4.0.28-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Jun 17 2015 Fedora Release Engineering - 4.0.28-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed May 20 2015 Severin Gehwolf - 4.0.28-1 +- Update to upstream 4.0.28 release. +- Fixes CVE-2015-2156 (HttpOnly cookie bypass). +- Resolves RHBZ#1111502 + +* Wed May 20 2015 Severin Gehwolf - 4.0.27-1 +- Update to upstream 4.0.27 release. + +* Wed Apr 01 2015 Severin Gehwolf - 4.0.19-3 +- Drop mvn(org.easymock:easymockclassextension) BR. + Resolves: RHBZ#1207991 + +* Sun Aug 17 2014 Fedora Release Engineering - 4.0.19-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Mon Jun 9 2014 Mikolaj Izdebski - 4.0.19-1 +- Update to upstream version 4.0.19 +- Convert to arch-specific package + +* Sat Jun 07 2014 Fedora Release Engineering - 4.0.14-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Tue Mar 04 2014 Stanislav Ochotnicky - 4.0.14-4 +- Use Requires: java-headless rebuild (#1067528) + +* Mon Jan 13 2014 Marek Goldmann - 4.0.14-3 +- Enable netty-all.jar artifact + +* Mon Jan 13 2014 Marek Goldmann - 4.0.14-2 +- Bump the release, so Obsoletes work properly + +* Mon Dec 30 2013 Marek Goldmann - 4.0.14-1 +- Upstream release 4.0.14.Final + +* Sat Aug 03 2013 Fedora Release Engineering - 3.6.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Thu May 16 2013 Mikolaj Izdebski - 3.6.6-1 +- Update to upstream version 3.6.6 + +* Wed Apr 10 2013 Mikolaj Izdebski - 3.6.5-1 +- Update to upstream version 3.6.5 + +* Mon Apr 8 2013 Mikolaj Izdebski - 3.6.4-1 +- Update to upstream version 3.6.4 + +* Wed Feb 27 2013 Mikolaj Izdebski - 3.6.3-3 +- Set scope of optional compile dependencies to 'provided' + +* Wed Feb 27 2013 Mikolaj Izdebski - 3.6.3-2 +- Drop dependency on OSGi +- Resolves: rhbz#916139 + +* Mon Feb 25 2013 Mikolaj Izdebski - 3.6.3-1 +- Update to upstream version 3.6.3 + +* Thu Feb 14 2013 Fedora Release Engineering - 3.6.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Wed Feb 06 2013 Java SIG - 3.6.2-2 +- Update for https://fedoraproject.org/wiki/Fedora_19_Maven_Rebuild +- Replace maven BuildRequires with maven-local + +* Wed Jan 16 2013 Mikolaj Izdebski - 3.6.2-1 +- Update to upstream version 3.6.2 + +* Tue Jan 15 2013 Mikolaj Izdebski - 3.6.1-1 +- Update to upstream version 3.6.1 + +* Thu Dec 13 2012 Mikolaj Izdebski - 3.5.11-2 +- Use system jzlib instead of bundled jzlib +- Resolves: rhbz#878391 + +* Mon Dec 3 2012 Mikolaj Izdebski - 3.5.11-1 +- Update to upstream version 3.5.11 + +* Mon Nov 12 2012 Mikolaj Izdebski - 3.5.10-1 +- Update to upstream version 3.5.10 + +* Thu Oct 25 2012 Mikolaj Izdebski - 3.5.9-1 +- Update to upstream version 3.5.9 + +* Fri Oct 5 2012 Mikolaj Izdebski - 3.5.8-1 +- Update to upstream version 3.5.8 + +* Fri Sep 7 2012 Mikolaj Izdebski - 3.5.7-1 +- Update to upstream version 3.5.7 + +* Mon Sep 3 2012 Mikolaj Izdebski - 3.5.6-1 +- Update to upstream version 3.5.6 + +* Thu Aug 23 2012 Mikolaj Izdebski - 3.5.5-1 +- Update to upstream version 3.5.5 + +* Wed Aug 15 2012 Tomas Rohovsky - 3.5.4-1 +- Update to upstream version 3.5.4 + +* Tue Jul 24 2012 Mikolaj Izdebski - 3.5.3-1 +- Update to upstream version 3.5.3 + +* Fri Jul 20 2012 Fedora Release Engineering - 3.5.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jul 16 2012 Mikolaj Izdebski - 3.5.2-2 +- Add additional depmap for org.jboss.netty:netty +- Fixes #840301 + +* Thu Jul 12 2012 Mikolaj Izdebski - 3.5.2-1 +- Update to upstream version 3.5.2 +- Convert patches to POM macros +- Enable jboss-logging + +* Fri May 18 2012 Stanislav Ochotnicky - 3.2.4-4 +- Add enforcer-plugin to BR + +* Wed Apr 18 2012 Stanislav Ochotnicky - 3.2.4-3 +- Remove eclipse plugin from BuildRequires + +* Fri Jan 13 2012 Fedora Release Engineering - 3.2.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Mon Dec 5 2011 Stanislav Ochotnicky - 3.2.4-1 +- Update to latest upstream version + +* Mon Jul 4 2011 Alexander Kurtakov 3.2.3-4 +- Fix FTBFS. +- Adapt to current guidelines. + +* Tue Feb 08 2011 Fedora Release Engineering - 3.2.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Jan 17 2011 Stanislav Ochotnicky - 3.2.3-2 +- Use maven 3 to build +- Drop ant-contrib depmap (no longer needed) + +* Thu Jan 13 2011 Stanislav Ochotnicky - 3.2.3-1 +- Initial version of the package