From 38464b7257708c7a75e9194ae69f7dd2a0bfaab5 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Thu, 20 Oct 2016 17:55:57 +0200 Subject: [PATCH] Update to upstream's 4.0.42 release. Resolves: RHBZ#1380921 --- ...-OpenSSL-parts-depending-on-tcnative.patch | 6037 +++++++++++++++++ 0002-Remove-NPN-ALPN.patch | 884 +++ netty.spec | 27 +- npn_alpn_ssl_fixes.patch | 4384 ------------ sources | 2 +- transport-native-epoll-configure-fix.patch | 14 - 6 files changed, 6938 insertions(+), 4410 deletions(-) create mode 100644 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch create mode 100644 0002-Remove-NPN-ALPN.patch delete mode 100644 npn_alpn_ssl_fixes.patch delete mode 100644 transport-native-epoll-configure-fix.patch diff --git a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch b/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch new file mode 100644 index 0000000..087ae53 --- /dev/null +++ b/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch @@ -0,0 +1,6037 @@ +From 8b7286b1c8cd740e85fc483c1be6fcc8ce478ec4 Mon Sep 17 00:00:00 2001 +From: Severin Gehwolf +Date: Thu, 20 Oct 2016 15:54:52 +0200 +Subject: [PATCH 1/2] Remove OpenSSL parts depending on tcnative. + +--- + .../main/java/io/netty/handler/ssl/OpenSsl.java | 479 ----- + .../handler/ssl/OpenSslCertificateException.java | 80 - + .../io/netty/handler/ssl/OpenSslClientContext.java | 210 --- + .../java/io/netty/handler/ssl/OpenSslContext.java | 57 - + .../java/io/netty/handler/ssl/OpenSslEngine.java | 42 - + .../io/netty/handler/ssl/OpenSslEngineMap.java | 35 - + .../ssl/OpenSslExtendedKeyMaterialManager.java | 40 - + .../handler/ssl/OpenSslKeyMaterialManager.java | 179 -- + .../io/netty/handler/ssl/OpenSslServerContext.java | 370 ---- + .../handler/ssl/OpenSslServerSessionContext.java | 79 - + .../netty/handler/ssl/OpenSslSessionContext.java | 111 -- + .../io/netty/handler/ssl/OpenSslSessionStats.java | 155 -- + .../netty/handler/ssl/OpenSslSessionTicketKey.java | 78 - + .../ssl/ReferenceCountedOpenSslClientContext.java | 300 --- + .../ssl/ReferenceCountedOpenSslContext.java | 751 -------- + .../handler/ssl/ReferenceCountedOpenSslEngine.java | 1936 -------------------- + .../ssl/ReferenceCountedOpenSslServerContext.java | 195 -- + .../main/java/io/netty/handler/ssl/SslContext.java | 24 +- + .../main/java/io/netty/handler/ssl/SslHandler.java | 38 +- + .../handler/ssl/JdkOpenSslEngineInteroptTest.java | 37 - + .../handler/ssl/OpenSslClientContextTest.java | 38 - + .../io/netty/handler/ssl/OpenSslEngineTest.java | 129 -- + .../ssl/OpenSslJdkSslEngineInteroptTest.java | 38 - + .../netty/handler/ssl/OpenSslRenegotiateTest.java | 36 - + .../handler/ssl/OpenSslServerContextTest.java | 39 - + .../java/io/netty/handler/ssl/PemEncodedTest.java | 95 - + .../ssl/ReferenceCountedOpenSslEngineTest.java | 52 - + .../java/io/netty/handler/ssl/SniClientTest.java | 18 - + .../netty/handler/ssl/SslContextBuilderTest.java | 24 - + .../java/io/netty/handler/ssl/SslHandlerTest.java | 28 - + 30 files changed, 14 insertions(+), 5679 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/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.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/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/PemEncodedTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java + +diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java +deleted file mode 100644 +index c77d6cd..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java ++++ /dev/null +@@ -1,479 +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 org.apache.tomcat.Apr; +-import org.apache.tomcat.jni.Buffer; +-import org.apache.tomcat.jni.Library; +-import org.apache.tomcat.jni.Pool; +-import org.apache.tomcat.jni.SSL; +-import org.apache.tomcat.jni.SSLContext; +- +-import java.io.IOException; +-import java.io.InputStream; +-import java.security.AccessController; +-import java.security.PrivilegedAction; +-import java.util.Arrays; +-import java.util.Collections; +-import java.util.HashSet; +-import java.util.LinkedHashSet; +-import java.util.Locale; +-import java.util.Properties; +-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 USE_KEYMANAGER_FACTORY; +- +- // 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"; +- +- private static final String[] SUPPORTED_PROTOCOLS = { +- PROTOCOL_SSL_V2_HELLO, +- PROTOCOL_SSL_V2, +- PROTOCOL_SSL_V3, +- PROTOCOL_TLS_V1, +- PROTOCOL_TLS_V1_1, +- PROTOCOL_TLS_V1_2 +- }; +- static final Set SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet( +- new HashSet(Arrays.asList(SUPPORTED_PROTOCOLS))); +- +- static { +- Throwable cause = null; +- +- // Test if netty-tcnative is in the classpath first. +- try { +- Class.forName("org.apache.tomcat.jni.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); +- } +- } +- +- if (cause == null && !isNettyTcnative()) { +- logger.debug("incompatible tcnative in the classpath; " +- + OpenSslEngine.class.getSimpleName() + " will be unavailable."); +- cause = new ClassNotFoundException("incompatible tcnative in the classpath"); +- } +- +- UNAVAILABILITY_CAUSE = cause; +- +- if (cause == null) { +- final Set availableOpenSslCipherSuites = new LinkedHashSet(128); +- boolean supportsKeyManagerFactory = false; +- boolean useKeyManagerFactory = false; +- final long aprPool = Pool.create(0); +- try { +- final long sslCtx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER); +- long privateKeyBio = 0; +- long certBio = 0; +- try { +- SSLContext.setOptions(sslCtx, SSL.SSL_OP_ALL); +- 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.length() == 0 || availableOpenSslCipherSuites.contains(c)) { +- continue; +- } +- availableOpenSslCipherSuites.add(c); +- } +- try { +- SelfSignedCertificate cert = new SelfSignedCertificate(); +- certBio = OpenSslContext.toBIO(cert.cert()); +- SSL.setCertificateChainBio(ssl, certBio, false); +- supportsKeyManagerFactory = true; +- useKeyManagerFactory = AccessController.doPrivileged(new PrivilegedAction() { +- @Override +- public Boolean run() { +- return SystemPropertyUtil.getBoolean( +- "io.netty.handler.ssl.openssl.useKeyManagerFactory", true); +- } +- }); +- } catch (Throwable ignore) { +- logger.debug("KeyManagerFactory not supported."); +- } +- } finally { +- SSL.freeSSL(ssl); +- if (privateKeyBio != 0) { +- SSL.freeBIO(privateKeyBio); +- } +- if (certBio != 0) { +- SSL.freeBIO(certBio); +- } +- } +- } finally { +- SSLContext.free(sslCtx); +- } +- } catch (Exception e) { +- logger.warn("Failed to get the list of available OpenSSL cipher suites.", e); +- } finally { +- Pool.destroy(aprPool); +- } +- 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()); +- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) { +- availableCipherSuites.add(cipher); +- } +- for (String cipher: AVAILABLE_JAVA_CIPHER_SUITES) { +- availableCipherSuites.add(cipher); +- } +- AVAILABLE_CIPHER_SUITES = availableCipherSuites; +- SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory; +- USE_KEYMANAGER_FACTORY = useKeyManagerFactory; +- } else { +- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet(); +- AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet(); +- AVAILABLE_CIPHER_SUITES = Collections.emptySet(); +- SUPPORTS_KEYMANAGER_FACTORY = false; +- USE_KEYMANAGER_FACTORY = false; +- } +- } +- +- private static boolean isNettyTcnative() { +- return AccessController.doPrivileged(new PrivilegedAction() { +- @Override +- public Boolean run() { +- InputStream is = null; +- try { +- is = Apr.class.getResourceAsStream("/org/apache/tomcat/apr.properties"); +- Properties props = new Properties(); +- props.load(is); +- String info = props.getProperty("tcn.info"); +- return info != null && info.startsWith("netty-tcnative"); +- } catch (Throwable ignore) { +- return false; +- } finally { +- if (is != null) { +- try { +- is.close(); +- } catch (IOException ignore) { +- // ignore +- } +- } +- } +- } +- }); +- } +- +- /** +- * 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 the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()} +- * returns {@code false}. +- */ +- public static int version() { +- if (isAvailable()) { +- return SSL.version(); +- } +- return -1; +- } +- +- /** +- * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()} +- * returns {@code false}. +- */ +- public static String versionString() { +- if (isAvailable()) { +- return SSL.versionString(); +- } +- return 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; +- } +- +- static boolean useKeyManagerFactory() { +- return USE_KEYMANAGER_FACTORY; +- } +- +- static boolean isError(long errorCode) { +- return errorCode != SSL.SSL_ERROR_NONE; +- } +- +- 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(3); +- // 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"); +- +- NativeLibraryLoader.loadFirstAvailable(SSL.class.getClassLoader(), +- libNames.toArray(new String[libNames.size()])); +- } +- +- private static void initializeTcNative() throws Exception { +- Library.initialize("provided"); +- SSL.initialize(null); +- } +- +- 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 5d9bce0..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java ++++ /dev/null +@@ -1,80 +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.apache.tomcat.jni.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} 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 (errorCode < CertificateVerifier.X509_V_OK || errorCode > CertificateVerifier.X509_V_ERR_DANE_NO_MATCH) { +- throw new IllegalArgumentException("errorCode must be " + CertificateVerifier.X509_V_OK + " => " +- + CertificateVerifier.X509_V_ERR_DANE_NO_MATCH + +- ". See https://www.openssl.org/docs/manmaster/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 bbbbbee..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java ++++ /dev/null +@@ -1,210 +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 org.apache.tomcat.jni.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, sessionCacheSize, sessionTimeout); +- } +- +- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, +- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, +- KeyManagerFactory keyManagerFactory, Iterable ciphers, +- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, +- long sessionCacheSize, long sessionTimeout) +- throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, +- ClientAuth.NONE, false); +- 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 4cafbfb..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java ++++ /dev/null +@@ -1,57 +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, boolean startTls) +- throws SSLException { +- super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain, +- clientAuth, startTls, false); +- } +- +- OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, +- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, +- long sessionTimeout, int mode, Certificate[] keyCertChain, +- ClientAuth clientAuth, boolean startTls) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, startTls, +- 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 2ab7c5c..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java ++++ /dev/null +@@ -1,42 +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; +- +-import static io.netty.util.ReferenceCountUtil.safeRelease; +- +-/** +- * 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 95a38fd..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 org.apache.tomcat.jni.CertificateRequestedCallback; +-import org.apache.tomcat.jni.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 a65e07d..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java ++++ /dev/null +@@ -1,370 +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 org.apache.tomcat.jni.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, 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, boolean startTls) throws SSLException { +- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, +- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, startTls); +- } +- +- @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, boolean startTls) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, +- clientAuth, startTls); +- // 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 c6687f6..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java ++++ /dev/null +@@ -1,79 +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 org.apache.tomcat.jni.SSL; +-import org.apache.tomcat.jni.SSLContext; +- +- +-/** +- * {@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(); +- } +- SSLContext.setSessionCacheTimeout(context.ctx, seconds); +- } +- +- @Override +- public int getSessionTimeout() { +- return (int) SSLContext.getSessionCacheTimeout(context.ctx); +- } +- +- @Override +- public void setSessionCacheSize(int size) { +- if (size < 0) { +- throw new IllegalArgumentException(); +- } +- SSLContext.setSessionCacheSize(context.ctx, size); +- } +- +- @Override +- public int getSessionCacheSize() { +- return (int) SSLContext.getSessionCacheSize(context.ctx); +- } +- +- @Override +- public void setSessionCacheEnabled(boolean enabled) { +- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF; +- SSLContext.setSessionCacheMode(context.ctx, mode); +- } +- +- @Override +- public boolean isSessionCacheEnabled() { +- return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER; +- } +- +- /** +- * 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) { +- return SSLContext.setSessionIdContext(context.ctx, sidCtx); +- } +-} +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 df13d6a..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java ++++ /dev/null +@@ -1,111 +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 org.apache.tomcat.jni.SSL; +-import org.apache.tomcat.jni.SSLContext; +-import org.apache.tomcat.jni.SessionTicketKey; +- +-import javax.net.ssl.SSLSession; +-import javax.net.ssl.SSLSessionContext; +-import java.util.Enumeration; +-import java.util.NoSuchElementException; +- +-/** +- * 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) { +- ObjectUtil.checkNotNull(keys, "keys"); +- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET); +- SSLContext.setSessionTicketKeys(context.ctx, keys); +- } +- +- /** +- * Sets the SSL session ticket keys of this context. +- */ +- public void setTicketKeys(OpenSslSessionTicketKey... keys) { +- ObjectUtil.checkNotNull(keys, "keys"); +- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET); +- SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length]; +- for (int i = 0; i < ticketKeys.length; i++) { +- ticketKeys[i] = keys[i].key; +- } +- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys); +- } +- +- /** +- * 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 ff93a04..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java ++++ /dev/null +@@ -1,155 +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 org.apache.tomcat.jni.SSLContext; +- +-/** +- * 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() { +- return SSLContext.sessionNumber(context.ctx); +- } +- +- /** +- * Returns the number of started SSL/TLS handshakes in client mode. +- */ +- public long connect() { +- return SSLContext.sessionConnect(context.ctx); +- } +- +- /** +- * Returns the number of successfully established SSL/TLS sessions in client mode. +- */ +- public long connectGood() { +- return SSLContext.sessionConnectGood(context.ctx); +- } +- +- /** +- * Returns the number of start renegotiations in client mode. +- */ +- public long connectRenegotiate() { +- return SSLContext.sessionConnectRenegotiate(context.ctx); +- } +- +- /** +- * Returns the number of started SSL/TLS handshakes in server mode. +- */ +- public long accept() { +- return SSLContext.sessionAccept(context.ctx); +- } +- +- /** +- * Returns the number of successfully established SSL/TLS sessions in server mode. +- */ +- public long acceptGood() { +- return SSLContext.sessionAcceptGood(context.ctx); +- } +- +- /** +- * Returns the number of start renegotiations in server mode. +- */ +- public long acceptRenegotiate() { +- return SSLContext.sessionAcceptRenegotiate(context.ctx); +- } +- +- /** +- * 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() { +- return SSLContext.sessionHits(context.ctx); +- } +- +- /** +- * Returns the number of successfully retrieved sessions from the external session cache in server mode. +- */ +- public long cbHits() { +- return SSLContext.sessionCbHits(context.ctx); +- } +- +- /** +- * Returns the number of sessions proposed by clients that were not found in the internal session cache +- * in server mode. +- */ +- public long misses() { +- return SSLContext.sessionMisses(context.ctx); +- } +- +- /** +- * 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() { +- return SSLContext.sessionTimeouts(context.ctx); +- } +- +- /** +- * Returns the number of sessions that were removed because the maximum session cache size was exceeded. +- */ +- public long cacheFull() { +- return SSLContext.sessionCacheFull(context.ctx); +- } +- +- /** +- * Returns the number of times a client presented a ticket that did not match any key in the list. +- */ +- public long ticketKeyFail() { +- return SSLContext.sessionTicketKeyFail(context.ctx); +- } +- +- /** +- * Returns the number of times a client did not present a ticket and we issued a new one +- */ +- public long ticketKeyNew() { +- return SSLContext.sessionTicketKeyNew(context.ctx); +- } +- +- /** +- * 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() { +- return SSLContext.sessionTicketKeyRenew(context.ctx); +- } +- +- /** +- * Returns the number of times a client presented a ticket derived from the primary key. +- */ +- public long ticketKeyResume() { +- return SSLContext.sessionTicketKeyResume(context.ctx); +- } +-} +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 f3af820..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 org.apache.tomcat.jni.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 97cd3e3..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java ++++ /dev/null +@@ -1,300 +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 org.apache.tomcat.jni.CertificateRequestedCallback; +-import org.apache.tomcat.jni.SSL; +-import org.apache.tomcat.jni.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, +- long sessionCacheSize, long sessionTimeout) +- throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, +- ClientAuth.NONE, false, 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"); +- } +- synchronized (ReferenceCountedOpenSslContext.class) { +- 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_VERIFY_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 82e90a9..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java ++++ /dev/null +@@ -1,751 +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.util.AbstractReferenceCounted; +-import io.netty.util.ReferenceCounted; +-import io.netty.util.ResourceLeak; +-import io.netty.util.ResourceLeakDetector; +-import io.netty.util.ResourceLeakDetectorFactory; +-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 org.apache.tomcat.jni.CertificateVerifier; +-import org.apache.tomcat.jni.Pool; +-import org.apache.tomcat.jni.SSL; +-import org.apache.tomcat.jni.SSLContext; +- +-import java.security.AccessController; +-import java.security.PrivateKey; +-import java.security.PrivilegedAction; +-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 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; +- +-/** +- * 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 implemention 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 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 +- */ +- protected volatile long ctx; +- long aprPool; +- @SuppressWarnings({ "unused", "FieldMayBeFinal" }) +- private volatile int aprPoolDestroyed; +- private final List unmodifiableCiphers; +- private final long sessionCacheSize; +- private final long sessionTimeout; +- private final OpenSslApplicationProtocolNegotiator apn; +- private final int mode; +- +- // Reference Counting +- private final ResourceLeak leak; +- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { +- @Override +- protected void deallocate() { +- destroy(); +- if (leak != null) { +- leak.close(); +- } +- } +- }; +- +- final Certificate[] keyCertChain; +- final ClientAuth clientAuth; +- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap(); +- volatile boolean rejectRemoteInitiatedRenegotiation; +- +- 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, boolean startTls, +- boolean leakDetection) throws SSLException { +- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain, +- clientAuth, startTls, leakDetection); +- } +- +- ReferenceCountedOpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, +- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, +- long sessionTimeout, int mode, Certificate[] keyCertChain, +- ClientAuth clientAuth, boolean startTls, boolean leakDetection) throws SSLException { +- super(startTls); +- +- OpenSsl.ensureAvailability(); +- +- 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.open(this) : null; +- this.mode = mode; +- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE; +- +- 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.availableCipherSuites())); +- +- this.apn = checkNotNull(apn, "apn"); +- +- // Allocate a new APR pool. +- aprPool = Pool.create(0); +- +- // Create a new SSL_CTX and configure it. +- boolean success = false; +- try { +- synchronized (ReferenceCountedOpenSslContext.class) { +- try { +- ctx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, mode); +- } catch (Exception e) { +- throw new SSLException("failed to create an SSL_CTX", e); +- } +- +- SSLContext.setOptions(ctx, SSL.SSL_OP_ALL); +- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SSLv2); +- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SSLv3); +- SSLContext.setOptions(ctx, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); +- SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_ECDH_USE); +- SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_DH_USE); +- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); +- // 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. +- SSLContext.setOptions(ctx, 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[] protocols = nextProtoList.toArray(new String[nextProtoList.size()]); +- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior()); +- +- switch (apn.protocol()) { +- case NPN: +- SSLContext.setNpnProtos(ctx, protocols, selectorBehavior); +- break; +- case ALPN: +- SSLContext.setAlpnProtos(ctx, protocols, selectorBehavior); +- break; +- case NPN_AND_ALPN: +- SSLContext.setNpnProtos(ctx, protocols, selectorBehavior); +- SSLContext.setAlpnProtos(ctx, protocols, 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); +- } +- } +- 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 use {@link #sslCtxPointer()} +- */ +- @Deprecated +- public final long context() { +- return ctx; +- } +- +- /** +- * 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; +- } +- +- /** +- * 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. +- */ +- public final long sslCtxPointer() { +- return ctx; +- } +- +- // 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. +- final void destroy() { +- synchronized (ReferenceCountedOpenSslContext.class) { +- if (ctx != 0) { +- SSLContext.free(ctx); +- ctx = 0; +- } +- +- // Guard against multiple destroyPools() calls triggered by construction exception and finalize() later +- if (aprPool != 0) { +- Pool.destroy(aprPool); +- aprPool = 0; +- } +- } +- } +- +- 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 boolean release() { +- return refCnt.release(); +- } +- +- @Override +- public final boolean release(int decrement) { +- return refCnt.release(decrement); +- } +- +- abstract static class AbstractCertificateVerifier implements 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; +- +- if (cause instanceof 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 && cause instanceof CertificateRevokedException) { +- return CertificateVerifier.X509_V_ERR_CERT_REVOKED; +- } +- 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.slice().retain()); +- } +- +- ByteBuf buffer = allocator.directBuffer(content.readableBytes()); +- try { +- buffer.writeBytes(content, content.readerIndex(), content.readableBytes()); +- return newBIO(buffer.slice().retain()); +- } 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.writeToBIO(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 6b28ca0..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java ++++ /dev/null +@@ -1,1936 +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.buffer.Unpooled; +-import io.netty.util.AbstractReferenceCounted; +-import io.netty.util.ReferenceCounted; +-import io.netty.util.ResourceLeak; +-import io.netty.util.ResourceLeakDetector; +-import io.netty.util.ResourceLeakDetectorFactory; +-import io.netty.util.internal.EmptyArrays; +-import io.netty.util.internal.InternalThreadLocalMap; +-import io.netty.util.internal.PlatformDependent; +-import io.netty.util.internal.StringUtil; +-import io.netty.util.internal.ThrowableUtil; +-import io.netty.util.internal.logging.InternalLogger; +-import io.netty.util.internal.logging.InternalLoggerFactory; +-import org.apache.tomcat.jni.Buffer; +-import org.apache.tomcat.jni.SSL; +- +-import java.lang.reflect.InvocationTargetException; +-import java.lang.reflect.Method; +-import java.nio.ByteBuffer; +-import java.nio.ReadOnlyBufferException; +-import java.security.Principal; +-import java.security.cert.Certificate; +-import java.util.Arrays; +-import java.util.Collections; +-import java.util.HashMap; +-import java.util.List; +-import java.util.Map; +-import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +- +-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.util.internal.ObjectUtil.checkNotNull; +-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.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 SSLException ENCRYPTED_PACKET_OVERSIZED = ThrowableUtil.unknownStackTrace( +- new SSLException("encrypted packet oversized"), ReferenceCountedOpenSslEngine.class, "unwrap(...)"); +- private static final Class SNI_HOSTNAME_CLASS; +- private static final Method GET_SERVER_NAMES_METHOD; +- private static final Method SET_SERVER_NAMES_METHOD; +- private static final Method GET_ASCII_NAME_METHOD; +- private static final Method GET_USE_CIPHER_SUITES_ORDER_METHOD; +- private static final Method SET_USE_CIPHER_SUITES_ORDER_METHOD; +- private static final ResourceLeakDetector leakDetector = +- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class); +- +- static { +- AtomicIntegerFieldUpdater destroyedUpdater = +- PlatformDependent.newAtomicIntegerFieldUpdater(ReferenceCountedOpenSslEngine.class, "destroyed"); +- if (destroyedUpdater == null) { +- destroyedUpdater = AtomicIntegerFieldUpdater.newUpdater(ReferenceCountedOpenSslEngine.class, "destroyed"); +- } +- DESTROYED_UPDATER = destroyedUpdater; +- +- Method getUseCipherSuitesOrderMethod = null; +- Method setUseCipherSuitesOrderMethod = null; +- Class sniHostNameClass = null; +- Method getAsciiNameMethod = null; +- Method getServerNamesMethod = null; +- Method setServerNamesMethod = null; +- if (PlatformDependent.javaVersion() >= 8) { +- try { +- getUseCipherSuitesOrderMethod = SSLParameters.class.getDeclaredMethod("getUseCipherSuitesOrder"); +- SSLParameters parameters = new SSLParameters(); +- @SuppressWarnings("unused") +- Boolean order = (Boolean) getUseCipherSuitesOrderMethod.invoke(parameters); +- setUseCipherSuitesOrderMethod = SSLParameters.class.getDeclaredMethod("setUseCipherSuitesOrder", +- boolean.class); +- setUseCipherSuitesOrderMethod.invoke(parameters, true); +- } catch (Throwable ignore) { +- getUseCipherSuitesOrderMethod = null; +- setUseCipherSuitesOrderMethod = null; +- } +- try { +- sniHostNameClass = Class.forName("javax.net.ssl.SNIHostName", false, +- PlatformDependent.getClassLoader(ReferenceCountedOpenSslEngine.class)); +- Object sniHostName = sniHostNameClass.getConstructor(String.class).newInstance("netty.io"); +- getAsciiNameMethod = sniHostNameClass.getDeclaredMethod("getAsciiName"); +- @SuppressWarnings("unused") +- String name = (String) getAsciiNameMethod.invoke(sniHostName); +- +- getServerNamesMethod = SSLParameters.class.getDeclaredMethod("getServerNames"); +- setServerNamesMethod = SSLParameters.class.getDeclaredMethod("setServerNames", List.class); +- SSLParameters parameters = new SSLParameters(); +- @SuppressWarnings({ "rawtypes", "unused" }) +- List serverNames = (List) getServerNamesMethod.invoke(parameters); +- setServerNamesMethod.invoke(parameters, Collections.emptyList()); +- } catch (Throwable ingore) { +- sniHostNameClass = null; +- getAsciiNameMethod = null; +- getServerNamesMethod = null; +- setServerNamesMethod = null; +- } +- } +- GET_USE_CIPHER_SUITES_ORDER_METHOD = getUseCipherSuitesOrderMethod; +- SET_USE_CIPHER_SUITES_ORDER_METHOD = setUseCipherSuitesOrderMethod; +- SNI_HOSTNAME_CLASS = sniHostNameClass; +- GET_ASCII_NAME_METHOD = getAsciiNameMethod; +- GET_SERVER_NAMES_METHOD = getServerNamesMethod; +- SET_SERVER_NAMES_METHOD = setServerNamesMethod; +- } +- +- 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 AtomicIntegerFieldUpdater DESTROYED_UPDATER; +- +- private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL"; +- +- private static final long EMPTY_ADDR = Buffer.address(Unpooled.EMPTY_BUFFER.nioBuffer()); +- +- 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 receivedShutdown; +- private volatile int destroyed; +- +- // Reference Counting +- private final ResourceLeak leak; +- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { +- @Override +- protected void deallocate() { +- shutdown(); +- if (leak != null) { +- leak.close(); +- } +- } +- }; +- +- 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; +- +- // SSL Engine status variables +- private boolean isInboundDone; +- private boolean isOutboundDone; +- private boolean engineClosed; +- +- private final boolean clientMode; +- private final ByteBufAllocator alloc; +- private final OpenSslEngineMap engineMap; +- private final OpenSslApplicationProtocolNegotiator apn; +- private final boolean rejectRemoteInitiatedRenegation; +- 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; +- +- // 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.open(this) : null; +- this.alloc = checkNotNull(alloc, "alloc"); +- apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator(); +- ssl = SSL.newSSL(context.ctx, !context.isClient()); +- session = new ReferenceCountedOpenSslEngine.OpenSslSession(context.sessionContext()); +- networkBIO = SSL.makeNetworkBIO(ssl); +- clientMode = context.isClient(); +- engineMap = context.engineMap; +- rejectRemoteInitiatedRenegation = context.rejectRemoteInitiatedRenegotiation; +- localCerts = context.keyCertChain; +- +- // 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); +- +- // Use SNI if peerHost was specified +- // See https://github.com/netty/netty/issues/4746 +- if (clientMode && peerHost != null) { +- SSL.setTlsExtHostName(ssl, peerHost); +- } +- keyMaterialManager = context.keyMaterialManager(); +- } +- +- @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 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.freeBIO(networkBIO); +- ssl = networkBIO = 0; +- +- // internal errors can cause shutdown without marking the engine closed +- isInboundDone = isOutboundDone = engineClosed = 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) { +- final int pos = src.position(); +- final int limit = src.limit(); +- final int len = Math.min(limit - pos, MAX_PLAINTEXT_LENGTH); +- final int sslWrote; +- +- if (src.isDirect()) { +- final long addr = Buffer.address(src) + pos; +- sslWrote = SSL.writeToSSL(ssl, addr, len); +- if (sslWrote > 0) { +- src.position(pos + sslWrote); +- } +- } else { +- ByteBuf buf = alloc.directBuffer(len); +- try { +- final long addr = memoryAddress(buf); +- +- src.limit(pos + len); +- +- buf.setBytes(0, src); +- src.limit(limit); +- +- sslWrote = SSL.writeToSSL(ssl, addr, 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 int writeEncryptedData(final ByteBuffer src) { +- final int pos = src.position(); +- final int len = src.remaining(); +- final int netWrote; +- if (src.isDirect()) { +- final long addr = Buffer.address(src) + pos; +- netWrote = SSL.writeToBIO(networkBIO, addr, len); +- if (netWrote >= 0) { +- src.position(pos + netWrote); +- } +- } else { +- final ByteBuf buf = alloc.directBuffer(len); +- try { +- final long addr = memoryAddress(buf); +- +- buf.setBytes(0, src); +- +- netWrote = SSL.writeToBIO(networkBIO, addr, len); +- if (netWrote >= 0) { +- src.position(pos + netWrote); +- } else { +- src.position(pos); +- } +- } finally { +- buf.release(); +- } +- } +- +- return netWrote; +- } +- +- /** +- * Read plaintext data from the OpenSSL internal BIO +- */ +- private int readPlaintextData(final ByteBuffer dst) { +- final int sslRead; +- if (dst.isDirect()) { +- final int pos = dst.position(); +- final long addr = Buffer.address(dst) + pos; +- final int len = dst.limit() - pos; +- sslRead = SSL.readFromSSL(ssl, addr, len); +- if (sslRead > 0) { +- dst.position(pos + sslRead); +- } +- } else { +- final int pos = dst.position(); +- final int limit = dst.limit(); +- final int len = Math.min(MAX_ENCRYPTED_PACKET_LENGTH, limit - pos); +- final ByteBuf buf = alloc.directBuffer(len); +- try { +- final long addr = memoryAddress(buf); +- +- sslRead = SSL.readFromSSL(ssl, addr, len); +- if (sslRead > 0) { +- dst.limit(pos + sslRead); +- buf.getBytes(0, dst); +- dst.limit(limit); +- } +- } finally { +- buf.release(); +- } +- } +- +- return sslRead; +- } +- +- /** +- * Read encrypted data from the OpenSSL network BIO +- */ +- private int readEncryptedData(final ByteBuffer dst, final int pending) { +- final int bioRead; +- +- if (dst.isDirect() && dst.remaining() >= pending) { +- final int pos = dst.position(); +- final long addr = Buffer.address(dst) + pos; +- bioRead = SSL.readFromBIO(networkBIO, addr, pending); +- if (bioRead > 0) { +- dst.position(pos + bioRead); +- return bioRead; +- } +- } else { +- final ByteBuf buf = alloc.directBuffer(pending); +- try { +- final long addr = memoryAddress(buf); +- +- bioRead = SSL.readFromBIO(networkBIO, addr, pending); +- if (bioRead > 0) { +- int oldLimit = dst.limit(); +- dst.limit(dst.position() + bioRead); +- buf.getBytes(0, dst); +- dst.limit(oldLimit); +- return bioRead; +- } +- } finally { +- buf.release(); +- } +- } +- +- return bioRead; +- } +- +- private SSLEngineResult readPendingBytesFromBIO(ByteBuffer dst, int bytesConsumed, int bytesProduced, +- SSLEngineResult.HandshakeStatus status) throws SSLException { +- // Check to see if the engine wrote data into the network BIO +- int pendingNet = SSL.pendingWrittenBytesInBIO(networkBIO); +- if (pendingNet > 0) { +- +- // Do we have enough room in dst to write encrypted data? +- int capacity = dst.remaining(); +- if (capacity < pendingNet) { +- return new SSLEngineResult(BUFFER_OVERFLOW, +- mayFinishHandshake(status != FINISHED ? getHandshakeStatus(pendingNet) : status), +- bytesConsumed, bytesProduced); +- } +- +- // Write the pending data from the network BIO into the dst buffer +- int produced = readEncryptedData(dst, pendingNet); +- +- if (produced <= 0) { +- // We ignore BIO_* errors here as we use in memory BIO anyway and will do another SSL_* call later +- // on in which we will produce an exception in case of an error +- SSL.clearError(); +- } else { +- bytesProduced += produced; +- pendingNet -= produced; +- } +- // If isOuboundDone is set, then the data from the network BIO +- // was the close_notify message -- we are not required to wait +- // for the receipt the peer's close_notify message -- shutdown. +- if (isOutboundDone) { +- shutdown(); +- } +- +- return new SSLEngineResult(getEngineStatus(), +- mayFinishHandshake(status != FINISHED ? getHandshakeStatus(pendingNet) : status), +- bytesConsumed, bytesProduced); +- } +- return null; +- } +- +- @Override +- public final SSLEngineResult wrap( +- final ByteBuffer[] srcs, final 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) { +- // Check to make sure the engine has not been closed +- if (isDestroyed()) { +- return CLOSED_NOT_HANDSHAKING; +- } +- +- 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_UNWRAP) { +- return NEED_UNWRAP_OK; +- } +- +- if (engineClosed) { +- return NEED_UNWRAP_CLOSED; +- } +- } +- +- // There was no pending data in the network BIO -- encrypt any application data +- int bytesProduced = 0; +- int bytesConsumed = 0; +- 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"); +- } +- while (src.hasRemaining()) { +- final SSLEngineResult pendingNetResult; +- // Write plaintext application data to the SSL engine +- int result = writePlaintextData(src); +- if (result > 0) { +- bytesConsumed += result; +- +- pendingNetResult = readPendingBytesFromBIO(dst, bytesConsumed, bytesProduced, status); +- if (pendingNetResult != null) { +- if (pendingNetResult.getStatus() != OK) { +- return pendingNetResult; +- } +- bytesProduced = pendingNetResult.bytesProduced(); +- } +- } else { +- int sslError = SSL.getError(ssl, result); +- switch (sslError) { +- case SSL.SSL_ERROR_ZERO_RETURN: +- // This means the connection was shutdown correctly, close inbound and outbound +- if (!receivedShutdown) { +- closeAll(); +- } +- pendingNetResult = readPendingBytesFromBIO(dst, bytesConsumed, bytesProduced, status); +- return pendingNetResult != null ? pendingNetResult : CLOSED_NOT_HANDSHAKING; +- case 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 +- pendingNetResult = readPendingBytesFromBIO(dst, bytesConsumed, bytesProduced, status); +- return pendingNetResult != null ? pendingNetResult : +- new SSLEngineResult(getEngineStatus(), +- NEED_UNWRAP, bytesConsumed, bytesProduced); +- case 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 +- pendingNetResult = readPendingBytesFromBIO(dst, bytesConsumed, bytesProduced, status); +- return pendingNetResult != null ? pendingNetResult : NEED_WRAP_CLOSED; +- default: +- // Everything else is considered as error +- throw shutdownWithError("SSL_write"); +- } +- } +- } +- } +- // We need to check if pendingWrittenBytesInBIO was checked yet, as we may not checked if the srcs was +- // empty, or only contained empty buffers. +- if (bytesConsumed == 0) { +- SSLEngineResult pendingNetResult = readPendingBytesFromBIO(dst, 0, bytesProduced, status); +- if (pendingNetResult != null) { +- return pendingNetResult; +- } +- } +- +- return newResult(bytesConsumed, bytesProduced, status); +- } +- } +- +- /** +- * 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, final 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 endOffset = dstsOffset + dstsLength; +- for (int i = dstsOffset; i < endOffset; 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) { +- // Check to make sure the engine has not been closed +- if (isDestroyed()) { +- return CLOSED_NOT_HANDSHAKING; +- } +- +- // protect against protocol overflow attack vector +- if (len > MAX_ENCRYPTED_PACKET_LENGTH) { +- isInboundDone = true; +- isOutboundDone = true; +- engineClosed = true; +- shutdown(); +- throw ENCRYPTED_PACKET_OVERSIZED; +- } +- +- 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; +- } +- if (engineClosed) { +- return NEED_WRAP_CLOSED; +- } +- } +- +- // Write encrypted data to network BIO +- int bytesConsumed = 0; +- if (srcsOffset < srcsEndOffset) { +- do { +- 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. +- srcsOffset++; +- continue; +- } +- int written = writeEncryptedData(src); +- if (written > 0) { +- bytesConsumed += written; +- +- if (written == remaining) { +- srcsOffset++; +- } else { +- // We were not able to write everything into the BIO so break the write loop as otherwise +- // we will produce an error on the next write attempt, which will trigger a SSL.clearError() +- // later. +- break; +- } +- } else { +- // BIO_write returned a negative or zero number, this means we could not complete the write +- // operation and should retry later. +- // We ignore BIO_* errors here as we use in memory BIO anyway and will do another SSL_* call +- // later on in which we will produce an exception in case of an error +- SSL.clearError(); +- break; +- } +- } while (srcsOffset < srcsEndOffset); +- } +- +- // Number of produced bytes +- int bytesProduced = 0; +- +- if (capacity > 0) { +- // Write decrypted data to dsts buffers +- int idx = dstsOffset; +- while (idx < endOffset) { +- ByteBuffer dst = dsts[idx]; +- if (!dst.hasRemaining()) { +- idx++; +- continue; +- } +- +- int bytesRead = readPlaintextData(dst); +- +- // TODO: We may want to consider if we move this check and only do it in a less often called place +- // at the price of not being 100% accurate, like for example when calling SSL.getError(...). +- rejectRemoteInitiatedRenegation(); +- +- if (bytesRead > 0) { +- bytesProduced += bytesRead; +- +- if (!dst.hasRemaining()) { +- idx++; +- } else { +- // We read everything return now. +- return newResult(bytesConsumed, bytesProduced, status); +- } +- } else { +- int sslError = SSL.getError(ssl, bytesRead); +- switch (sslError) { +- case SSL.SSL_ERROR_ZERO_RETURN: +- // This means the connection was shutdown correctly, close inbound and outbound +- if (!receivedShutdown) { +- closeAll(); +- } +- // fall-trough! +- case SSL.SSL_ERROR_WANT_READ: +- case SSL.SSL_ERROR_WANT_WRITE: +- // break to the outer loop +- return newResult(bytesConsumed, bytesProduced, status); +- default: +- return sslReadErrorResult(SSL.getLastErrorNumber(), bytesConsumed, bytesProduced); +- } +- } +- } +- } else { +- // If the capacity of all destination buffers is 0 we need to trigger a SSL_read anyway to ensure +- // everything is flushed in the BIO pair and so we can detect it in the pendingAppData() call. +- if (SSL.readFromSSL(ssl, EMPTY_ADDR, 0) <= 0) { +- // We do not check SSL_get_error as we are not interested in any error that is not fatal. +- int err = SSL.getLastErrorNumber(); +- if (OpenSsl.isError(err)) { +- return sslReadErrorResult(err, bytesConsumed, bytesProduced); +- } +- } +- } +- if (pendingAppData() > 0) { +- // We filled all buffers but there is still some data pending in the BIO buffer, return BUFFER_OVERFLOW. +- return new SSLEngineResult( +- BUFFER_OVERFLOW, mayFinishHandshake(status != FINISHED ? getHandshakeStatus() : status), +- bytesConsumed, bytesProduced); +- } +- +- // 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 newResult(bytesConsumed, bytesProduced, status); +- } +- } +- +- 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.pendingWrittenBytesInBIO(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 int pendingAppData() { +- // There won't be any application data until we're done handshaking. +- // We first check handshakeFinished to eliminate the overhead of extra JNI call if possible. +- return handshakeState == HandshakeState.FINISHED ? SSL.pendingReadableBytesInSSL(ssl) : 0; +- } +- +- private SSLEngineResult newResult( +- int bytesConsumed, int bytesProduced, SSLEngineResult.HandshakeStatus status) throws SSLException { +- return new SSLEngineResult( +- getEngineStatus(), mayFinishHandshake(status != FINISHED ? getHandshakeStatus() : status) +- , bytesConsumed, bytesProduced); +- } +- +- private void closeAll() throws SSLException { +- receivedShutdown = true; +- closeOutbound(); +- closeInbound(); +- } +- +- private void rejectRemoteInitiatedRenegation() throws SSLHandshakeException { +- if (rejectRemoteInitiatedRenegation && 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 renegotation 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; +- engineClosed = true; +- +- 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 || engineClosed; +- } +- +- @Override +- public final synchronized void closeOutbound() { +- if (isOutboundDone) { +- return; +- } +- +- isOutboundDone = true; +- engineClosed = true; +- +- if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) { +- int mode = SSL.getShutdown(ssl); +- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) { +- int err = SSL.shutdownSSL(ssl); +- if (err < 0) { +- int sslErr = SSL.getError(ssl, err); +- switch (sslErr) { +- case SSL.SSL_ERROR_NONE: +- case SSL.SSL_ERROR_WANT_ACCEPT: +- case SSL.SSL_ERROR_WANT_CONNECT: +- case SSL.SSL_ERROR_WANT_WRITE: +- case SSL.SSL_ERROR_WANT_READ: +- case SSL.SSL_ERROR_WANT_X509_LOOKUP: +- case SSL.SSL_ERROR_ZERO_RETURN: +- // Nothing to do here +- break; +- case SSL.SSL_ERROR_SYSCALL: +- case SSL.SSL_ERROR_SSL: +- if (logger.isDebugEnabled()) { +- logger.debug("SSL_shutdown failed: OpenSSL error: {}", SSL.getLastError()); +- } +- // There was an internal error -- shutdown +- shutdown(); +- break; +- default: +- SSL.clearError(); +- break; +- } +- } +- } +- } else { +- // engine closing before initial handshake +- shutdown(); +- } +- } +- +- @Override +- public final synchronized boolean isOutboundDone() { +- return isOutboundDone; +- } +- +- @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 = InternalThreadLocalMap.get().arrayList(); +- // Seems like there is no way to explict 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 ((opts & SSL.SSL_OP_NO_TLSv1) == 0) { +- enabled.add(OpenSsl.PROTOCOL_TLS_V1); +- } +- if ((opts & SSL.SSL_OP_NO_TLSv1_1) == 0) { +- enabled.add(OpenSsl.PROTOCOL_TLS_V1_1); +- } +- if ((opts & SSL.SSL_OP_NO_TLSv1_2) == 0) { +- enabled.add(OpenSsl.PROTOCOL_TLS_V1_2); +- } +- if ((opts & SSL.SSL_OP_NO_SSLv2) == 0) { +- enabled.add(OpenSsl.PROTOCOL_SSL_V2); +- } +- if ((opts & SSL.SSL_OP_NO_SSLv3) == 0) { +- enabled.add(OpenSsl.PROTOCOL_SSL_V3); +- } +- return enabled.toArray(new String[enabled.size()]); +- } +- +- @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()) { +- // Enable all and then disable what we not want +- SSL.setOptions(ssl, SSL.SSL_OP_ALL); +- +- // 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) +- // +- // Bcause 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 +- if (SSL.renegotiate(ssl) != 1 || SSL.doHandshake(ssl) != 1) { +- 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 (engineClosed || 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 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.pendingWrittenBytesInBIO(networkBIO) > 0) { +- // There is something pending, we need to consume it first via a WRAP so we not 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); +- +- switch (sslError) { +- case SSL.SSL_ERROR_WANT_READ: +- case SSL.SSL_ERROR_WANT_WRITE: +- return pendingStatus(SSL.pendingWrittenBytesInBIO(networkBIO)); +- default: +- // 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.Status getEngineStatus() { +- return engineClosed? CLOSED : OK; +- } +- +- 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.pendingWrittenBytesInBIO(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 || engineClosed); +- } +- +- /** +- * 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.length() == 0) { +- 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; +- } +- +- 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, OpenSslContext.VERIFY_DEPTH); +- break; +- case REQUIRE: +- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRE, OpenSslContext.VERIFY_DEPTH); +- break; +- case OPTIONAL: +- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, OpenSslContext.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); +- SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints); +- if (version >= 8) { +- if (SET_SERVER_NAMES_METHOD != null && sniHostNames != null) { +- try { +- SET_SERVER_NAMES_METHOD.invoke(sslParameters, sniHostNames); +- } catch (IllegalAccessException e) { +- throw new Error(e); +- } catch (InvocationTargetException e) { +- throw new Error(e); +- } +- } +- if (SET_USE_CIPHER_SUITES_ORDER_METHOD != null && !isDestroyed()) { +- try { +- SET_USE_CIPHER_SUITES_ORDER_METHOD.invoke(sslParameters, +- (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0); +- } catch (IllegalAccessException e) { +- throw new Error(e); +- } catch (InvocationTargetException e) { +- throw new Error(e); +- } +- } +- } +- } +- return sslParameters; +- } +- +- @Override +- public final synchronized void setSSLParameters(SSLParameters sslParameters) { +- super.setSSLParameters(sslParameters); +- +- int version = PlatformDependent.javaVersion(); +- if (version >= 7) { +- endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm(); +- algorithmConstraints = sslParameters.getAlgorithmConstraints(); +- if (version >= 8) { +- if (SNI_HOSTNAME_CLASS != null && clientMode && !isDestroyed()) { +- assert GET_SERVER_NAMES_METHOD != null; +- assert GET_ASCII_NAME_METHOD != null; +- try { +- List servernames = (List) GET_SERVER_NAMES_METHOD.invoke(sslParameters); +- if (servernames != null) { +- for (Object serverName : servernames) { +- if (SNI_HOSTNAME_CLASS.isInstance(serverName)) { +- SSL.setTlsExtHostName(ssl, (String) GET_ASCII_NAME_METHOD.invoke(serverName)); +- } else { +- throw new IllegalArgumentException("Only " + SNI_HOSTNAME_CLASS.getName() +- + " instances are supported, but found: " + +- serverName); +- } +- } +- } +- sniHostNames = servernames; +- } catch (IllegalAccessException e) { +- throw new Error(e); +- } catch (InvocationTargetException e) { +- throw new Error(e); +- } +- } +- if (GET_USE_CIPHER_SUITES_ORDER_METHOD != null && !isDestroyed()) { +- try { +- if ((Boolean) GET_USE_CIPHER_SUITES_ORDER_METHOD.invoke(sslParameters)) { +- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); +- } else { +- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); +- } +- } catch (IllegalAccessException e) { +- throw new Error(e); +- } catch (InvocationTargetException e) { +- throw new Error(e); +- } +- } +- } +- } +- } +- +- private boolean isDestroyed() { +- return destroyed != 0; +- } +- +- 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 String protocol; +- private String applicationProtocol; +- private Certificate[] peerCerts; +- 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); +- final byte[] clientCert; +- if (!clientMode) { +- // 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 +- clientCert = SSL.getPeerCertificate(ssl); +- } else { +- clientCert = null; +- } +- +- if (chain == null || chain.length == 0) { +- if (clientCert == null || clientCert.length == 0) { +- peerCerts = EmptyArrays.EMPTY_CERTIFICATES; +- x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES; +- } else { +- peerCerts = new Certificate[1]; +- x509PeerCerts = new X509Certificate[1]; +- +- peerCerts[0] = new OpenSslX509Certificate(clientCert); +- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert); +- } +- } else if (clientCert == null || clientCert.length == 0) { +- peerCerts = new Certificate[chain.length]; +- x509PeerCerts = new X509Certificate[chain.length]; +- +- for (int a = 0; a < chain.length; ++a) { +- byte[] bytes = chain[a]; +- peerCerts[a] = new OpenSslX509Certificate(bytes); +- x509PeerCerts[a] = new OpenSslJavaxX509Certificate(bytes); +- } +- } else { +- int len = clientCert.length + 1; +- peerCerts = new Certificate[len]; +- x509PeerCerts = new X509Certificate[len]; +- +- peerCerts[0] = new OpenSslX509Certificate(clientCert); +- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert); +- +- for (int a = 0, i = 1; a < chain.length; ++a, ++i) { +- byte[] bytes = chain[a]; +- peerCerts[i] = new OpenSslX509Certificate(bytes); +- x509PeerCerts[i] = new OpenSslJavaxX509Certificate(bytes); +- } +- } +- } +- +- /** +- * 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 (peerCerts == null || peerCerts.length == 0) { +- 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 (x509PeerCerts == null || x509PeerCerts.length == 0) { +- 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 ace2153..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java ++++ /dev/null +@@ -1,195 +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.apache.tomcat.jni.SSL; +-import org.apache.tomcat.jni.SSLContext; +- +-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 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, boolean startTls) throws SSLException { +- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, +- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, startTls); +- } +- +- 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, boolean startTls) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, +- clientAuth, startTls, 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(); +- synchronized (ReferenceCountedOpenSslContext.class) { +- 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"); +- +- /* Set certificate verification policy. */ +- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); +- +- 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)); +- } +- } 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); +- } +- } +-} +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 9a40d92..b76e4af 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java ++++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java +@@ -114,11 +114,7 @@ public abstract class SslContext { + } + + private static SslProvider defaultProvider() { +- if (OpenSsl.isAvailable()) { +- return SslProvider.OPENSSL; +- } else { +- return SslProvider.JDK; +- } ++ return SslProvider.JDK; + } + + /** +@@ -410,16 +406,6 @@ public abstract class SslContext { + trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, + keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, + clientAuth, startTls); +- case OPENSSL: +- return new OpenSslServerContext( +- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, +- clientAuth, startTls); +- case OPENSSL_REFCNT: +- return new ReferenceCountedOpenSslServerContext( +- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, +- clientAuth, startTls); + default: + throw new Error(provider.toString()); + } +@@ -751,14 +737,6 @@ public abstract class SslContext { + return new JdkSslClientContext( + trustCert, trustManagerFactory, keyCertChain, key, keyPassword, + keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); +- case OPENSSL: +- return new OpenSslClientContext( +- trustCert, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); +- case OPENSSL_REFCNT: +- return new ReferenceCountedOpenSslClientContext( +- trustCert, trustManagerFactory, keyCertChain, key, keyPassword, +- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); + 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 55c09ae..a9cb9ae 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,14 @@ import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength; + */ + 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); + +@@ -281,7 +289,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + this.startTls = startTls; + maxPacketBufferSize = engine.getSession().getPacketBufferSize(); + +- boolean opensslEngine = engine instanceof OpenSslEngine; ++ boolean opensslEngine = false; + wantsDirectBuffer = opensslEngine; + wantsLargeOutboundNetworkBuffer = !opensslEngine; + +@@ -415,9 +423,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + // Check if queue is not empty first because create a new ChannelException is expensive + pendingUnencryptedWrites.removeAndFailAll(new ChannelException("Pending write on removal of SslHandler")); + } +- if (engine instanceof ReferenceCountedOpenSslEngine) { +- ((ReferenceCountedOpenSslEngine) engine).release(); +- } + } + + @Override +@@ -853,7 +858,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + + boolean nonSslRecord = false; + +- while (totalLength < OpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { ++ while (totalLength < MAX_ENCRYPTED_PACKET_LENGTH) { + final int readableBytes = endOffset - offset; + if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) { + break; +@@ -874,7 +879,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + } + + int newTotalLength = totalLength + packetLength; +- if (newTotalLength > OpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { ++ if (newTotalLength > MAX_ENCRYPTED_PACKET_LENGTH) { + // Don't read too much. + break; + } +@@ -1076,27 +1081,10 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + + private SSLEngineResult unwrap( + SSLEngine engine, ByteBuf in, int readerIndex, int len, ByteBuf out) throws SSLException { +- int nioBufferCount = in.nioBufferCount(); + int writerIndex = out.writerIndex(); + final SSLEngineResult result; +- if (engine instanceof OpenSslEngine && 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. +- */ +- OpenSslEngine opensslEngine = (OpenSslEngine) engine; +- try { +- singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes()); +- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), singleBuffer); +- out.writerIndex(writerIndex + result.bytesProduced()); +- } finally { +- singleBuffer[0] = null; +- } +- } else { +- result = engine.unwrap(toByteBuffer(in, readerIndex, len), ++ result = engine.unwrap(toByteBuffer(in, readerIndex, len), + toByteBuffer(out, writerIndex, out.writableBytes())); +- } + out.writerIndex(writerIndex + result.bytesProduced()); + return result; + } +@@ -1482,7 +1470,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + return allocate(ctx, maxPacketBufferSize); + } else { + return allocate(ctx, Math.min( +- pendingBytes + OpenSslEngine.MAX_ENCRYPTION_OVERHEAD_LENGTH, ++ pendingBytes + MAX_ENCRYPTION_OVERHEAD_LENGTH, + maxPacketBufferSize)); + } + } +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 381df73..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java ++++ /dev/null +@@ -1,37 +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 static org.junit.Assume.assumeTrue; +- +-public class JdkOpenSslEngineInteroptTest extends SSLEngineTest { +- @BeforeClass +- public static void checkOpenSsl() { +- assumeTrue(OpenSsl.isAvailable()); +- } +- +- @Override +- protected SslProvider sslClientProvider() { +- return SslProvider.JDK; +- } +- +- @Override +- protected SslProvider sslServerProvider() { +- return SslProvider.OPENSSL; +- } +-} +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 2ef0a6c..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java ++++ /dev/null +@@ -1,129 +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.ThreadLocalRandom; +-import org.junit.BeforeClass; +-import org.junit.Test; +- +-import java.nio.ByteBuffer; +- +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLEngineResult; +- +-import static org.junit.Assert.assertNull; +-import static org.junit.Assert.assertSame; +-import static org.junit.Assume.assumeTrue; +- +-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"; +- +- @BeforeClass +- public static void checkOpenSsl() { +- assumeTrue(OpenSsl.isAvailable()); +- } +- +- @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 testWrapHeapBuffersNoWritePendingError() 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 = ByteBuffer.allocate(1024 * 10); +- ThreadLocalRandom.current().nextBytes(src.array()); +- ByteBuffer dst = ByteBuffer.allocate(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); +- } +- } +- +- @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 9954f69..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.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 org.junit.BeforeClass; +- +-import static org.junit.Assume.assumeTrue; +- +-public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest { +- +- @BeforeClass +- public static void checkOpenSsl() { +- assumeTrue(OpenSsl.isAvailable()); +- } +- +- @Override +- protected SslProvider sslClientProvider() { +- return SslProvider.OPENSSL; +- } +- +- @Override +- protected SslProvider sslServerProvider() { +- return SslProvider.JDK; +- } +-} +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/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 40b3193..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java ++++ /dev/null +@@ -1,52 +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 { +- @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 +index 1ad3c56..2bb510d 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java ++++ b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java +@@ -40,24 +40,6 @@ public class SniClientTest { + testSniClient(SslProvider.JDK, SslProvider.JDK); + } + +- @Test(timeout = 5000) +- public void testSniClientOpenSslServerOpenSsl() throws Exception { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL); +- } +- +- @Test(timeout = 5000) +- public void testSniClientJdkSslServerOpenSsl() throws Exception { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- testSniClient(SslProvider.JDK, SslProvider.OPENSSL); +- } +- +- @Test(timeout = 5000) +- public void testSniClientOpenSslServerJdkSsl() throws Exception { +- Assume.assumeTrue(OpenSsl.isAvailable()); +- testSniClient(SslProvider.OPENSSL, SslProvider.JDK); +- } +- + @SuppressWarnings("deprecation") + private static void testSniClient(SslProvider sslClientProvider, SslProvider sslServerProvider) throws Exception { + final String sniHost = "sni.netty.io"; +diff --git a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java b/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java +index 752424c..4cd3c76 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java ++++ b/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java +@@ -33,44 +33,20 @@ public class SslContextBuilderTest { + } + + @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() +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 7d50460..ddcf3bd 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java ++++ b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java +@@ -94,34 +94,6 @@ public class SslHandlerTest { + ch.writeOutbound(new Object()); + } + +- @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()); +- +- 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; + +-- +2.7.4 + diff --git a/0002-Remove-NPN-ALPN.patch b/0002-Remove-NPN-ALPN.patch new file mode 100644 index 0000000..73749cc --- /dev/null +++ b/0002-Remove-NPN-ALPN.patch @@ -0,0 +1,884 @@ +From cfb6f2a620525a94d6964c287792f2645bff4f4a Mon Sep 17 00:00:00 2001 +From: Severin Gehwolf +Date: Thu, 20 Oct 2016 16:18:10 +0200 +Subject: [PATCH 2/2] Remove NPN ALPN + +--- + .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 120 --------- + .../io/netty/handler/ssl/JdkAlpnSslEngine.java | 124 ---------- + .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 --------- + .../java/io/netty/handler/ssl/JdkNpnSslEngine.java | 122 --------- + .../java/io/netty/handler/ssl/JdkSslContext.java | 44 ---- + .../io/netty/handler/ssl/JdkSslEngineTest.java | 273 --------------------- + 6 files changed, 803 deletions(-) + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java + +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +deleted file mode 100644 +index aaaf5b7..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java ++++ /dev/null +@@ -1,120 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import javax.net.ssl.SSLEngine; +- +-/** +- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}. +- */ +-public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { +- private static final SslEngineWrapperFactory ALPN_WRAPPER = new SslEngineWrapperFactory() { +- { +- if (!JdkAlpnSslEngine.isAvailable()) { +- throw new RuntimeException("ALPN unsupported. Is your classpatch configured correctly?" +- + " See http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-starting"); +- } +- } +- +- @Override +- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, +- boolean isServer) { +- return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer); +- } +- }; +- +- /** +- * Create a new instance. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkAlpnApplicationProtocolNegotiator(Iterable protocols) { +- this(false, protocols); +- } +- +- /** +- * Create a new instance. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkAlpnApplicationProtocolNegotiator(String... protocols) { +- this(false, protocols); +- } +- +- /** +- * Create a new instance. +- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable protocols) { +- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); +- } +- +- /** +- * Create a new instance. +- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) { +- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); +- } +- +- /** +- * Create a new instance. +- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. +- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, +- boolean serverFailIfNoCommonProtocols, Iterable protocols) { +- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, +- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, +- protocols); +- } +- +- /** +- * Create a new instance. +- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. +- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, +- boolean serverFailIfNoCommonProtocols, String... protocols) { +- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, +- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, +- protocols); +- } +- +- /** +- * Create a new instance. +- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. +- * @param listenerFactory The factory which provides to be notified of which protocol was selected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, +- ProtocolSelectionListenerFactory listenerFactory, Iterable protocols) { +- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols); +- } +- +- /** +- * Create a new instance. +- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. +- * @param listenerFactory The factory which provides to be notified of which protocol was selected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, +- ProtocolSelectionListenerFactory listenerFactory, String... protocols) { +- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols); +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java +deleted file mode 100644 +index bdf3aca..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java ++++ /dev/null +@@ -1,124 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +- +-import java.util.LinkedHashSet; +-import java.util.List; +- +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +-import javax.net.ssl.SSLHandshakeException; +- +-import org.eclipse.jetty.alpn.ALPN; +-import org.eclipse.jetty.alpn.ALPN.ClientProvider; +-import org.eclipse.jetty.alpn.ALPN.ServerProvider; +- +-final class JdkAlpnSslEngine extends JdkSslEngine { +- private static boolean available; +- +- static boolean isAvailable() { +- updateAvailability(); +- return available; +- } +- +- private static void updateAvailability() { +- if (available) { +- return; +- } +- +- try { +- // Always use bootstrap class loader. +- Class.forName("sun.security.ssl.ALPNExtension", true, null); +- available = true; +- } catch (Exception ignore) { +- // alpn-boot was not loaded. +- } +- } +- +- JdkAlpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) { +- super(engine); +- checkNotNull(applicationNegotiator, "applicationNegotiator"); +- +- if (server) { +- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() +- .newSelector(this, new LinkedHashSet(applicationNegotiator.protocols())), +- "protocolSelector"); +- ALPN.put(engine, new ServerProvider() { +- @Override +- public String select(List protocols) throws SSLException { +- try { +- return protocolSelector.select(protocols); +- } catch (SSLHandshakeException e) { +- throw e; +- } catch (Throwable t) { +- SSLHandshakeException e = new SSLHandshakeException(t.getMessage()); +- e.initCause(t); +- throw e; +- } +- } +- +- @Override +- public void unsupported() { +- protocolSelector.unsupported(); +- } +- }); +- } else { +- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator +- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), +- "protocolListener"); +- ALPN.put(engine, new ClientProvider() { +- @Override +- public List protocols() { +- return applicationNegotiator.protocols(); +- } +- +- @Override +- public void selected(String protocol) throws SSLException { +- try { +- protocolListener.selected(protocol); +- } catch (SSLHandshakeException e) { +- throw e; +- } catch (Throwable t) { +- SSLHandshakeException e = new SSLHandshakeException(t.getMessage()); +- e.initCause(t); +- throw e; +- } +- } +- +- @Override +- public void unsupported() { +- protocolListener.unsupported(); +- } +- }); +- } +- } +- +- @Override +- public void closeInbound() throws SSLException { +- ALPN.remove(getWrappedEngine()); +- super.closeInbound(); +- } +- +- @Override +- public void closeOutbound() { +- ALPN.remove(getWrappedEngine()); +- super.closeOutbound(); +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java +deleted file mode 100644 +index c893f05..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java ++++ /dev/null +@@ -1,120 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import javax.net.ssl.SSLEngine; +- +-/** +- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}. +- */ +-public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { +- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() { +- { +- if (!JdkNpnSslEngine.isAvailable()) { +- throw new RuntimeException("NPN unsupported. Is your classpatch configured correctly?" +- + " See http://www.eclipse.org/jetty/documentation/current/npn-chapter.html#npn-starting"); +- } +- } +- +- @Override +- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, +- boolean isServer) { +- return new JdkNpnSslEngine(engine, applicationNegotiator, isServer); +- } +- }; +- +- /** +- * Create a new instance. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(Iterable 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/JdkNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java +deleted file mode 100644 +index 422727a..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java ++++ /dev/null +@@ -1,122 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-package io.netty.handler.ssl; +- +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +-import io.netty.util.internal.PlatformDependent; +- +-import java.util.LinkedHashSet; +-import java.util.List; +- +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +- +-import org.eclipse.jetty.npn.NextProtoNego; +-import org.eclipse.jetty.npn.NextProtoNego.ClientProvider; +-import org.eclipse.jetty.npn.NextProtoNego.ServerProvider; +- +-final class JdkNpnSslEngine extends JdkSslEngine { +- private static boolean available; +- +- static boolean isAvailable() { +- updateAvailability(); +- return available; +- } +- +- private static void updateAvailability() { +- if (available) { +- return; +- } +- try { +- // Always use bootstrap class loader. +- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null); +- available = true; +- } catch (Exception ignore) { +- // npn-boot was not loaded. +- } +- } +- +- JdkNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) { +- super(engine); +- checkNotNull(applicationNegotiator, "applicationNegotiator"); +- +- if (server) { +- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator +- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), +- "protocolListener"); +- NextProtoNego.put(engine, new ServerProvider() { +- @Override +- public void unsupported() { +- protocolListener.unsupported(); +- } +- +- @Override +- public List 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/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java +index 0a120eb..cdad232 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java ++++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java +@@ -270,50 +270,6 @@ public class JdkSslContext extends SslContext { + switch(config.protocol()) { + case NONE: + return JdkDefaultApplicationProtocolNegotiator.INSTANCE; +- case ALPN: +- if (isServer) { +- switch(config.selectorFailureBehavior()) { +- case FATAL_ALERT: +- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); +- case NO_ADVERTISE: +- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); +- default: +- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") +- .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); +- } +- } else { +- switch(config.selectedListenerFailureBehavior()) { +- case ACCEPT: +- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); +- case FATAL_ALERT: +- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); +- default: +- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") +- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); +- } +- } +- case NPN: +- if (isServer) { +- switch(config.selectedListenerFailureBehavior()) { +- case ACCEPT: +- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); +- case FATAL_ALERT: +- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); +- default: +- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") +- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); +- } +- } else { +- switch(config.selectorFailureBehavior()) { +- case FATAL_ALERT: +- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); +- case NO_ADVERTISE: +- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); +- default: +- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") +- .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); +- } +- } + default: + throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") + .append(config.protocol()).append(" protocol").toString()); +diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +index 9a57230..090f996 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java ++++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +@@ -15,262 +15,15 @@ + */ + package io.netty.handler.ssl; + +-import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; +-import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior; +-import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectorFactory; +-import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +-import io.netty.handler.ssl.util.SelfSignedCertificate; + import org.junit.Test; + +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLHandshakeException; +-import java.util.List; +-import java.util.Set; +-import java.util.concurrent.TimeUnit; +- +-import static org.junit.Assert.assertNull; +-import static org.junit.Assert.assertTrue; +-import static org.junit.Assume.assumeNoException; +- + public class JdkSslEngineTest extends SSLEngineTest { +- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2"; +- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1"; +- private static final String APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE = "my-protocol-FOO"; +- +- @Test +- public void testNpn() throws Exception { +- try { +- // Typical code will not have to check this, but will get a initialization error on class load. +- // Check in this test just in case we have multiple tests that just the class and we already ignored the +- // initialization error. +- if (!JdkNpnSslEngine.isAvailable()) { +- throw tlsExtensionNotFound(Protocol.NPN); +- } +- ApplicationProtocolConfig apn = failingNegotiator(Protocol.NPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- setupHandlers(apn); +- runTest(); +- } catch (SkipTestException e) { +- // NPN availability is dependent on the java version. If NPN is not available because of +- // java version incompatibility don't fail the test, but instead just skip the test +- assumeNoException(e); +- } +- } +- +- @Test +- public void testNpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception { +- try { +- // Typical code will not have to check this, but will get a initialization error on class load. +- // Check in this test just in case we have multiple tests that just the class and we already ignored the +- // initialization error. +- if (!JdkNpnSslEngine.isAvailable()) { +- throw tlsExtensionNotFound(Protocol.NPN); +- } +- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN, +- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); +- setupHandlers(serverApn, clientApn); +- runTest(null); +- } catch (SkipTestException e) { +- // ALPN availability is dependent on the java version. If ALPN is not available because of +- // java version incompatibility don't fail the test, but instead just skip the test +- assumeNoException(e); +- } +- } +- +- @Test +- public void testNpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception { +- try { +- // Typical code will not have to check this, but will get a initialization error on class load. +- // Check in this test just in case we have multiple tests that just the class and we already ignored the +- // initialization error. +- if (!JdkNpnSslEngine.isAvailable()) { +- throw tlsExtensionNotFound(Protocol.NPN); +- } +- ApplicationProtocolConfig clientApn = failingNegotiator(Protocol.NPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN, +- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); +- setupHandlers(serverApn, clientApn); +- assertTrue(clientLatch.await(2, TimeUnit.SECONDS)); +- assertTrue(clientException instanceof SSLHandshakeException); +- } catch (SkipTestException e) { +- // NPN availability is dependent on the java version. If NPN is not available because of +- // java version incompatibility don't fail the test, but instead just skip the test +- assumeNoException(e); +- } +- } +- +- @Test +- public void testNpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception { +- try { +- // Typical code will not have to check this, but will get a initialization error on class load. +- // Check in this test just in case we have multiple tests that just the class and we already ignored the +- // initialization error. +- if (!JdkNpnSslEngine.isAvailable()) { +- throw tlsExtensionNotFound(Protocol.NPN); +- } +- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.NPN, +- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); +- setupHandlers(serverApn, clientApn); +- assertTrue(serverLatch.await(2, TimeUnit.SECONDS)); +- assertTrue(serverException instanceof SSLHandshakeException); +- } catch (SkipTestException e) { +- // NPN availability is dependent on the java version. If NPN is not available because of +- // java version incompatibility don't fail the test, but instead just skip the test +- assumeNoException(e); +- } +- } +- +- @Test +- public void testAlpn() throws Exception { +- try { +- // Typical code will not have to check this, but will get a initialization error on class load. +- // Check in this test just in case we have multiple tests that just the class and we already ignored the +- // initialization error. +- if (!JdkAlpnSslEngine.isAvailable()) { +- throw tlsExtensionNotFound(Protocol.ALPN); +- } +- ApplicationProtocolConfig apn = failingNegotiator(Protocol.ALPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- setupHandlers(apn); +- runTest(); +- } catch (SkipTestException e) { +- // ALPN availability is dependent on the java version. If ALPN is not available because of +- // java version incompatibility don't fail the test, but instead just skip the test +- assumeNoException(e); +- } +- } +- +- @Test +- public void testAlpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception { +- try { +- // Typical code will not have to check this, but will get a initialization error on class load. +- // Check in this test just in case we have multiple tests that just the class and we already ignored the +- // initialization error. +- if (!JdkAlpnSslEngine.isAvailable()) { +- throw tlsExtensionNotFound(Protocol.ALPN); +- } +- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN, +- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); +- setupHandlers(serverApn, clientApn); +- runTest(null); +- } catch (SkipTestException e) { +- // ALPN availability is dependent on the java version. If ALPN is not available because of +- // java version incompatibility don't fail the test, but instead just skip the test +- assumeNoException(e); +- } +- } +- +- @Test +- public void testAlpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception { +- try { +- // Typical code will not have to check this, but will get a initialization error on class load. +- // Check in this test just in case we have multiple tests that just the class and we already ignored the +- // initialization error. +- if (!JdkAlpnSslEngine.isAvailable()) { +- throw tlsExtensionNotFound(Protocol.ALPN); +- } +- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN, +- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); +- setupHandlers(serverApn, clientApn); +- assertTrue(serverLatch.await(2, TimeUnit.SECONDS)); +- assertTrue(serverException instanceof SSLHandshakeException); +- } catch (SkipTestException e) { +- // ALPN availability is dependent on the java version. If ALPN is not available because of +- // java version incompatibility don't fail the test, but instead just skip the test +- assumeNoException(e); +- } +- } +- +- @Test +- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception { +- try { +- // Typical code will not have to check this, but will get a initialization error on class load. +- // Check in this test just in case we have multiple tests that just the class and we already ignored the +- // initialization error. +- if (!JdkAlpnSslEngine.isAvailable()) { +- throw tlsExtensionNotFound(Protocol.ALPN); +- } +- // Even the preferred application protocol appears second in the client's list, it will be picked +- // because it's the first one on server's list. +- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN, +- FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL); +- setupHandlers(serverApn, clientApn); +- assertNull(serverException); +- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- } catch (SkipTestException e) { +- // ALPN availability is dependent on the java version. If ALPN is not available because of +- // java version incompatibility don't fail the test, but instead just skip the test +- assumeNoException(e); +- } +- } +- +- @Test +- public void testAlpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception { +- try { +- // Typical code will not have to check this, but will get a initialization error on class load. +- // Check in this test just in case we have multiple tests that just the class and we already ignored the +- // initialization error. +- if (!JdkAlpnSslEngine.isAvailable()) { +- throw tlsExtensionNotFound(Protocol.ALPN); +- } +- SelfSignedCertificate ssc = new SelfSignedCertificate(); +- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(true, true, +- PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator( +- new ProtocolSelectorFactory() { +- @Override +- public ProtocolSelector newSelector(SSLEngine engine, Set supportedProtocols) { +- return new ProtocolSelector() { +- @Override +- public void unsupported() { +- } +- +- @Override +- public String select(List protocols) { +- return APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE; +- } +- }; +- } +- }, JdkBaseApplicationProtocolNegotiator.FAIL_SELECTION_LISTENER_FACTORY, +- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); +- +- SslContext serverSslCtx = new JdkSslServerContext(ssc.certificate(), ssc.privateKey(), null, null, +- IdentityCipherSuiteFilter.INSTANCE, serverApn, 0, 0); +- SslContext clientSslCtx = new JdkSslClientContext(null, InsecureTrustManagerFactory.INSTANCE, null, +- IdentityCipherSuiteFilter.INSTANCE, clientApn, 0, 0); +- +- setupHandlers(serverSslCtx, clientSslCtx); +- assertTrue(clientLatch.await(2, TimeUnit.SECONDS)); +- assertTrue(clientException instanceof SSLHandshakeException); +- } catch (SkipTestException e) { +- // ALPN availability is dependent on the java version. If ALPN is not available because of +- // java version incompatibility don't fail the test, but instead just skip the test +- assumeNoException(e); +- } +- } + + @Test + public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception { + testEnablingAnAlreadyDisabledSslProtocol(new String[]{}, new String[]{PROTOCOL_TLS_V1_2}); + } + +- private void runTest() throws Exception { +- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); +- } +- + @Override + protected SslProvider sslClientProvider() { + return SslProvider.JDK; +@@ -280,30 +33,4 @@ public class JdkSslEngineTest extends SSLEngineTest { + protected SslProvider sslServerProvider() { + return SslProvider.JDK; + } +- +- private ApplicationProtocolConfig failingNegotiator(Protocol protocol, +- String... supportedProtocols) { +- return new ApplicationProtocolConfig(protocol, +- SelectorFailureBehavior.FATAL_ALERT, +- SelectedListenerFailureBehavior.FATAL_ALERT, +- supportedProtocols); +- } +- +- private ApplicationProtocolConfig acceptingNegotiator(Protocol protocol, +- String... supportedProtocols) { +- return new ApplicationProtocolConfig(protocol, +- SelectorFailureBehavior.NO_ADVERTISE, +- SelectedListenerFailureBehavior.ACCEPT, +- supportedProtocols); +- } +- +- private SkipTestException tlsExtensionNotFound(Protocol protocol) { +- throw new SkipTestException(protocol + " not on classpath"); +- } +- +- private static final class SkipTestException extends RuntimeException { +- public SkipTestException(String message) { +- super(message); +- } +- } + } +-- +2.7.4 + diff --git a/netty.spec b/netty.spec index f4dac18..ef12f96 100644 --- a/netty.spec +++ b/netty.spec @@ -4,14 +4,15 @@ %global namedversion %{version}%{?namedreltag} Name: netty -Version: 4.0.28 -Release: 3%{?dist} +Version: 4.0.42 +Release: 1%{?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 -Patch0: npn_alpn_ssl_fixes.patch -Patch1: transport-native-epoll-configure-fix.patch +Patch0: 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch +Patch1: 0002-Remove-NPN-ALPN.patch +#Patch1: transport-native-epoll-configure-fix.patch BuildRequires: maven-local BuildRequires: mvn(ant-contrib:ant-contrib) @@ -21,6 +22,7 @@ BuildRequires: mvn(com.jcraft:jzlib) BuildRequires: mvn(commons-logging:commons-logging) BuildRequires: mvn(junit:junit) BuildRequires: mvn(log4j:log4j) +BuildRequires: mvn(org.jctools:jctools-core) BuildRequires: mvn(org.apache.felix:maven-bundle-plugin) BuildRequires: mvn(org.apache.maven.plugins:maven-antrun-plugin) BuildRequires: mvn(org.apache.maven.plugins:maven-checkstyle-plugin) @@ -72,7 +74,7 @@ Summary: API documentation for %{name} %setup -q -n netty-netty-%{namedversion} %patch0 -p1 -%patch1 -p2 +%patch1 -p1 # Missing Mavenized rxtx %pom_disable_module "transport-rxtx" @@ -93,17 +95,16 @@ Summary: API documentation for %{name} %pom_remove_plugin :maven-enforcer-plugin %pom_remove_plugin :maven-antrun-plugin %pom_remove_plugin :maven-dependency-plugin +%pom_remove_plugin :maven-shade-plugin +%pom_remove_plugin :maven-shade-plugin common +%pom_remove_plugin :xml-maven-plugin # Optional things we don't ship -%pom_remove_dep ":netty-tcnative" -%pom_remove_dep ":netty-tcnative" handler +%pom_remove_dep ":\${tcnative.artifactId}" +%pom_remove_dep ":\${tcnative.artifactId}" handler %pom_remove_dep "org.eclipse.jetty.npn:npn-api" %pom_remove_dep "org.eclipse.jetty.npn:npn-api" handler -%pom_remove_dep "org.mortbay.jetty.npn:npn-boot" -%pom_remove_dep "org.mortbay.jetty.npn:npn-boot" handler %pom_remove_dep "org.eclipse.jetty.alpn:alpn-api" %pom_remove_dep "org.eclipse.jetty.alpn:alpn-api" handler -%pom_remove_dep "org.mortbay.jetty.alpn:alpn-boot" -%pom_remove_dep "org.mortbay.jetty.alpn:alpn-boot" handler sed -i 's|taskdef|taskdef classpathref="maven.plugin.classpath"|' all/pom.xml @@ -129,6 +130,10 @@ export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS" %doc LICENSE.txt NOTICE.txt %changelog +* 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 diff --git a/npn_alpn_ssl_fixes.patch b/npn_alpn_ssl_fixes.patch deleted file mode 100644 index 48c4842..0000000 --- a/npn_alpn_ssl_fixes.patch +++ /dev/null @@ -1,4384 +0,0 @@ -commit b654e334d8df083dca71f330c6d9d7306ab78649 -Author: Severin Gehwolf -Date: Wed May 20 13:19:37 2015 +0200 - - Remove optional NPN/ALPN/OpenSSL handlers. - -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java -deleted file mode 100644 -index aaaf5b7..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java -+++ /dev/null -@@ -1,120 +0,0 @@ --/* -- * Copyright 2014 The Netty Project -- * -- * The Netty Project licenses this file to you under the Apache License, -- * version 2.0 (the "License"); you may not use this file except in compliance -- * with the License. You may obtain a copy of the License at: -- * -- * http://www.apache.org/licenses/LICENSE-2.0 -- * -- * Unless required by applicable law or agreed to in writing, software -- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -- * License for the specific language governing permissions and limitations -- * under the License. -- */ --package io.netty.handler.ssl; -- --import javax.net.ssl.SSLEngine; -- --/** -- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}. -- */ --public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { -- private static final SslEngineWrapperFactory ALPN_WRAPPER = new SslEngineWrapperFactory() { -- { -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw new RuntimeException("ALPN unsupported. Is your classpatch configured correctly?" -- + " See http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-starting"); -- } -- } -- -- @Override -- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, -- boolean isServer) { -- return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer); -- } -- }; -- -- /** -- * Create a new instance. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(Iterable protocols) { -- this(false, protocols); -- } -- -- /** -- * Create a new instance. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(String... protocols) { -- this(false, protocols); -- } -- -- /** -- * Create a new instance. -- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable protocols) { -- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); -- } -- -- /** -- * Create a new instance. -- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) { -- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); -- } -- -- /** -- * Create a new instance. -- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. -- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, -- boolean serverFailIfNoCommonProtocols, Iterable protocols) { -- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, -- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, -- protocols); -- } -- -- /** -- * Create a new instance. -- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. -- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, -- boolean serverFailIfNoCommonProtocols, String... protocols) { -- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, -- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, -- protocols); -- } -- -- /** -- * Create a new instance. -- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. -- * @param listenerFactory The factory which provides to be notified of which protocol was selected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, -- ProtocolSelectionListenerFactory listenerFactory, Iterable protocols) { -- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols); -- } -- -- /** -- * Create a new instance. -- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. -- * @param listenerFactory The factory which provides to be notified of which protocol was selected. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, -- ProtocolSelectionListenerFactory listenerFactory, String... protocols) { -- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols); -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java -deleted file mode 100644 -index 6cfacb8..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java -+++ /dev/null -@@ -1,117 +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.alpn.ALPN; --import org.eclipse.jetty.alpn.ALPN.ClientProvider; --import org.eclipse.jetty.alpn.ALPN.ServerProvider; -- --final class JdkAlpnSslEngine extends JdkSslEngine { -- private static boolean available; -- -- static boolean isAvailable() { -- updateAvailability(); -- return available; -- } -- -- private static void updateAvailability() { -- if (available) { -- return; -- } -- -- try { -- // Always use bootstrap class loader. -- Class.forName("sun.security.ssl.ALPNExtension", true, null); -- available = true; -- } catch (Exception ignore) { -- // alpn-boot was not loaded. -- } -- } -- -- JdkAlpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) { -- super(engine); -- checkNotNull(applicationNegotiator, "applicationNegotiator"); -- -- if (server) { -- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() -- .newSelector(this, new LinkedHashSet(applicationNegotiator.protocols())), -- "protocolSelector"); -- ALPN.put(engine, new ServerProvider() { -- @Override -- public String select(List protocols) { -- try { -- return protocolSelector.select(protocols); -- } catch (Throwable t) { -- PlatformDependent.throwException(t); -- return null; -- } -- } -- -- @Override -- public void unsupported() { -- protocolSelector.unsupported(); -- } -- }); -- } else { -- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator -- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), -- "protocolListener"); -- ALPN.put(engine, new ClientProvider() { -- @Override -- public List protocols() { -- return applicationNegotiator.protocols(); -- } -- -- @Override -- public void selected(String protocol) { -- try { -- protocolListener.selected(protocol); -- } catch (Throwable t) { -- PlatformDependent.throwException(t); -- } -- } -- -- @Override -- public void unsupported() { -- protocolListener.unsupported(); -- } -- }); -- } -- } -- -- @Override -- public void closeInbound() throws SSLException { -- ALPN.remove(getWrappedEngine()); -- super.closeInbound(); -- } -- -- @Override -- public void closeOutbound() { -- ALPN.remove(getWrappedEngine()); -- super.closeOutbound(); -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java -deleted file mode 100644 -index c893f05..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java -+++ /dev/null -@@ -1,120 +0,0 @@ --/* -- * Copyright 2014 The Netty Project -- * -- * The Netty Project licenses this file to you under the Apache License, -- * version 2.0 (the "License"); you may not use this file except in compliance -- * with the License. You may obtain a copy of the License at: -- * -- * http://www.apache.org/licenses/LICENSE-2.0 -- * -- * Unless required by applicable law or agreed to in writing, software -- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -- * License for the specific language governing permissions and limitations -- * under the License. -- */ --package io.netty.handler.ssl; -- --import javax.net.ssl.SSLEngine; -- --/** -- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}. -- */ --public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { -- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() { -- { -- if (!JdkNpnSslEngine.isAvailable()) { -- throw new RuntimeException("NPN unsupported. Is your classpatch configured correctly?" -- + " See http://www.eclipse.org/jetty/documentation/current/npn-chapter.html#npn-starting"); -- } -- } -- -- @Override -- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, -- boolean isServer) { -- return new JdkNpnSslEngine(engine, applicationNegotiator, isServer); -- } -- }; -- -- /** -- * Create a new instance. -- * @param protocols The order of iteration determines the preference of support for protocols. -- */ -- public JdkNpnApplicationProtocolNegotiator(Iterable 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/JdkNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java -deleted file mode 100644 -index 422727a..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java -+++ /dev/null -@@ -1,122 +0,0 @@ --/* -- * Copyright 2014 The Netty Project -- * -- * The Netty Project licenses this file to you under the Apache License, -- * version 2.0 (the "License"); you may not use this file except in compliance -- * with the License. You may obtain a copy of the License at: -- * -- * http://www.apache.org/licenses/LICENSE-2.0 -- * -- * Unless required by applicable law or agreed to in writing, software -- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -- * License for the specific language governing permissions and limitations -- * under the License. -- */ -- --package io.netty.handler.ssl; -- --import static io.netty.util.internal.ObjectUtil.checkNotNull; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; --import io.netty.util.internal.PlatformDependent; -- --import java.util.LinkedHashSet; --import java.util.List; -- --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLException; -- --import org.eclipse.jetty.npn.NextProtoNego; --import org.eclipse.jetty.npn.NextProtoNego.ClientProvider; --import org.eclipse.jetty.npn.NextProtoNego.ServerProvider; -- --final class JdkNpnSslEngine extends JdkSslEngine { -- private static boolean available; -- -- static boolean isAvailable() { -- updateAvailability(); -- return available; -- } -- -- private static void updateAvailability() { -- if (available) { -- return; -- } -- try { -- // Always use bootstrap class loader. -- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null); -- available = true; -- } catch (Exception ignore) { -- // npn-boot was not loaded. -- } -- } -- -- JdkNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) { -- super(engine); -- checkNotNull(applicationNegotiator, "applicationNegotiator"); -- -- if (server) { -- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator -- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), -- "protocolListener"); -- NextProtoNego.put(engine, new ServerProvider() { -- @Override -- public void unsupported() { -- protocolListener.unsupported(); -- } -- -- @Override -- public List 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/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java -index 54ee2be..e3ffb67 100644 ---- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java -+++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java -@@ -220,50 +220,6 @@ public abstract class JdkSslContext extends SslContext { - switch(config.protocol()) { - case NONE: - return JdkDefaultApplicationProtocolNegotiator.INSTANCE; -- case ALPN: -- if (isServer) { -- switch(config.selectorFailureBehavior()) { -- case FATAL_ALERT: -- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- case NO_ADVERTISE: -- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- default: -- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") -- .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); -- } -- } else { -- switch(config.selectedListenerFailureBehavior()) { -- case ACCEPT: -- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- case FATAL_ALERT: -- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- default: -- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") -- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); -- } -- } -- case NPN: -- if (isServer) { -- switch(config.selectedListenerFailureBehavior()) { -- case ACCEPT: -- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- case FATAL_ALERT: -- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- default: -- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") -- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); -- } -- } else { -- switch(config.selectorFailureBehavior()) { -- case FATAL_ALERT: -- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); -- case NO_ADVERTISE: -- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); -- default: -- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") -- .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); -- } -- } - default: - throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") - .append(config.protocol()).append(" protocol").toString()); -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java -deleted file mode 100644 -index 619768a..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java -+++ /dev/null -@@ -1,194 +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.NativeLibraryLoader; --import io.netty.util.internal.logging.InternalLogger; --import io.netty.util.internal.logging.InternalLoggerFactory; --import org.apache.tomcat.jni.Library; --import org.apache.tomcat.jni.Pool; --import org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; -- --import java.util.Collections; --import java.util.LinkedHashSet; --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 Throwable UNAVAILABILITY_CAUSE; -- -- private static final Set AVAILABLE_CIPHER_SUITES; -- -- static { -- Throwable cause = null; -- -- // Test if netty-tcnative is in the classpath first. -- try { -- Class.forName("org.apache.tomcat.jni.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 { -- NativeLibraryLoader.load("netty-tcnative", SSL.class.getClassLoader()); -- Library.initialize("provided"); -- SSL.initialize(null); -- } catch (Throwable t) { -- cause = t; -- logger.debug( -- "Failed to load 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) { -- final Set availableCipherSuites = new LinkedHashSet(128); -- final long aprPool = Pool.create(0); -- try { -- final long sslCtx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER); -- try { -- SSLContext.setOptions(sslCtx, SSL.SSL_OP_ALL); -- 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.length() == 0 || availableCipherSuites.contains(c)) { -- continue; -- } -- availableCipherSuites.add(c); -- } -- } finally { -- SSL.freeSSL(ssl); -- } -- } finally { -- SSLContext.free(sslCtx); -- } -- } catch (Exception e) { -- logger.warn("Failed to get the list of available OpenSSL cipher suites.", e); -- } finally { -- Pool.destroy(aprPool); -- } -- -- AVAILABLE_CIPHER_SUITES = Collections.unmodifiableSet(availableCipherSuites); -- } else { -- AVAILABLE_CIPHER_SUITES = Collections.emptySet(); -- } -- } -- -- /** -- * 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 the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()} -- * returns {@code false}. -- */ -- public static int version() { -- if (isAvailable()) { -- return SSL.version(); -- } -- return -1; -- } -- -- /** -- * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()} -- * returns {@code false}. -- */ -- public static String versionString() { -- if (isAvailable()) { -- return SSL.versionString(); -- } -- return 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; -- } -- -- /** -- * 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 availableCipherSuites() { -- return AVAILABLE_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_CIPHER_SUITES.contains(cipherSuite); -- } -- -- static boolean isError(long errorCode) { -- return errorCode != SSL.SSL_ERROR_NONE; -- } -- -- private OpenSsl() { } --} -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 85f15d1..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java -+++ /dev/null -@@ -1,333 +0,0 @@ --/* -- * Copyright 2014 The Netty Project -- * -- * The Netty Project licenses this file to you under the Apache License, -- * version 2.0 (the "License"); you may not use this file except in compliance -- * with the License. You may obtain a copy of the License at: -- * -- * http://www.apache.org/licenses/LICENSE-2.0 -- * -- * Unless required by applicable law or agreed to in writing, software -- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -- * License for the specific language governing permissions and limitations -- * under the License. -- */ --package io.netty.handler.ssl; -- --import io.netty.buffer.ByteBuf; --import io.netty.buffer.ByteBufInputStream; --import org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; -- --import javax.net.ssl.KeyManagerFactory; --import javax.net.ssl.SSLException; --import javax.net.ssl.TrustManager; --import javax.net.ssl.TrustManagerFactory; --import javax.net.ssl.X509ExtendedTrustManager; --import javax.net.ssl.X509TrustManager; --import javax.security.auth.x500.X500Principal; --import java.io.File; --import java.io.IOException; --import java.security.KeyStore; --import java.security.KeyStoreException; --import java.security.NoSuchAlgorithmException; --import java.security.cert.CertificateException; --import java.security.cert.X509Certificate; -- --/** -- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. -- */ --public final class OpenSslClientContext extends OpenSslContext { -- private final OpenSslSessionContext sessionContext; -- -- /** -- * Creates a new instance. -- */ -- public OpenSslClientContext() throws SSLException { -- this(null, null, null, null, null, null, null, IdentityCipherSuiteFilter.INSTANCE, null, 0, 0); -- } -- -- /** -- * Creates a new instance. -- * -- * @param certChainFile an X.509 certificate chain file in PEM format. -- * {@code null} to use the system default -- */ -- 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. -- */ -- 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. -- */ -- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException { -- this(certChainFile, trustManagerFactory, null, null, null, null, null, -- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0); -- } -- -- /** -- * @deprecated use {@link #OpenSslClientContext(File, TrustManagerFactory, Iterable, -- * CipherSuiteFilter, ApplicationProtocolConfig, long, long)} -- * -- * 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 -- 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); -- } -- -- /** -- * @deprecated use {@link #OpenSslClientContext(File, TrustManagerFactory, File, File, String, -- * KeyManagerFactory, Iterable, CipherSuiteFilter, ApplicationProtocolConfig,long, long)} -- * -- * 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 -- 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 trustCertChainFile 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 or the results of parsing {@code trustCertChainFile} -- * @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. -- */ -- public OpenSslClientContext(File trustCertChainFile, TrustManagerFactory trustManagerFactory, -- File keyCertChainFile, File keyFile, String keyPassword, -- KeyManagerFactory keyManagerFactory, Iterable ciphers, -- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, -- long sessionCacheSize, long sessionTimeout) -- throws SSLException { -- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT); -- boolean success = false; -- try { -- if (trustCertChainFile != null && !trustCertChainFile.isFile()) { -- throw new IllegalArgumentException("trustCertChainFile is not a file: " + trustCertChainFile); -- } -- -- if (keyCertChainFile != null && !keyCertChainFile.isFile()) { -- throw new IllegalArgumentException("keyCertChainFile is not a file: " + keyCertChainFile); -- } -- -- if (keyFile != null && !keyFile.isFile()) { -- throw new IllegalArgumentException("keyFile is not a file: " + keyFile); -- } -- if (keyFile == null && keyCertChainFile != null || keyFile != null && keyCertChainFile == null) { -- throw new IllegalArgumentException( -- "Either both keyCertChainFile and keyFile needs to be null or none of them"); -- } -- synchronized (OpenSslContext.class) { -- if (trustCertChainFile != null) { -- /* Load the certificate chain. We must skip the first cert when server mode */ -- if (!SSLContext.setCertificateChainFile(ctx, trustCertChainFile.getPath(), true)) { -- long error = SSL.getLastErrorNumber(); -- if (OpenSsl.isError(error)) { -- throw new SSLException( -- "failed to set certificate chain: " -- + trustCertChainFile + " (" + SSL.getErrorString(error) + ')'); -- } -- } -- } -- if (keyCertChainFile != null && keyFile != null) { -- /* Load the certificate file and private key. */ -- try { -- if (!SSLContext.setCertificate( -- ctx, keyCertChainFile.getPath(), keyFile.getPath(), keyPassword, SSL.SSL_AIDX_RSA)) { -- long error = SSL.getLastErrorNumber(); -- if (OpenSsl.isError(error)) { -- throw new SSLException("failed to set certificate: " + -- keyCertChainFile + " and " + keyFile + -- " (" + SSL.getErrorString(error) + ')'); -- } -- } -- } catch (SSLException e) { -- throw e; -- } catch (Exception e) { -- throw new SSLException("failed to set certificate: " + keyCertChainFile + " and " + keyFile, e); -- } -- } -- -- SSLContext.setVerify(ctx, SSL.SSL_VERIFY_NONE, VERIFY_DEPTH); -- -- try { -- // Set up trust manager factory to use our key store. -- if (trustManagerFactory == null) { -- trustManagerFactory = TrustManagerFactory.getInstance( -- TrustManagerFactory.getDefaultAlgorithm()); -- } -- initTrustManagerFactory(trustCertChainFile, trustManagerFactory); -- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); -- -- // Use this to prevent an error when running on java < 7 -- if (useExtendedTrustManager(manager)) { -- final X509ExtendedTrustManager extendedManager = (X509ExtendedTrustManager) manager; -- SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() { -- @Override -- void verify(OpenSslEngine engine, X509Certificate[] peerCerts, String auth) -- throws Exception { -- extendedManager.checkServerTrusted(peerCerts, auth, engine); -- } -- }); -- } else { -- SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() { -- @Override -- void verify(OpenSslEngine engine, X509Certificate[] peerCerts, String auth) -- throws Exception { -- manager.checkServerTrusted(peerCerts, auth); -- } -- }); -- } -- } catch (Exception e) { -- throw new SSLException("unable to setup trustmanager", e); -- } -- } -- sessionContext = new OpenSslClientSessionContext(ctx); -- success = true; -- } finally { -- if (!success) { -- destroyPools(); -- } -- } -- } -- -- private static void initTrustManagerFactory(File certChainFile, TrustManagerFactory trustManagerFactory) -- throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { -- KeyStore ks = KeyStore.getInstance("JKS"); -- ks.load(null, null); -- if (certChainFile != null) { -- ByteBuf[] certs = PemReader.readCertificates(certChainFile); -- try { -- for (ByteBuf buf: certs) { -- X509Certificate cert = (X509Certificate) X509_CERT_FACTORY.generateCertificate( -- new ByteBufInputStream(buf)); -- X500Principal principal = cert.getSubjectX500Principal(); -- ks.setCertificateEntry(principal.getName("RFC2253"), cert); -- } -- } finally { -- for (ByteBuf buf: certs) { -- buf.release(); -- } -- } -- } -- trustManagerFactory.init(ks); -- } -- -- @Override -- public OpenSslSessionContext sessionContext() { -- return sessionContext; -- } -- -- // No cache is currently supported for client side mode. -- private static final class OpenSslClientSessionContext extends OpenSslSessionContext { -- private OpenSslClientSessionContext(long 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; -- } -- } --} -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 6cfdc57..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java -+++ /dev/null -@@ -1,456 +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 io.netty.util.internal.PlatformDependent; --import io.netty.util.internal.SystemPropertyUtil; --import io.netty.util.internal.logging.InternalLogger; --import io.netty.util.internal.logging.InternalLoggerFactory; --import org.apache.tomcat.jni.CertificateVerifier; --import org.apache.tomcat.jni.Pool; --import org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; -- --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLException; --import javax.net.ssl.SSLHandshakeException; --import javax.net.ssl.TrustManager; --import javax.net.ssl.X509ExtendedTrustManager; --import javax.net.ssl.X509TrustManager; --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.atomic.AtomicIntegerFieldUpdater; -- --import static io.netty.util.internal.ObjectUtil.checkNotNull; --import static io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; --import static io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior; -- --public abstract class OpenSslContext extends SslContext { -- -- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslContext.class); -- /** -- * To make it easier for users to replace JDK implemention 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 = -- SystemPropertyUtil.getBoolean("jdk.tls.rejectClientInitiatedRenegotiation", false); -- private static final List DEFAULT_CIPHERS; -- private static final AtomicIntegerFieldUpdater DESTROY_UPDATER; -- -- // TODO: Maybe make configurable ? -- protected static final int VERIFY_DEPTH = 10; -- -- private final long aprPool; -- @SuppressWarnings({ "unused", "FieldMayBeFinal" }) -- private volatile int aprPoolDestroyed; -- private volatile boolean rejectRemoteInitiatedRenegotiation; -- private final List unmodifiableCiphers; -- private final long sessionCacheSize; -- private final long sessionTimeout; -- private final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap(); -- -- private final OpenSslApplicationProtocolNegotiator apn; -- /** The OpenSSL SSL_CTX object */ -- protected final long ctx; -- private final int mode; -- -- 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 SelectorFailureBehavior selectorFailureBehavior() { -- return SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL; -- } -- -- @Override -- public SelectedListenerFailureBehavior selectedListenerFailureBehavior() { -- return SelectedListenerFailureBehavior.ACCEPT; -- } -- }; -- -- static { -- List ciphers = new ArrayList(); -- // XXX: Make sure to sync this list with JdkSslEngineFactory. -- Collections.addAll( -- ciphers, -- "ECDHE-RSA-AES128-GCM-SHA256", -- "ECDHE-RSA-AES128-SHA", -- "ECDHE-RSA-AES256-SHA", -- "AES128-GCM-SHA256", -- "AES128-SHA", -- "AES256-SHA", -- "DES-CBC3-SHA", -- "RC4-SHA"); -- DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers); -- -- if (logger.isDebugEnabled()) { -- logger.debug("Default cipher suite (OpenSSL): " + ciphers); -- } -- -- AtomicIntegerFieldUpdater updater = -- PlatformDependent.newAtomicIntegerFieldUpdater(OpenSslContext.class, "aprPoolDestroyed"); -- if (updater == null) { -- updater = AtomicIntegerFieldUpdater.newUpdater(OpenSslContext.class, "aprPoolDestroyed"); -- } -- DESTROY_UPDATER = updater; -- } -- -- OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg, -- long sessionCacheSize, long sessionTimeout, int mode) throws SSLException { -- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode); -- } -- -- OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, -- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, -- long sessionTimeout, int mode) throws SSLException { -- OpenSsl.ensureAvailability(); -- -- 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"); -- } -- this.mode = mode; -- -- if (mode == SSL.SSL_MODE_SERVER) { -- rejectRemoteInitiatedRenegotiation = -- JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION; -- } -- 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.availableCipherSuites())); -- -- this.apn = checkNotNull(apn, "apn"); -- -- // Allocate a new APR pool. -- aprPool = Pool.create(0); -- -- // Create a new SSL_CTX and configure it. -- boolean success = false; -- try { -- synchronized (OpenSslContext.class) { -- try { -- ctx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, mode); -- } catch (Exception e) { -- throw new SSLException("failed to create an SSL_CTX", e); -- } -- -- SSLContext.setOptions(ctx, SSL.SSL_OP_ALL); -- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SSLv2); -- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SSLv3); -- SSLContext.setOptions(ctx, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); -- SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_ECDH_USE); -- SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_DH_USE); -- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); -- -- /* 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[] protocols = nextProtoList.toArray(new String[nextProtoList.size()]); -- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior()); -- -- switch (apn.protocol()) { -- case NPN: -- SSLContext.setNpnProtos(ctx, protocols, selectorBehavior); -- break; -- case ALPN: -- SSLContext.setAlpnProtos(ctx, protocols, selectorBehavior); -- break; -- case NPN_AND_ALPN: -- SSLContext.setNpnProtos(ctx, protocols, selectorBehavior); -- SSLContext.setAlpnProtos(ctx, protocols, 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); -- } -- } -- success = true; -- } finally { -- if (!success) { -- destroyPools(); -- } -- } -- } -- -- private static int opensslSelectorFailureBehavior(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) { -- throw new UnsupportedOperationException(); -- } -- -- /** -- * Returns a new server-side {@link javax.net.ssl.SSLEngine} with the current configuration. -- */ -- @Override -- public final SSLEngine newEngine(ByteBufAllocator alloc) { -- final OpenSslEngine engine = new OpenSslEngine( -- ctx, alloc, isClient(), sessionContext(), apn, engineMap, rejectRemoteInitiatedRenegotiation); -- engineMap.add(engine); -- return engine; -- } -- -- /** -- * Returns the {@code SSL_CTX} object of this context. -- */ -- public final long context() { -- return ctx; -- } -- -- /** -- * 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; -- } -- -- @Override -- @SuppressWarnings("FinalizeDeclaration") -- protected final void finalize() throws Throwable { -- super.finalize(); -- synchronized (OpenSslContext.class) { -- if (ctx != 0) { -- SSLContext.free(ctx); -- } -- } -- -- destroyPools(); -- } -- -- /** -- * 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(); -- -- protected final void destroyPools() { -- // Guard against multiple destroyPools() calls triggered by construction exception and finalize() later -- if (aprPool != 0 && DESTROY_UPDATER.compareAndSet(this, 0, 1)) { -- Pool.destroy(aprPool); -- } -- } -- -- 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"); -- } -- -- /** -- * 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; -- } -- -- abstract class AbstractCertificateVerifier implements CertificateVerifier { -- @Override -- public final boolean verify(long ssl, byte[][] chain, String auth) { -- X509Certificate[] peerCerts = certificates(chain); -- final OpenSslEngine engine = engineMap.remove(ssl); -- try { -- verify(engine, peerCerts, auth); -- return true; -- } catch (Throwable cause) { -- logger.debug("verification of certificate failed", cause); -- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem"); -- e.initCause(cause); -- engine.handshakeException = e; -- } -- return false; -- } -- -- abstract void verify(OpenSslEngine engine, X509Certificate[] peerCerts, String auth) throws Exception; -- } -- -- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap { -- private final Map engines = PlatformDependent.newConcurrentHashMap(); -- @Override -- public OpenSslEngine remove(long ssl) { -- return engines.remove(ssl); -- } -- -- @Override -- public void add(OpenSslEngine engine) { -- engines.put(engine.ssl(), engine); -- } -- } --} -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 b5c8e6c..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java -+++ /dev/null -@@ -1,1525 +0,0 @@ --/* -- * Copyright 2014 The Netty Project -- * -- * The Netty Project licenses this file to you under the Apache License, -- * version 2.0 (the "License"); you may not use this file except in compliance -- * with the License. You may obtain a copy of the License at: -- * -- * http://www.apache.org/licenses/LICENSE-2.0 -- * -- * Unless required by applicable law or agreed to in writing, software -- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -- * License for the specific language governing permissions and limitations -- * under the License. -- */ --package io.netty.handler.ssl; -- --import io.netty.buffer.ByteBuf; --import io.netty.buffer.ByteBufAllocator; --import io.netty.buffer.Unpooled; --import io.netty.util.internal.EmptyArrays; --import io.netty.util.internal.PlatformDependent; --import io.netty.util.internal.StringUtil; --import io.netty.util.internal.logging.InternalLogger; --import io.netty.util.internal.logging.InternalLoggerFactory; --import org.apache.tomcat.jni.Buffer; --import org.apache.tomcat.jni.SSL; -- --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLEngineResult; --import javax.net.ssl.SSLException; --import javax.net.ssl.SSLHandshakeException; --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.CertificateException; --import javax.security.cert.X509Certificate; --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.HashMap; --import java.util.HashSet; --import java.util.List; --import java.util.Map; --import java.util.Set; --import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; -- --import static io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior; --import static io.netty.util.internal.ObjectUtil.checkNotNull; --import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*; --import static javax.net.ssl.SSLEngineResult.Status.*; -- --/** -- * Implements a {@link SSLEngine} using -- * OpenSSL BIO abstractions. -- */ --public final class OpenSslEngine extends SSLEngine { -- -- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslEngine.class); -- -- private static final Certificate[] EMPTY_CERTIFICATES = EmptyArrays.EMPTY_CERTIFICATES; -- private static final X509Certificate[] EMPTY_X509_CERTIFICATES = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES; -- -- private static final SSLException ENGINE_CLOSED = new SSLException("engine closed"); -- private static final SSLException RENEGOTIATION_UNSUPPORTED = new SSLException("renegotiation unsupported"); -- private static final SSLException ENCRYPTED_PACKET_OVERSIZED = new SSLException("encrypted packet oversized"); -- static { -- ENGINE_CLOSED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE); -- RENEGOTIATION_UNSUPPORTED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE); -- ENCRYPTED_PACKET_OVERSIZED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE); -- -- AtomicIntegerFieldUpdater destroyedUpdater = -- PlatformDependent.newAtomicIntegerFieldUpdater(OpenSslEngine.class, "destroyed"); -- if (destroyedUpdater == null) { -- destroyedUpdater = AtomicIntegerFieldUpdater.newUpdater(OpenSslEngine.class, "destroyed"); -- } -- DESTROYED_UPDATER = destroyedUpdater; -- } -- -- 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; -- -- // Protocols -- private static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello"; -- private static final String PROTOCOL_SSL_V2 = "SSLv2"; -- private static final String PROTOCOL_SSL_V3 = "SSLv3"; -- private static final String PROTOCOL_TLS_V1 = "TLSv1"; -- private static final String PROTOCOL_TLS_V1_1 = "TLSv1.1"; -- private static final String PROTOCOL_TLS_V1_2 = "TLSv1.2"; -- -- private static final String[] SUPPORTED_PROTOCOLS = { -- PROTOCOL_SSL_V2_HELLO, -- PROTOCOL_SSL_V2, -- PROTOCOL_SSL_V3, -- PROTOCOL_TLS_V1, -- PROTOCOL_TLS_V1_1, -- PROTOCOL_TLS_V1_2 -- }; -- private static final Set SUPPORTED_PROTOCOLS_SET = new HashSet(Arrays.asList(SUPPORTED_PROTOCOLS)); -- -- // 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; -- -- enum ClientAuthMode { -- NONE, -- OPTIONAL, -- REQUIRE, -- } -- -- private static final AtomicIntegerFieldUpdater DESTROYED_UPDATER; -- -- private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL"; -- -- private static final long EMPTY_ADDR = Buffer.address(Unpooled.EMPTY_BUFFER.nioBuffer()); -- -- 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; -- -- /** -- * 0 - not accepted, 1 - accepted implicitly via wrap()/unwrap(), 2 - accepted explicitly via beginHandshake() call -- */ -- private int accepted; -- private boolean handshakeFinished; -- private boolean receivedShutdown; -- @SuppressWarnings("UnusedDeclaration") -- private volatile int destroyed; -- -- // Use an invalid cipherSuite until the handshake is completed -- // See http://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html#getSession() -- private volatile String cipher; -- private volatile String applicationProtocol; -- -- // We store this outside of the SslSession so we not need to create an instance during verifyCertificates(...) -- private volatile Certificate[] peerCerts; -- private volatile ClientAuthMode clientAuth = ClientAuthMode.NONE; -- -- // SSL Engine status variables -- private boolean isInboundDone; -- private boolean isOutboundDone; -- private boolean engineClosed; -- -- private final boolean clientMode; -- private final ByteBufAllocator alloc; -- private final OpenSslSessionContext sessionContext; -- private final OpenSslEngineMap engineMap; -- private final OpenSslApplicationProtocolNegotiator apn; -- private final boolean rejectRemoteInitiatedRenegation; -- private final SSLSession session = new OpenSslSession(); -- -- // This is package-private as we set it from OpenSslContext if an exception is thrown during -- // the verification step. -- SSLHandshakeException handshakeException; -- -- /** -- * Creates a new instance -- * -- * @param sslCtx an OpenSSL {@code SSL_CTX} object -- * @param alloc the {@link ByteBufAllocator} that will be used by this engine -- */ -- @Deprecated -- public OpenSslEngine(long sslCtx, ByteBufAllocator alloc, -- @SuppressWarnings("unused") String fallbackApplicationProtocol) { -- this(sslCtx, alloc, false, null, OpenSslContext.NONE_PROTOCOL_NEGOTIATOR, OpenSslEngineMap.EMPTY, false); -- } -- -- /** -- * Creates a new instance -- * -- * @param sslCtx an OpenSSL {@code SSL_CTX} object -- * @param alloc the {@link ByteBufAllocator} that will be used by this engine -- * @param clientMode {@code true} if this is used for clients, {@code false} otherwise -- * @param sessionContext the {@link OpenSslSessionContext} this {@link SSLEngine} belongs to. -- */ -- OpenSslEngine(long sslCtx, ByteBufAllocator alloc, -- boolean clientMode, OpenSslSessionContext sessionContext, -- OpenSslApplicationProtocolNegotiator apn, OpenSslEngineMap engineMap, -- boolean rejectRemoteInitiatedRenegation) { -- OpenSsl.ensureAvailability(); -- if (sslCtx == 0) { -- throw new NullPointerException("sslCtx"); -- } -- -- this.alloc = checkNotNull(alloc, "alloc"); -- this.apn = checkNotNull(apn, "apn"); -- ssl = SSL.newSSL(sslCtx, !clientMode); -- networkBIO = SSL.makeNetworkBIO(ssl); -- this.clientMode = clientMode; -- this.sessionContext = sessionContext; -- this.engineMap = engineMap; -- this.rejectRemoteInitiatedRenegation = rejectRemoteInitiatedRenegation; -- } -- -- @Override -- public SSLSession getHandshakeSession() { -- if (accepted > 0) { -- // handshake started we are able to return the session. -- return session; -- } -- // As stated by the javadocs of getHandshakeSession() we should return null if the handshake not started yet. -- return null; -- } -- -- long ssl() { -- return ssl; -- } -- -- /** -- * Destroys this engine. -- */ -- public synchronized void shutdown() { -- if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) { -- engineMap.remove(ssl); -- SSL.freeSSL(ssl); -- SSL.freeBIO(networkBIO); -- ssl = networkBIO = 0; -- -- // internal errors can cause shutdown without marking the engine closed -- isInboundDone = isOutboundDone = engineClosed = true; -- } -- } -- -- /** -- * Write plaintext data to the OpenSSL internal BIO -- * -- * Calling this function with src.remaining == 0 is undefined. -- */ -- private int writePlaintextData(final ByteBuffer src) { -- final int pos = src.position(); -- final int limit = src.limit(); -- final int len = Math.min(limit - pos, MAX_PLAINTEXT_LENGTH); -- final int sslWrote; -- -- if (src.isDirect()) { -- final long addr = Buffer.address(src) + pos; -- sslWrote = SSL.writeToSSL(ssl, addr, len); -- if (sslWrote > 0) { -- src.position(pos + sslWrote); -- return sslWrote; -- } -- } else { -- ByteBuf buf = alloc.directBuffer(len); -- try { -- final long addr = memoryAddress(buf); -- -- src.limit(pos + len); -- -- buf.setBytes(0, src); -- src.limit(limit); -- -- sslWrote = SSL.writeToSSL(ssl, addr, len); -- if (sslWrote > 0) { -- src.position(pos + sslWrote); -- return sslWrote; -- } else { -- src.position(pos); -- } -- } finally { -- buf.release(); -- } -- } -- -- throw new IllegalStateException("SSL.writeToSSL() returned a non-positive value: " + sslWrote); -- } -- -- /** -- * Write encrypted data to the OpenSSL network BIO. -- */ -- private int writeEncryptedData(final ByteBuffer src) { -- final int pos = src.position(); -- final int len = src.remaining(); -- if (src.isDirect()) { -- final long addr = Buffer.address(src) + pos; -- final int netWrote = SSL.writeToBIO(networkBIO, addr, len); -- if (netWrote >= 0) { -- src.position(pos + netWrote); -- return netWrote; -- } -- } else { -- final ByteBuf buf = alloc.directBuffer(len); -- try { -- final long addr = memoryAddress(buf); -- -- buf.setBytes(0, src); -- -- final int netWrote = SSL.writeToBIO(networkBIO, addr, len); -- if (netWrote >= 0) { -- src.position(pos + netWrote); -- return netWrote; -- } else { -- src.position(pos); -- } -- } finally { -- buf.release(); -- } -- } -- -- return -1; -- } -- -- /** -- * Read plaintext data from the OpenSSL internal BIO -- */ -- private int readPlaintextData(final ByteBuffer dst) { -- if (dst.isDirect()) { -- final int pos = dst.position(); -- final long addr = Buffer.address(dst) + pos; -- final int len = dst.limit() - pos; -- final int sslRead = SSL.readFromSSL(ssl, addr, len); -- if (sslRead > 0) { -- dst.position(pos + sslRead); -- return sslRead; -- } -- } else { -- final int pos = dst.position(); -- final int limit = dst.limit(); -- final int len = Math.min(MAX_ENCRYPTED_PACKET_LENGTH, limit - pos); -- final ByteBuf buf = alloc.directBuffer(len); -- try { -- final long addr = memoryAddress(buf); -- -- final int sslRead = SSL.readFromSSL(ssl, addr, len); -- if (sslRead > 0) { -- dst.limit(pos + sslRead); -- buf.getBytes(0, dst); -- dst.limit(limit); -- return sslRead; -- } -- } finally { -- buf.release(); -- } -- } -- -- return 0; -- } -- -- /** -- * Read encrypted data from the OpenSSL network BIO -- */ -- private int readEncryptedData(final ByteBuffer dst, final int pending) { -- if (dst.isDirect() && dst.remaining() >= pending) { -- final int pos = dst.position(); -- final long addr = Buffer.address(dst) + pos; -- final int bioRead = SSL.readFromBIO(networkBIO, addr, pending); -- if (bioRead > 0) { -- dst.position(pos + bioRead); -- return bioRead; -- } -- } else { -- final ByteBuf buf = alloc.directBuffer(pending); -- try { -- final long addr = memoryAddress(buf); -- -- final int bioRead = SSL.readFromBIO(networkBIO, addr, pending); -- if (bioRead > 0) { -- int oldLimit = dst.limit(); -- dst.limit(dst.position() + bioRead); -- buf.getBytes(0, dst); -- dst.limit(oldLimit); -- return bioRead; -- } -- } finally { -- buf.release(); -- } -- } -- -- return 0; -- } -- -- @Override -- public synchronized SSLEngineResult wrap( -- final ByteBuffer[] srcs, final int offset, final int length, final ByteBuffer dst) throws SSLException { -- -- // Check to make sure the engine has not been closed -- if (destroyed != 0) { -- return CLOSED_NOT_HANDSHAKING; -- } -- -- // 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(); -- } -- -- // Prepare OpenSSL to work in server mode and receive handshake -- if (accepted == 0) { -- beginHandshakeImplicitly(); -- } -- -- // In handshake or close_notify stages, check if call to wrap was made -- // without regard to the handshake status. -- SSLEngineResult.HandshakeStatus handshakeStatus = handshakeStatus0(); -- -- if (handshakeStatus == NEED_UNWRAP) { -- if (!handshakeFinished) { -- return NEED_UNWRAP_OK; -- } -- if (engineClosed) { -- return NEED_UNWRAP_CLOSED; -- } -- } -- -- int bytesProduced = 0; -- int pendingNet; -- -- // Check for pending data in the network BIO -- pendingNet = SSL.pendingWrittenBytesInBIO(networkBIO); -- if (pendingNet > 0) { -- // Do we have enough room in dst to write encrypted data? -- int capacity = dst.remaining(); -- if (capacity < pendingNet) { -- return new SSLEngineResult(BUFFER_OVERFLOW, handshakeStatus, 0, bytesProduced); -- } -- -- // Write the pending data from the network BIO into the dst buffer -- try { -- bytesProduced += readEncryptedData(dst, pendingNet); -- } catch (Exception e) { -- throw new SSLException(e); -- } -- -- // If isOuboundDone is set, then the data from the network BIO -- // was the close_notify message -- we are not required to wait -- // for the receipt the peer's close_notify message -- shutdown. -- if (isOutboundDone) { -- shutdown(); -- } -- -- return new SSLEngineResult(getEngineStatus(), handshakeStatus0(), 0, bytesProduced); -- } -- -- // There was no pending data in the network BIO -- encrypt any application data -- int bytesConsumed = 0; -- 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"); -- } -- while (src.hasRemaining()) { -- -- // Write plaintext application data to the SSL engine -- try { -- bytesConsumed += writePlaintextData(src); -- } catch (Exception e) { -- throw new SSLException(e); -- } -- -- // Check to see if the engine wrote data into the network BIO -- pendingNet = SSL.pendingWrittenBytesInBIO(networkBIO); -- if (pendingNet > 0) { -- // Do we have enough room in dst to write encrypted data? -- int capacity = dst.remaining(); -- if (capacity < pendingNet) { -- return new SSLEngineResult( -- BUFFER_OVERFLOW, handshakeStatus0(), bytesConsumed, bytesProduced); -- } -- -- // Write the pending data from the network BIO into the dst buffer -- try { -- bytesProduced += readEncryptedData(dst, pendingNet); -- } catch (Exception e) { -- throw new SSLException(e); -- } -- -- return new SSLEngineResult(getEngineStatus(), handshakeStatus0(), bytesConsumed, bytesProduced); -- } -- } -- } -- -- return new SSLEngineResult(getEngineStatus(), handshakeStatus0(), bytesConsumed, bytesProduced); -- } -- -- private SSLException newSSLException(String msg) { -- if (!handshakeFinished) { -- return new SSLHandshakeException(msg); -- } -- return new SSLException(msg); -- } -- -- private void checkPendingHandshakeException() throws SSLHandshakeException { -- if (handshakeException != null) { -- SSLHandshakeException exception = handshakeException; -- handshakeException = null; -- shutdown(); -- throw exception; -- } -- } -- -- public synchronized SSLEngineResult unwrap( -- final ByteBuffer[] srcs, int srcsOffset, final int srcsLength, -- final ByteBuffer[] dsts, final int dstsOffset, final int dstsLength) throws SSLException { -- -- // Check to make sure the engine has not been closed -- if (destroyed != 0) { -- return CLOSED_NOT_HANDSHAKING; -- } -- -- // Throw requried 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 + "))"); -- } -- int capacity = 0; -- final int endOffset = dstsOffset + dstsLength; -- for (int i = dstsOffset; i < endOffset; i ++) { -- ByteBuffer dst = dsts[i]; -- if (dst == null) { -- throw new IllegalArgumentException("dsts[" + i + "] is null"); -- } -- if (dst.isReadOnly()) { -- throw new ReadOnlyBufferException(); -- } -- capacity += dst.remaining(); -- } -- -- // Prepare OpenSSL to work in server mode and receive handshake -- if (accepted == 0) { -- beginHandshakeImplicitly(); -- } -- -- // In handshake or close_notify stages, check if call to unwrap was made -- // without regard to the handshake status. -- SSLEngineResult.HandshakeStatus handshakeStatus = handshakeStatus0(); -- if (handshakeStatus == NEED_WRAP) { -- if (!handshakeFinished) { -- return NEED_WRAP_OK; -- } -- if (engineClosed) { -- return NEED_WRAP_CLOSED; -- } -- } -- -- final int srcsEndOffset = srcsOffset + srcsLength; -- int 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(); -- } -- -- // protect against protocol overflow attack vector -- if (len > MAX_ENCRYPTED_PACKET_LENGTH) { -- isInboundDone = true; -- isOutboundDone = true; -- engineClosed = true; -- shutdown(); -- throw ENCRYPTED_PACKET_OVERSIZED; -- } -- -- // Write encrypted data to network BIO -- int bytesConsumed = -1; -- try { -- while (srcsOffset < srcsEndOffset) { -- ByteBuffer src = srcs[srcsOffset]; -- int remaining = src.remaining(); -- int written = writeEncryptedData(src); -- if (written >= 0) { -- if (bytesConsumed == -1) { -- bytesConsumed = written; -- } else { -- bytesConsumed += written; -- } -- if (written == remaining) { -- srcsOffset ++; -- } else if (written == 0) { -- break; -- } -- } else { -- break; -- } -- } -- } catch (Exception e) { -- throw new SSLException(e); -- } -- if (bytesConsumed >= 0) { -- int lastPrimingReadResult = SSL.readFromSSL(ssl, EMPTY_ADDR, 0); // priming read -- -- // check if SSL_read returned <= 0. In this case we need to check the error and see if it was something -- // fatal. -- if (lastPrimingReadResult <= 0) { -- // Check for OpenSSL errors caused by the priming read -- long error = SSL.getLastErrorNumber(); -- if (OpenSsl.isError(error)) { -- String err = SSL.getErrorString(error); -- if (logger.isDebugEnabled()) { -- logger.debug( -- "SSL_read failed: primingReadResult: " + lastPrimingReadResult + -- "; OpenSSL error: '" + err + '\''); -- } -- -- // There was an internal error -- shutdown -- shutdown(); -- throw newSSLException(err); -- } else { -- checkPendingHandshakeException(); -- } -- } -- -- rejectRemoteInitiatedRenegation(); -- } else { -- // Reset to 0 as -1 is used to signal that nothing was written and no priming read needs to be done -- bytesConsumed = 0; -- } -- -- // There won't be any application data until we're done handshaking -- // -- // We first check handshakeFinished to eliminate the overhead of extra JNI call if possible. -- int pendingApp = (handshakeFinished || SSL.isInInit(ssl) == 0) ? SSL.pendingReadableBytesInSSL(ssl) : 0; -- int bytesProduced = 0; -- -- if (pendingApp > 0) { -- // Do we have enough room in dsts to write decrypted data? -- if (capacity < pendingApp) { -- return new SSLEngineResult(BUFFER_OVERFLOW, handshakeStatus0(), bytesConsumed, 0); -- } -- -- // Write decrypted data to dsts buffers -- int idx = dstsOffset; -- while (idx < endOffset) { -- ByteBuffer dst = dsts[idx]; -- if (!dst.hasRemaining()) { -- idx ++; -- continue; -- } -- -- if (pendingApp <= 0) { -- break; -- } -- -- int bytesRead; -- try { -- bytesRead = readPlaintextData(dst); -- } catch (Exception e) { -- throw new SSLException(e); -- } -- -- rejectRemoteInitiatedRenegation(); -- -- if (bytesRead == 0) { -- break; -- } -- bytesProduced += bytesRead; -- pendingApp -= bytesRead; -- -- if (!dst.hasRemaining()) { -- idx ++; -- } -- } -- } -- -- // 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) { -- receivedShutdown = true; -- closeOutbound(); -- closeInbound(); -- } -- -- return new SSLEngineResult(getEngineStatus(), handshakeStatus0(), bytesConsumed, bytesProduced); -- } -- -- private void rejectRemoteInitiatedRenegation() throws SSLHandshakeException { -- if (rejectRemoteInitiatedRenegation && 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 renegotation not allowed"); -- } -- } -- -- public SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException { -- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length); -- } -- -- @Override -- public SSLEngineResult unwrap( -- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException { -- return unwrap(new ByteBuffer[] { src }, 0, 1, dsts, offset, length); -- } -- -- @Override -- public 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 synchronized void closeInbound() throws SSLException { -- if (isInboundDone) { -- return; -- } -- -- isInboundDone = true; -- engineClosed = true; -- -- shutdown(); -- -- if (accepted != 0 && !receivedShutdown) { -- throw new SSLException( -- "Inbound closed before receiving peer's close_notify: possible truncation attack?"); -- } -- } -- -- @Override -- public synchronized boolean isInboundDone() { -- return isInboundDone || engineClosed; -- } -- -- @Override -- public synchronized void closeOutbound() { -- if (isOutboundDone) { -- return; -- } -- -- isOutboundDone = true; -- engineClosed = true; -- -- if (accepted != 0 && destroyed == 0) { -- int mode = SSL.getShutdown(ssl); -- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) { -- SSL.shutdownSSL(ssl); -- } -- } else { -- // engine closing before initial handshake -- shutdown(); -- } -- } -- -- @Override -- public synchronized boolean isOutboundDone() { -- return isOutboundDone; -- } -- -- @Override -- public String[] getSupportedCipherSuites() { -- Set availableCipherSuites = OpenSsl.availableCipherSuites(); -- return availableCipherSuites.toArray(new String[availableCipherSuites.size()]); -- } -- -- @Override -- public String[] getEnabledCipherSuites() { -- final String[] enabled; -- synchronized (this) { -- if (destroyed == 0) { -- enabled = SSL.getCiphers(ssl); -- } else { -- return EmptyArrays.EMPTY_STRINGS; -- } -- } -- if (enabled == null) { -- return EmptyArrays.EMPTY_STRINGS; -- } else { -- for (int i = 0; i < enabled.length; i++) { -- String mapped = toJavaCipherSuite(enabled[i]); -- if (mapped != null) { -- enabled[i] = mapped; -- } -- } -- return enabled; -- } -- } -- -- @Override -- public 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 (destroyed == 0) { -- 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 String[] getSupportedProtocols() { -- return SUPPORTED_PROTOCOLS.clone(); -- } -- -- @Override -- public String[] getEnabledProtocols() { -- List enabled = new ArrayList(); -- // Seems like there is no way to explict disable SSLv2Hello in openssl so it is always enabled -- enabled.add(PROTOCOL_SSL_V2_HELLO); -- -- int opts; -- synchronized (this) { -- if (destroyed == 0) { -- opts = SSL.getOptions(ssl); -- } else { -- return enabled.toArray(new String[1]); -- } -- } -- if ((opts & SSL.SSL_OP_NO_TLSv1) == 0) { -- enabled.add(PROTOCOL_TLS_V1); -- } -- if ((opts & SSL.SSL_OP_NO_TLSv1_1) == 0) { -- enabled.add(PROTOCOL_TLS_V1_1); -- } -- if ((opts & SSL.SSL_OP_NO_TLSv1_2) == 0) { -- enabled.add(PROTOCOL_TLS_V1_2); -- } -- if ((opts & SSL.SSL_OP_NO_SSLv2) == 0) { -- enabled.add(PROTOCOL_SSL_V2); -- } -- if ((opts & SSL.SSL_OP_NO_SSLv3) == 0) { -- enabled.add(PROTOCOL_SSL_V3); -- } -- return enabled.toArray(new String[enabled.size()]); -- } -- -- @Override -- public 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 (!SUPPORTED_PROTOCOLS_SET.contains(p)) { -- throw new IllegalArgumentException("Protocol " + p + " is not supported."); -- } -- if (p.equals(PROTOCOL_SSL_V2)) { -- sslv2 = true; -- } else if (p.equals(PROTOCOL_SSL_V3)) { -- sslv3 = true; -- } else if (p.equals(PROTOCOL_TLS_V1)) { -- tlsv1 = true; -- } else if (p.equals(PROTOCOL_TLS_V1_1)) { -- tlsv1_1 = true; -- } else if (p.equals(PROTOCOL_TLS_V1_2)) { -- tlsv1_2 = true; -- } -- } -- synchronized (this) { -- if (destroyed == 0) { -- // Enable all and then disable what we not want -- SSL.setOptions(ssl, SSL.SSL_OP_ALL); -- -- if (!sslv2) { -- SSL.setOptions(ssl, SSL.SSL_OP_NO_SSLv2); -- } -- if (!sslv3) { -- SSL.setOptions(ssl, SSL.SSL_OP_NO_SSLv3); -- } -- if (!tlsv1) { -- SSL.setOptions(ssl, SSL.SSL_OP_NO_TLSv1); -- } -- if (!tlsv1_1) { -- SSL.setOptions(ssl, SSL.SSL_OP_NO_TLSv1_1); -- } -- if (!tlsv1_2) { -- SSL.setOptions(ssl, SSL.SSL_OP_NO_TLSv1_2); -- } -- } else { -- throw new IllegalStateException("failed to enable protocols: " + protocols); -- } -- } -- } -- -- @Override -- public SSLSession getSession() { -- return session; -- } -- -- @Override -- public synchronized void beginHandshake() throws SSLException { -- if (engineClosed || destroyed != 0) { -- throw ENGINE_CLOSED; -- } -- switch (accepted) { -- case 0: -- handshake(); -- accepted = 2; -- break; -- case 1: -- // 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. -- -- accepted = 2; // Next time this method is invoked by the user, we should raise an exception. -- break; -- case 2: -- throw RENEGOTIATION_UNSUPPORTED; -- default: -- throw new Error(); -- } -- } -- -- private void beginHandshakeImplicitly() throws SSLException { -- if (engineClosed || destroyed != 0) { -- throw ENGINE_CLOSED; -- } -- -- if (accepted == 0) { -- handshake(); -- accepted = 1; -- } -- } -- -- private void handshake() throws SSLException { -- int code = SSL.doHandshake(ssl); -- if (code <= 0) { -- // Check for OpenSSL errors caused by the handshake -- long error = SSL.getLastErrorNumber(); -- if (OpenSsl.isError(error)) { -- String err = SSL.getErrorString(error); -- if (logger.isDebugEnabled()) { -- logger.debug( -- "SSL_do_handshake failed: OpenSSL error: '" + err + '\''); -- } -- -- // There was an internal error -- shutdown -- shutdown(); -- throw newSSLException(err); -- } -- checkPendingHandshakeException(); -- } else { -- // if SSL_do_handshake returns > 0 it means the handshake was finished. This means we can update -- // handshakeFinished directly and so eliminate uncessary calls to SSL.isInInit(...) -- handshakeFinished(); -- } -- } -- -- private static long memoryAddress(ByteBuf buf) { -- if (buf.hasMemoryAddress()) { -- return buf.memoryAddress(); -- } else { -- return Buffer.address(buf.nioBuffer()); -- } -- } -- -- private void handshakeFinished() throws SSLException { -- 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(); -- } -- handshakeFinished = true; -- } -- -- private static String selectApplicationProtocol(List protocols, -- SelectedListenerFailureBehavior behavior, -- String applicationProtocol) throws SSLException { -- applicationProtocol = applicationProtocol.replace(':', '_'); -- if (behavior == SelectedListenerFailureBehavior.ACCEPT) { -- return applicationProtocol; -- } else { -- int size = protocols.size(); -- assert size > 0; -- if (protocols.contains(applicationProtocol)) { -- return applicationProtocol; -- } else { -- if (behavior == SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) { -- return protocols.get(size - 1); -- } else { -- throw new SSLException("Unknown protocol " + applicationProtocol); -- } -- } -- } -- } -- -- private SSLEngineResult.Status getEngineStatus() { -- return engineClosed? CLOSED : OK; -- } -- -- private SSLEngineResult.HandshakeStatus handshakeStatus0() throws SSLException { -- SSLEngineResult.HandshakeStatus status = getHandshakeStatus(); -- if (status == FINISHED) { -- handshakeFinished(); -- } -- checkPendingHandshakeException(); -- -- return status; -- } -- -- @Override -- public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() { -- if (accepted == 0 || destroyed != 0) { -- return NOT_HANDSHAKING; -- } -- -- // Check if we are in the initial handshake phase -- if (!handshakeFinished) { -- // There is pending data in the network BIO -- call wrap -- if (SSL.pendingWrittenBytesInBIO(networkBIO) != 0) { -- return NEED_WRAP; -- } -- -- // No pending data to be sent to the peer -- // Check to see if we have finished handshaking -- if (SSL.isInInit(ssl) == 0) { -- return FINISHED; -- } -- -- // No pending data and still handshaking -- // Must be waiting on the peer to send more data -- return NEED_UNWRAP; -- } -- -- // Check if we are in the shutdown phase -- if (engineClosed) { -- // Waiting to send the close_notify message -- if (SSL.pendingWrittenBytesInBIO(networkBIO) != 0) { -- return NEED_WRAP; -- } -- -- // Must be waiting to receive the close_notify message -- return NEED_UNWRAP; -- } -- -- return NOT_HANDSHAKING; -- } -- -- /** -- * 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.length() == 0) { -- c = 0; -- } else { -- c = protocolVersion.charAt(0); -- } -- -- switch (c) { -- case 'T': -- return "TLS"; -- case 'S': -- return "SSL"; -- default: -- return "UNKNOWN"; -- } -- } -- -- @Override -- public void setUseClientMode(boolean clientMode) { -- if (clientMode != this.clientMode) { -- throw new UnsupportedOperationException(); -- } -- } -- -- @Override -- public boolean getUseClientMode() { -- return clientMode; -- } -- -- @Override -- public void setNeedClientAuth(boolean b) { -- setClientAuth(b ? ClientAuthMode.REQUIRE : ClientAuthMode.NONE); -- } -- -- @Override -- public boolean getNeedClientAuth() { -- return clientAuth == ClientAuthMode.REQUIRE; -- } -- -- @Override -- public void setWantClientAuth(boolean b) { -- setClientAuth(b ? ClientAuthMode.OPTIONAL : ClientAuthMode.NONE); -- } -- -- @Override -- public boolean getWantClientAuth() { -- return clientAuth == ClientAuthMode.OPTIONAL; -- } -- -- private void setClientAuth(ClientAuthMode 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, OpenSslContext.VERIFY_DEPTH); -- break; -- case REQUIRE: -- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRE, OpenSslContext.VERIFY_DEPTH); -- break; -- case OPTIONAL: -- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, OpenSslContext.VERIFY_DEPTH); -- break; -- } -- clientAuth = mode; -- } -- } -- -- @Override -- public void setEnableSessionCreation(boolean b) { -- if (b) { -- throw new UnsupportedOperationException(); -- } -- } -- -- @Override -- public boolean getEnableSessionCreation() { -- return false; -- } -- -- @Override -- @SuppressWarnings("FinalizeDeclaration") -- protected void finalize() throws Throwable { -- super.finalize(); -- // Call shutdown as the user may have created the OpenSslEngine and not used it at all. -- shutdown(); -- } -- -- private final class OpenSslSession implements SSLSession { -- // SSLSession implementation seems to not need to be thread-safe so no need for volatile etc. -- private X509Certificate[] x509PeerCerts; -- -- // lazy init for memory reasons -- private Map values; -- -- @Override -- public byte[] getId() { -- final byte[] id; -- synchronized (OpenSslEngine.this) { -- if (destroyed == 0) { -- id = SSL.getSessionId(ssl); -- } else { -- id = EmptyArrays.EMPTY_BYTES; -- } -- } -- // We don't cache that to keep memory usage to a minimum. -- if (id == null) { -- // The id should never be null, if it was null then the SESSION itself was not valid. -- throw new IllegalStateException("SSL session ID not available"); -- } -- return id; -- } -- -- @Override -- public SSLSessionContext getSessionContext() { -- return sessionContext; -- } -- -- @Override -- public long getCreationTime() { -- synchronized (OpenSslEngine.this) { -- if (destroyed == 0) { -- // We need ot multiple by 1000 as openssl uses seconds and we need milli-seconds. -- return SSL.getTime(ssl) * 1000L; -- } -- return 0; -- } -- } -- -- @Override -- public long getLastAccessedTime() { -- // TODO: Add proper implementation -- return getCreationTime(); -- } -- -- @Override -- public void invalidate() { -- // NOOP -- } -- -- @Override -- public boolean isValid() { -- 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)); -- } -- } -- -- @Override -- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { -- // these are lazy created to reduce memory overhead -- Certificate[] c = peerCerts; -- if (c == null) { -- synchronized (OpenSslEngine.this) { -- if (destroyed == 0) { -- if (SSL.isInInit(ssl) != 0) { -- throw new SSLPeerUnverifiedException("peer not verified"); -- } -- c = peerCerts = initPeerCertChain(); -- } else { -- c = peerCerts = EMPTY_CERTIFICATES; -- } -- } -- } -- return c; -- } -- -- @Override -- public Certificate[] getLocalCertificates() { -- // TODO: Find out how to get these -- return EMPTY_CERTIFICATES; -- } -- -- @Override -- public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { -- // these are lazy created to reduce memory overhead -- X509Certificate[] c = x509PeerCerts; -- if (c == null) { -- final byte[][] chain; -- synchronized (OpenSslEngine.this) { -- if (destroyed == 0) { -- if (SSL.isInInit(ssl) != 0) { -- throw new SSLPeerUnverifiedException("peer not verified"); -- } -- chain = SSL.getPeerCertChain(ssl); -- } else { -- c = x509PeerCerts = EMPTY_X509_CERTIFICATES; -- return c; -- } -- } -- if (chain == null) { -- throw new SSLPeerUnverifiedException("peer not verified"); -- } -- X509Certificate[] peerCerts = new X509Certificate[chain.length]; -- for (int i = 0; i < peerCerts.length; i++) { -- try { -- peerCerts[i] = X509Certificate.getInstance(chain[i]); -- } catch (CertificateException e) { -- throw new IllegalStateException(e); -- } -- } -- c = x509PeerCerts = peerCerts; -- } -- return c; -- } -- -- @Override -- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { -- Certificate[] peer = getPeerCertificates(); -- if (peer == null || peer.length == 0) { -- return null; -- } -- return principal(peer); -- } -- -- @Override -- public Principal getLocalPrincipal() { -- Certificate[] local = getLocalCertificates(); -- if (local == null || local.length == 0) { -- return null; -- } -- return principal(local); -- } -- -- private Principal principal(Certificate[] certs) { -- return ((java.security.cert.X509Certificate) certs[0]).getIssuerX500Principal(); -- } -- -- @Override -- public String getCipherSuite() { -- if (!handshakeFinished) { -- return INVALID_CIPHER; -- } -- if (cipher == null) { -- final String c; -- synchronized (OpenSslEngine.this) { -- if (destroyed == 0) { -- c = toJavaCipherSuite(SSL.getCipherForSSL(ssl)); -- } else { -- c = INVALID_CIPHER; -- } -- } -- if (c != null) { -- cipher = c; -- } -- } -- return cipher; -- } -- -- @Override -- public String getProtocol() { -- String applicationProtocol = OpenSslEngine.this.applicationProtocol; -- final String version; -- synchronized (OpenSslEngine.this) { -- if (destroyed == 0) { -- version = SSL.getVersion(ssl); -- } else { -- return StringUtil.EMPTY_STRING; -- } -- } -- if (applicationProtocol == null || applicationProtocol.isEmpty()) { -- return version; -- } else { -- return version + ':' + applicationProtocol; -- } -- } -- -- @Override -- public String getPeerHost() { -- return null; -- } -- -- @Override -- public int getPeerPort() { -- return 0; -- } -- -- @Override -- public int getPacketBufferSize() { -- return MAX_ENCRYPTED_PACKET_LENGTH; -- } -- -- @Override -- public int getApplicationBufferSize() { -- return MAX_PLAINTEXT_LENGTH; -- } -- -- private Certificate[] initPeerCertChain() throws SSLPeerUnverifiedException { -- byte[][] chain = SSL.getPeerCertChain(ssl); -- final byte[] clientCert; -- if (!clientMode) { -- // 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 -- clientCert = SSL.getPeerCertificate(ssl); -- } else { -- clientCert = null; -- } -- -- if (chain == null && clientCert == null) { -- throw new SSLPeerUnverifiedException("peer not verified"); -- } -- int len = 0; -- if (chain != null) { -- len += chain.length; -- } -- -- int i = 0; -- Certificate[] peerCerts; -- if (clientCert != null) { -- len++; -- peerCerts = new Certificate[len]; -- peerCerts[i++] = new OpenSslX509Certificate(clientCert); -- } else { -- peerCerts = new Certificate[len]; -- } -- if (chain != null) { -- int a = 0; -- for (; i < peerCerts.length; i++) { -- peerCerts[i] = new OpenSslX509Certificate(chain[a++]); -- } -- } -- return peerCerts; -- } -- } --} -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 382a28d..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java -+++ /dev/null -@@ -1,42 +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 { -- -- OpenSslEngineMap EMPTY = new OpenSslEngineMap() { -- @Override -- public OpenSslEngine remove(long ssl) { -- return null; -- } -- -- @Override -- public void add(OpenSslEngine engine) { -- // NOOP -- } -- }; -- -- /** -- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and -- * return it. -- */ -- OpenSslEngine remove(long ssl); -- -- /** -- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}. -- */ -- void add(OpenSslEngine engine); --} -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 83ee505..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java -+++ /dev/null -@@ -1,418 +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.EmptyArrays; --import org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; -- --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 javax.net.ssl.X509ExtendedTrustManager; --import javax.net.ssl.X509TrustManager; --import java.io.File; --import java.security.KeyStore; --import java.security.cert.X509Certificate; -- --import static io.netty.util.internal.ObjectUtil.*; -- --/** -- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. -- */ --public final class OpenSslServerContext extends OpenSslContext { -- private final OpenSslServerSessionContext sessionContext; -- -- /** -- * Creates a new instance. -- * -- * @param certChainFile an X.509 certificate chain file in PEM format -- * @param keyFile a PKCS#8 private key file in PEM format -- */ -- 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. -- */ -- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException { -- this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE, -- ApplicationProtocolConfig.DISABLED, 0, 0); -- } -- -- /** -- * @deprecated use {@link #OpenSslServerContext( -- * File, File, String, Iterable, CipherSuiteFilter, ApplicationProtocolConfig, long, long)} -- * -- * 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 -- 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); -- } -- -- /** -- * @deprecated Use the constructors that accepts {@link ApplicationProtocolConfig} or -- * {@link ApplicationProtocolNegotiator} instead. -- * -- * 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 -- 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 #OpenSslServerContext(File, TrustManagerFactory, File, File, String, KeyManagerFactory, -- * Iterable, CipherSuiteFilter, ApplicationProtocolConfig, long, long)} -- */ -- @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 #OpenSslServerContext(File, TrustManagerFactory, File, File, String, KeyManagerFactory, -- * Iterable, CipherSuiteFilter, ApplicationProtocolConfig, long, long)} -- */ -- @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. -- */ -- 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 trustCertChainFile an X.509 certificate chain file in PEM format. -- * This provides the certificate chains 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 trustCertChainFile}. -- * @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. -- */ -- public OpenSslServerContext( -- File trustCertChainFile, TrustManagerFactory trustManagerFactory, -- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, -- Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- this(trustCertChainFile, 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 -- 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 #OpenSslServerContext(File, TrustManagerFactory, File, File, String, KeyManagerFactory, -- * Iterable, CipherSuiteFilter, OpenSslApplicationProtocolNegotiator, long, long)} -- */ -- @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 trustCertChainFile an X.509 certificate chain file in PEM format. -- * This provides the certificate chains 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 trustCertChainFile}. -- * @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. -- */ -- public OpenSslServerContext( -- File trustCertChainFile, TrustManagerFactory trustManagerFactory, -- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, -- Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, -- long sessionCacheSize, long sessionTimeout) throws SSLException { -- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER); -- OpenSsl.ensureAvailability(); -- -- checkNotNull(keyCertChainFile, "keyCertChainFile"); -- if (!keyCertChainFile.isFile()) { -- throw new IllegalArgumentException("keyCertChainFile is not a file: " + keyCertChainFile); -- } -- checkNotNull(keyFile, "keyFile"); -- if (!keyFile.isFile()) { -- throw new IllegalArgumentException("keyFile is not a file: " + keyFile); -- } -- if (keyPassword == null) { -- keyPassword = ""; -- } -- -- // Create a new SSL_CTX and configure it. -- boolean success = false; -- try { -- synchronized (OpenSslContext.class) { -- /* Set certificate verification policy. */ -- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); -- -- /* Load the certificate chain. We must skip the first cert when server mode */ -- if (!SSLContext.setCertificateChainFile(ctx, keyCertChainFile.getPath(), true)) { -- long error = SSL.getLastErrorNumber(); -- if (OpenSsl.isError(error)) { -- String err = SSL.getErrorString(error); -- throw new SSLException( -- "failed to set certificate chain: " + keyCertChainFile + " (" + err + ')'); -- } -- } -- -- /* Load the certificate file and private key. */ -- try { -- if (!SSLContext.setCertificate( -- ctx, keyCertChainFile.getPath(), keyFile.getPath(), keyPassword, SSL.SSL_AIDX_RSA)) { -- long error = SSL.getLastErrorNumber(); -- if (OpenSsl.isError(error)) { -- String err = SSL.getErrorString(error); -- throw new SSLException("failed to set certificate: " + -- keyCertChainFile + " and " + keyFile + " (" + err + ')'); -- } -- } -- } catch (SSLException e) { -- throw e; -- } catch (Exception e) { -- throw new SSLException("failed to set certificate: " + keyCertChainFile + " and " + keyFile, e); -- } -- try { -- if (trustManagerFactory == null) { -- // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works -- trustManagerFactory = TrustManagerFactory.getInstance( -- TrustManagerFactory.getDefaultAlgorithm()); -- } -- if (trustCertChainFile != null) { -- trustManagerFactory = buildTrustManagerFactory(trustCertChainFile, trustManagerFactory); -- } else { -- char[] keyPasswordChars = -- keyPassword == null ? EmptyArrays.EMPTY_CHARS : keyPassword.toCharArray(); -- -- KeyStore ks = buildKeyStore(keyCertChainFile, keyFile, keyPasswordChars); -- trustManagerFactory.init(ks); -- } -- -- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); -- -- // Use this to prevent an error when running on java < 7 -- if (useExtendedTrustManager(manager)) { -- final X509ExtendedTrustManager extendedManager = (X509ExtendedTrustManager) manager; -- SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() { -- @Override -- void verify(OpenSslEngine engine, X509Certificate[] peerCerts, String auth) -- throws Exception { -- extendedManager.checkClientTrusted(peerCerts, auth, engine); -- } -- }); -- } else { -- SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() { -- @Override -- void verify(OpenSslEngine engine, X509Certificate[] peerCerts, String auth) -- throws Exception { -- manager.checkClientTrusted(peerCerts, auth); -- } -- }); -- } -- } catch (Exception e) { -- throw new SSLException("unable to setup trustmanager", e); -- } -- } -- sessionContext = new OpenSslServerSessionContext(ctx); -- success = true; -- } finally { -- if (!success) { -- destroyPools(); -- } -- } -- } -- -- @Override -- public OpenSslServerSessionContext sessionContext() { -- return sessionContext; -- } --} -diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java -deleted file mode 100644 -index 693801f..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java -+++ /dev/null -@@ -1,79 +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 org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; -- -- --/** -- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side. -- */ --public final class OpenSslServerSessionContext extends OpenSslSessionContext { -- OpenSslServerSessionContext(long context) { -- super(context); -- } -- -- @Override -- public void setSessionTimeout(int seconds) { -- if (seconds < 0) { -- throw new IllegalArgumentException(); -- } -- SSLContext.setSessionCacheTimeout(context, seconds); -- } -- -- @Override -- public int getSessionTimeout() { -- return (int) SSLContext.getSessionCacheTimeout(context); -- } -- -- @Override -- public void setSessionCacheSize(int size) { -- if (size < 0) { -- throw new IllegalArgumentException(); -- } -- SSLContext.setSessionCacheSize(context, size); -- } -- -- @Override -- public int getSessionCacheSize() { -- return (int) SSLContext.getSessionCacheSize(context); -- } -- -- @Override -- public void setSessionCacheEnabled(boolean enabled) { -- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF; -- SSLContext.setSessionCacheMode(context, mode); -- } -- -- @Override -- public boolean isSessionCacheEnabled() { -- return SSLContext.getSessionCacheMode(context) == SSL.SSL_SESS_CACHE_SERVER; -- } -- -- /** -- * 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) { -- return SSLContext.setSessionIdContext(context, sidCtx); -- } --} -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 fd17821..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java -+++ /dev/null -@@ -1,90 +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 org.apache.tomcat.jni.SSLContext; -- --import javax.net.ssl.SSLSession; --import javax.net.ssl.SSLSessionContext; --import java.util.Enumeration; --import java.util.NoSuchElementException; -- --/** -- * OpenSSL specific {@link SSLSessionContext} implementation. -- */ --public abstract class OpenSslSessionContext implements SSLSessionContext { -- private static final Enumeration EMPTY = new EmptyEnumeration(); -- -- private final OpenSslSessionStats stats; -- final long context; -- -- OpenSslSessionContext(long 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. -- */ -- public void setTicketKeys(byte[] keys) { -- if (keys == null) { -- throw new NullPointerException("keys"); -- } -- SSLContext.setSessionTicketKeys(context, keys); -- } -- -- /** -- * 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 2ec5146..0000000 ---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.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 org.apache.tomcat.jni.SSLContext; -- --/** -- * Stats exposed by an OpenSSL session context. -- * -- * @see SSL_CTX_sess_number -- */ --public final class OpenSslSessionStats { -- -- private final long context; -- -- OpenSslSessionStats(long context) { -- this.context = context; -- } -- -- /** -- * Returns the current number of sessions in the internal session cache. -- */ -- public long number() { -- return SSLContext.sessionNumber(context); -- } -- -- /** -- * Returns the number of started SSL/TLS handshakes in client mode. -- */ -- public long connect() { -- return SSLContext.sessionConnect(context); -- } -- -- /** -- * Returns the number of successfully established SSL/TLS sessions in client mode. -- */ -- public long connectGood() { -- return SSLContext.sessionConnectGood(context); -- } -- -- /** -- * Returns the number of start renegotiations in client mode. -- */ -- public long connectRenegotiate() { -- return SSLContext.sessionConnectRenegotiate(context); -- } -- -- /** -- * Returns the number of started SSL/TLS handshakes in server mode. -- */ -- public long accept() { -- return SSLContext.sessionAccept(context); -- } -- -- /** -- * Returns the number of successfully established SSL/TLS sessions in server mode. -- */ -- public long acceptGood() { -- return SSLContext.sessionAcceptGood(context); -- } -- -- /** -- * Returns the number of start renegotiations in server mode. -- */ -- public long acceptRenegotiate() { -- return SSLContext.sessionAcceptRenegotiate(context); -- } -- -- /** -- * 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() { -- return SSLContext.sessionHits(context); -- } -- -- /** -- * Returns the number of successfully retrieved sessions from the external session cache in server mode. -- */ -- public long cbHits() { -- return SSLContext.sessionCbHits(context); -- } -- -- /** -- * Returns the number of sessions proposed by clients that were not found in the internal session cache -- * in server mode. -- */ -- public long misses() { -- return SSLContext.sessionMisses(context); -- } -- -- /** -- * 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() { -- return SSLContext.sessionTimeouts(context); -- } -- -- /** -- * Returns the number of sessions that were removed because the maximum session cache size was exceeded. -- */ -- public long cacheFull() { -- return SSLContext.sessionCacheFull(context); -- } --} -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 890b362..42abc14 100644 ---- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java -+++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java -@@ -110,11 +110,7 @@ public abstract class SslContext { - } - - private static SslProvider defaultProvider() { -- if (OpenSsl.isAvailable()) { -- return SslProvider.OPENSSL; -- } else { -- return SslProvider.JDK; -- } -+ return SslProvider.JDK; - } - - /** -@@ -399,10 +395,6 @@ public abstract class SslContext { - return new JdkSslServerContext( - trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, - keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); -- case OPENSSL: -- return new OpenSslServerContext( -- trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, -- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); - default: - throw new Error(provider.toString()); - } -@@ -729,10 +721,6 @@ public abstract class SslContext { - return new JdkSslClientContext( - trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, - keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); -- case OPENSSL: -- return new OpenSslClientContext( -- trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, -- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); - } - // Should never happen!! - throw new Error(); -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 a3b1716..c492dc4 100644 ---- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java -+++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java -@@ -161,6 +161,15 @@ import java.util.regex.Pattern; - */ - 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); - -@@ -290,7 +299,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - this.startTls = startTls; - maxPacketBufferSize = engine.getSession().getPacketBufferSize(); - -- boolean opensslEngine = engine instanceof OpenSslEngine; -+ boolean opensslEngine = false; - wantsDirectBuffer = opensslEngine; - wantsLargeOutboundNetworkBuffer = !opensslEngine; - -@@ -883,7 +892,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - - boolean nonSslRecord = false; - -- while (totalLength < OpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { -+ while (totalLength < MAX_ENCRYPTED_PACKET_LENGTH) { - final int readableBytes = endOffset - offset; - if (readableBytes < 5) { - break; -@@ -904,7 +913,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - } - - int newTotalLength = totalLength + packetLength; -- if (newTotalLength > OpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { -+ if (newTotalLength > MAX_ENCRYPTED_PACKET_LENGTH) { - // Don't read too much. - break; - } -@@ -1077,47 +1086,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - private SSLEngineResult unwrap( - SSLEngine engine, ByteBuf in, int readerIndex, int len, ByteBuf out) throws SSLException { - int nioBufferCount = in.nioBufferCount(); -- if (engine instanceof OpenSslEngine && 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. -- */ -- OpenSslEngine opensslEngine = (OpenSslEngine) engine; -- int overflows = 0; -- ByteBuffer[] in0 = in.nioBuffers(readerIndex, len); -- try { -- for (;;) { -- int writerIndex = out.writerIndex(); -- int writableBytes = out.writableBytes(); -- ByteBuffer out0; -- if (out.nioBufferCount() == 1) { -- out0 = out.internalNioBuffer(writerIndex, writableBytes); -- } else { -- out0 = out.nioBuffer(writerIndex, writableBytes); -- } -- singleBuffer[0] = out0; -- SSLEngineResult result = opensslEngine.unwrap(in0, singleBuffer); -- out.writerIndex(out.writerIndex() + result.bytesProduced()); -- switch (result.getStatus()) { -- case BUFFER_OVERFLOW: -- int max = engine.getSession().getApplicationBufferSize(); -- switch (overflows ++) { -- case 0: -- out.ensureWritable(Math.min(max, in.readableBytes())); -- break; -- default: -- out.ensureWritable(max); -- } -- break; -- default: -- return result; -- } -- } -- } finally { -- singleBuffer[0] = null; -- } -- } else { -+ - int overflows = 0; - ByteBuffer in0; - if (nioBufferCount == 1) { -@@ -1154,7 +1123,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - return result; - } - } -- } - } - - /** -@@ -1514,7 +1482,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - return allocate(ctx, maxPacketBufferSize); - } else { - return allocate(ctx, Math.min( -- pendingBytes + OpenSslEngine.MAX_ENCRYPTION_OVERHEAD_LENGTH, -+ pendingBytes + MAX_ENCRYPTION_OVERHEAD_LENGTH, - maxPacketBufferSize)); - } - } -diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -deleted file mode 100644 -index 9482f2b..0000000 ---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java -+++ /dev/null -@@ -1,349 +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.junit.Assert.assertNull; --import static org.junit.Assert.assertTrue; --import static org.junit.Assume.assumeNoException; --import io.netty.bootstrap.Bootstrap; --import io.netty.bootstrap.ServerBootstrap; --import io.netty.channel.Channel; --import io.netty.channel.ChannelFuture; --import io.netty.channel.ChannelHandlerAdapter; --import io.netty.channel.ChannelHandlerContext; --import io.netty.channel.ChannelInitializer; --import io.netty.channel.ChannelPipeline; --import io.netty.channel.nio.NioEventLoopGroup; --import io.netty.channel.socket.nio.NioServerSocketChannel; --import io.netty.channel.socket.nio.NioSocketChannel; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; --import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectorFactory; --import io.netty.handler.ssl.util.InsecureTrustManagerFactory; --import io.netty.handler.ssl.util.SelfSignedCertificate; --import io.netty.util.NetUtil; -- --import java.net.InetSocketAddress; --import java.security.cert.CertificateException; --import java.util.List; --import java.util.Set; --import java.util.concurrent.TimeUnit; -- --import javax.net.ssl.SSLEngine; --import javax.net.ssl.SSLException; --import javax.net.ssl.SSLHandshakeException; -- --import org.junit.Test; -- --public class JdkSslEngineTest extends SSLEngineTest { -- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2"; -- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1"; -- private static final String APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE = "my-protocol-FOO"; -- -- @Test -- public void testNpn() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkNpnSslEngine.isAvailable()) { -- throw new RuntimeException("NPN not on classpath"); -- } -- JdkApplicationProtocolNegotiator apn = new JdkNpnApplicationProtocolNegotiator(true, true, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- mySetup(apn); -- runTest(); -- } catch (RuntimeException e) { -- // NPN availability is dependent on the java version. If NPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testNpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkNpnSslEngine.isAvailable()) { -- throw new RuntimeException("NPN not on classpath"); -- } -- JdkApplicationProtocolNegotiator clientApn = new JdkNpnApplicationProtocolNegotiator(false, false, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- JdkApplicationProtocolNegotiator serverApn = new JdkNpnApplicationProtocolNegotiator(false, false, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- mySetup(serverApn, clientApn); -- runTest(null); -- } catch (Exception e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testNpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkNpnSslEngine.isAvailable()) { -- throw new RuntimeException("NPN not on classpath"); -- } -- JdkApplicationProtocolNegotiator clientApn = new JdkNpnApplicationProtocolNegotiator(true, true, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- JdkApplicationProtocolNegotiator serverApn = new JdkNpnApplicationProtocolNegotiator(false, false, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- mySetup(serverApn, clientApn); -- assertTrue(clientLatch.await(2, TimeUnit.SECONDS)); -- assertTrue(clientException instanceof SSLHandshakeException); -- } catch (RuntimeException e) { -- // NPN availability is dependent on the java version. If NPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testNpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkNpnSslEngine.isAvailable()) { -- throw new RuntimeException("NPN not on classpath"); -- } -- JdkApplicationProtocolNegotiator clientApn = new JdkNpnApplicationProtocolNegotiator(false, false, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- JdkApplicationProtocolNegotiator serverApn = new JdkNpnApplicationProtocolNegotiator(true, true, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- mySetup(serverApn, clientApn); -- assertTrue(serverLatch.await(2, TimeUnit.SECONDS)); -- assertTrue(serverException instanceof SSLHandshakeException); -- } catch (RuntimeException e) { -- // NPN availability is dependent on the java version. If NPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testAlpn() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw new RuntimeException("ALPN not on classpath"); -- } -- JdkApplicationProtocolNegotiator apn = new JdkAlpnApplicationProtocolNegotiator(true, true, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- mySetup(apn); -- runTest(); -- } catch (Exception e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testAlpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw new RuntimeException("ALPN not on classpath"); -- } -- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(false, false, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(false, false, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- mySetup(serverApn, clientApn); -- runTest(null); -- } catch (Exception e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testAlpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw new RuntimeException("ALPN not on classpath"); -- } -- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(false, false, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(true, true, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- mySetup(serverApn, clientApn); -- assertTrue(serverLatch.await(2, TimeUnit.SECONDS)); -- assertTrue(serverException instanceof SSLHandshakeException); -- } catch (Exception e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw new RuntimeException("ALPN not on classpath"); -- } -- // Even the preferred application protocol appears second in the client's list, it will be picked -- // because it's the first one on server's list. -- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(false, false, -- FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(true, true, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL); -- mySetup(serverApn, clientApn); -- assertNull(serverException); -- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- } catch (Exception e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- @Test -- public void testAlpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception { -- try { -- // Typical code will not have to check this, but will get a initialization error on class load. -- // Check in this test just in case we have multiple tests that just the class and we already ignored the -- // initialization error. -- if (!JdkAlpnSslEngine.isAvailable()) { -- throw new RuntimeException("ALPN not on classpath"); -- } -- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(true, true, -- PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator( -- new ProtocolSelectorFactory() { -- @Override -- public ProtocolSelector newSelector(SSLEngine engine, Set supportedProtocols) { -- return new ProtocolSelector() { -- @Override -- public void unsupported() { -- } -- -- @Override -- public String select(List protocols) { -- return APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE; -- } -- }; -- } -- }, JdkBaseApplicationProtocolNegotiator.FAIL_SELECTION_LISTENER_FACTORY, -- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE); -- mySetup(serverApn, clientApn); -- assertTrue(clientLatch.await(2, TimeUnit.SECONDS)); -- assertTrue(clientException instanceof SSLHandshakeException); -- } catch (Exception e) { -- // ALPN availability is dependent on the java version. If ALPN is not available because of -- // java version incompatibility don't fail the test, but instead just skip the test -- assumeNoException(e); -- } -- } -- -- private void mySetup(JdkApplicationProtocolNegotiator apn) throws InterruptedException, SSLException, -- CertificateException { -- mySetup(apn, apn); -- } -- -- private void mySetup(JdkApplicationProtocolNegotiator serverApn, JdkApplicationProtocolNegotiator clientApn) -- throws InterruptedException, SSLException, CertificateException { -- SelfSignedCertificate ssc = new SelfSignedCertificate(); -- serverSslCtx = new JdkSslServerContext(ssc.certificate(), ssc.privateKey(), null, null, -- IdentityCipherSuiteFilter.INSTANCE, serverApn, 0, 0); -- clientSslCtx = new JdkSslClientContext(null, InsecureTrustManagerFactory.INSTANCE, null, -- IdentityCipherSuiteFilter.INSTANCE, clientApn, 0, 0); -- -- serverConnectedChannel = null; -- sb = new ServerBootstrap(); -- cb = new Bootstrap(); -- -- sb.group(new NioEventLoopGroup(), new NioEventLoopGroup()); -- sb.channel(NioServerSocketChannel.class); -- sb.childHandler(new ChannelInitializer() { -- @Override -- protected void initChannel(Channel ch) throws Exception { -- ChannelPipeline p = ch.pipeline(); -- p.addLast(serverSslCtx.newHandler(ch.alloc())); -- p.addLast(new MessageDelegatorChannelHandler(serverReceiver, serverLatch)); -- p.addLast(new ChannelHandlerAdapter() { -- @Override -- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { -- if (cause.getCause() instanceof SSLHandshakeException) { -- serverException = cause.getCause(); -- serverLatch.countDown(); -- } else { -- ctx.fireExceptionCaught(cause); -- } -- } -- }); -- serverConnectedChannel = ch; -- } -- }); -- -- cb.group(new NioEventLoopGroup()); -- cb.channel(NioSocketChannel.class); -- cb.handler(new ChannelInitializer() { -- @Override -- protected void initChannel(Channel ch) throws Exception { -- ChannelPipeline p = ch.pipeline(); -- p.addLast(clientSslCtx.newHandler(ch.alloc())); -- p.addLast(new MessageDelegatorChannelHandler(clientReceiver, clientLatch)); -- p.addLast(new ChannelHandlerAdapter() { -- @Override -- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { -- if (cause.getCause() instanceof SSLHandshakeException) { -- clientException = cause.getCause(); -- clientLatch.countDown(); -- } else { -- ctx.fireExceptionCaught(cause); -- } -- } -- }); -- } -- }); -- -- serverChannel = sb.bind(new InetSocketAddress(0)).sync().channel(); -- int port = ((InetSocketAddress) serverChannel.localAddress()).getPort(); -- -- ChannelFuture ccf = cb.connect(new InetSocketAddress(NetUtil.LOCALHOST, port)); -- assertTrue(ccf.awaitUninterruptibly().isSuccess()); -- clientChannel = ccf.channel(); -- } -- -- private void runTest() throws Exception { -- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); -- } -- -- @Override -- protected SslProvider sslProvider() { -- return SslProvider.JDK; -- } --} diff --git a/sources b/sources index 45d1316..dee10a7 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -a38973b451fb2c8e59c1adb01b292224 netty-4.0.28.Final.tar.gz +1259f8126350883c5770bd26a6896fc0 netty-4.0.42.Final.tar.gz diff --git a/transport-native-epoll-configure-fix.patch b/transport-native-epoll-configure-fix.patch deleted file mode 100644 index 08e8489..0000000 --- a/transport-native-epoll-configure-fix.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/netty-netty-4.0.27.Final/transport-native-epoll/pom.xml b/netty-netty-4.0.27.Final/transport-native-epoll/pom.xml -index c9c7b25..b489b3f 100644 ---- a/netty-netty-4.0.27.Final/transport-native-epoll/pom.xml -+++ b/netty-netty-4.0.27.Final/transport-native-epoll/pom.xml -@@ -73,9 +73,6 @@ - . - true - true -- -- ${jni.compiler.args} -- - - - generate