From 8b7286b1c8cd740e85fc483c1be6fcc8ce478ec4 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf <sgehwolf@redhat.com> 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 <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support - * are available. - */ -public final class OpenSsl { - - private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class); - private static final String LINUX = "linux"; - private static final String UNKNOWN = "unknown"; - private static final Throwable UNAVAILABILITY_CAUSE; - - static final Set<String> AVAILABLE_CIPHER_SUITES; - private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES; - private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES; - private static final boolean SUPPORTS_KEYMANAGER_FACTORY; - private static final boolean USE_KEYMANAGER_FACTORY; - - // 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<String> SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet( - new HashSet<String>(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<String> availableOpenSslCipherSuites = new LinkedHashSet<String>(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<Boolean>() { - @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<String> availableJavaCipherSuites = new LinkedHashSet<String>( - AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2); - for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) { - // Included converted but also openssl cipher name - availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS")); - availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL")); - } - AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites); - - final Set<String> availableCipherSuites = new LinkedHashSet<String>( - 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<Boolean>() { - @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 - * <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support - * are available. - */ - public static boolean isAvailable() { - return UNAVAILABILITY_CAUSE == null; - } - - /** - * Returns {@code true} if the used version of openssl supports - * <a href="https://tools.ietf.org/html/rfc7301">ALPN</a>. - */ - public static boolean isAlpnSupported() { - return version() >= 0x10002000L; - } - - /** - * 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 <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and - * its OpenSSL support are available. - * - * @throws UnsatisfiedLinkError if unavailable - */ - public static void ensureAvailability() { - if (UNAVAILABILITY_CAUSE != null) { - throw (Error) new UnsatisfiedLinkError( - "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE); - } - } - - /** - * Returns the cause of unavailability of - * <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support. - * - * @return the cause if unavailable. {@code null} if available. - */ - public static Throwable unavailabilityCause() { - return UNAVAILABILITY_CAUSE; - } - - /** - * @deprecated use {@link #availableOpenSslCipherSuites()} - */ - @Deprecated - public static Set<String> availableCipherSuites() { - return availableOpenSslCipherSuites(); - } - - /** - * Returns all the available OpenSSL cipher suites. - * Please note that the returned array may include the cipher suites that are insecure or non-functional. - */ - public static Set<String> availableOpenSslCipherSuites() { - return AVAILABLE_OPENSSL_CIPHER_SUITES; - } - - /** - * Returns all the available cipher suites (Java-style). - * Please note that the returned array may include the cipher suites that are insecure or non-functional. - */ - public static Set<String> availableJavaCipherSuites() { - return AVAILABLE_JAVA_CIPHER_SUITES; - } - - /** - * Returns {@code true} if and only if the specified cipher suite is available in OpenSSL. - * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted. - */ - public static boolean isCipherSuiteAvailable(String cipherSuite) { - String converted = CipherSuiteConverter.toOpenSsl(cipherSuite); - 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<String> libNames = new LinkedHashSet<String>(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 - * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a>. - */ - public OpenSslCertificateException(int errorCode) { - this((String) null, errorCode); - } - - /** - * Construct a new exception with the msg and - * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> . - */ - public OpenSslCertificateException(String msg, int errorCode) { - super(msg); - this.errorCode = checkErrorCode(errorCode); - } - - /** - * Construct a new exception with the msg, cause and - * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> . - */ - public OpenSslCertificateException(String message, Throwable cause, int errorCode) { - super(message, cause); - this.errorCode = checkErrorCode(errorCode); - } - - /** - * Construct a new exception with the cause and - * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> . - */ - public OpenSslCertificateException(Throwable cause, int errorCode) { - this(null, cause, errorCode); - } - - /** - * Return the <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> 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. - * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers - * and manually release the native memory see {@link ReferenceCountedOpenSslClientContext}. - */ -public final class OpenSslClientContext extends OpenSslContext { - private final OpenSslSessionContext sessionContext; - - /** - * Creates a new instance. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated - public OpenSslClientContext() throws SSLException { - this((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<String> ciphers, - ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) - throws SSLException { - this(certChainFile, trustManagerFactory, null, null, null, null, ciphers, IdentityCipherSuiteFilter.INSTANCE, - apn, sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * - * @param certChainFile an X.509 certificate chain file in PEM format - * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s - * that verifies the certificates sent from servers. - * {@code null} to use the default.. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param cipherFilter a filter to apply over the supplied list of ciphers - * @param apn Provides a means to configure parameters related to application protocol negotiation. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. - * {@code 0} to use the default value. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated - public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers, - CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, - long sessionCacheSize, long sessionTimeout) throws SSLException { - this(certChainFile, trustManagerFactory, null, null, null, null, - ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. - * {@code null} to use the system default - * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s - * that verifies the certificates sent from servers. - * {@code null} to use the default or the results of parsing - * {@code trustCertCollectionFile} - * @param keyCertChainFile an X.509 certificate chain file in PEM format. - * This provides the public key for mutual authentication. - * {@code null} to use the system default - * @param keyFile a PKCS#8 private key file in PEM format. - * This provides the private key for mutual authentication. - * {@code null} for no mutual authentication. - * @param keyPassword the password of the {@code keyFile}. - * {@code null} if it's not password-protected. - * Ignored if {@code keyFile} is {@code null}. - * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link javax.net.ssl.KeyManager}s - * that is used to encrypt data being sent to servers. - * {@code null} to use the default or the results of parsing - * {@code keyCertChainFile} and {@code keyFile}. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param cipherFilter a filter to apply over the supplied list of ciphers - * @param apn Application Protocol Negotiator object. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. - * {@code 0} to use the default value. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated - public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, - File keyCertChainFile, File keyFile, String keyPassword, - KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, - CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, - long sessionCacheSize, long sessionTimeout) - throws SSLException { - this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, - toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), - keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); - } - - OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, - X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, - KeyManagerFactory keyManagerFactory, Iterable<String> 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<String> 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<String> 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 - * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>. - * <p> - * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers - * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}. - */ -public final class OpenSslEngine extends ReferenceCountedOpenSslEngine { - OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int peerPort) { - 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<String, String> KEY_TYPES = new HashMap<String, String>(); - static { - KEY_TYPES.put("RSA", KEY_TYPE_RSA); - KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA); - KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA); - KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC); - KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA); - KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC); - KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA); - } - - private final 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<String> aliases = new HashSet<String>(authMethods.length); - for (String authMethod : authMethods) { - String type = KEY_TYPES.get(authMethod); - if (type != null) { - String alias = chooseServerAlias(engine, type); - if (alias != null && aliases.add(alias)) { - setKeyMaterial(ssl, alias); - } - } - } - } - - 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. - * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers - * and manually release the native memory see {@link ReferenceCountedOpenSslServerContext}. - */ -public final class OpenSslServerContext extends OpenSslContext { - private final OpenSslServerSessionContext sessionContext; - 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<String> ciphers, ApplicationProtocolConfig apn, - long sessionCacheSize, long sessionTimeout) throws SSLException { - this(certChainFile, keyFile, keyPassword, ciphers, IdentityCipherSuiteFilter.INSTANCE, - apn, sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * - * @param certChainFile an X.509 certificate chain file in PEM format - * @param keyFile a PKCS#8 private key file in PEM format - * @param keyPassword the password of the {@code keyFile}. - * {@code null} if it's not password-protected. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param nextProtocols the application layer protocols to accept, in the order of preference. - * {@code null} to disable TLS NPN/ALPN extension. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. - * {@code 0} to use the default value. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated - public OpenSslServerContext( - File certChainFile, File keyFile, String keyPassword, - Iterable<String> ciphers, Iterable<String> nextProtocols, - long sessionCacheSize, long sessionTimeout) throws SSLException { - this(certChainFile, keyFile, keyPassword, ciphers, - toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * - * @param certChainFile an X.509 certificate chain file in PEM format - * @param keyFile a PKCS#8 private key file in PEM format - * @param keyPassword the password of the {@code keyFile}. - * {@code null} if it's not password-protected. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param config Application protocol config. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. - * {@code 0} to use the default value. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated - public OpenSslServerContext( - File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, - Iterable<String> ciphers, ApplicationProtocolConfig config, - long sessionCacheSize, long sessionTimeout) throws SSLException { - this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers, - toNegotiator(config), sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * - * @param certChainFile an X.509 certificate chain file in PEM format - * @param keyFile a PKCS#8 private key file in PEM format - * @param keyPassword the password of the {@code keyFile}. - * {@code null} if it's not password-protected. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param apn Application protocol negotiator. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. - * {@code 0} to use the default value. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated - public OpenSslServerContext( - File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, - Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn, - long sessionCacheSize, long sessionTimeout) throws SSLException { - this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, - ciphers, null, apn, sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * - * @param certChainFile an X.509 certificate chain file in PEM format - * @param keyFile a PKCS#8 private key file in PEM format - * @param keyPassword the password of the {@code keyFile}. - * {@code null} if it's not password-protected. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param cipherFilter a filter to apply over the supplied list of ciphers - * @param apn Provides a means to configure parameters related to application protocol negotiation. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. - * {@code 0} to use the default value. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated - public OpenSslServerContext( - File certChainFile, File keyFile, String keyPassword, - Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, - long sessionCacheSize, long sessionTimeout) throws SSLException { - this(null, null, certChainFile, keyFile, keyPassword, null, - ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * - * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. - * This provides the certificate collection used for mutual authentication. - * {@code null} to use the system default - * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s - * that verifies the certificates sent from clients. - * {@code null} to use the default or the results of parsing - * {@code trustCertCollectionFile}. - * @param keyCertChainFile an X.509 certificate chain file in PEM format - * @param keyFile a PKCS#8 private key file in PEM format - * @param keyPassword the password of the {@code keyFile}. - * {@code null} if it's not password-protected. - * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s - * that is used to encrypt data being sent to clients. - * {@code null} to use the default or the results of parsing - * {@code keyCertChainFile} and {@code keyFile}. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param cipherFilter a filter to apply over the supplied list of ciphers - * Only required if {@code provider} is {@link SslProvider#JDK} - * @param config Provides a means to configure parameters related to application protocol negotiation. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. - * {@code 0} to use the default value. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated - public OpenSslServerContext( - File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, - File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, - Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config, - long sessionCacheSize, long sessionTimeout) throws SSLException { - this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory, - ciphers, cipherFilter, toNegotiator(config), sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * - * @param certChainFile an X.509 certificate chain file in PEM format - * @param keyFile a PKCS#8 private key file in PEM format - * @param keyPassword the password of the {@code keyFile}. - * {@code null} if it's not password-protected. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param cipherFilter a filter to apply over the supplied list of ciphers - * @param config Application protocol config. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. - * {@code 0} to use the default value. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated - public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword, - TrustManagerFactory trustManagerFactory, Iterable<String> ciphers, - CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config, - long sessionCacheSize, long sessionTimeout) throws SSLException { - this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter, - toNegotiator(config), sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * - * @param certChainFile an X.509 certificate chain file in PEM format - * @param keyFile a PKCS#8 private key file in PEM format - * @param keyPassword the password of the {@code keyFile}. - * {@code null} if it's not password-protected. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param cipherFilter a filter to apply over the supplied list of ciphers - * @param apn Application protocol negotiator. - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. - * {@code 0} to use the default value. - * @deprecated use {@link SslContextBuilder}} - */ - @Deprecated - public OpenSslServerContext( - File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory, - Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, - long sessionCacheSize, long sessionTimeout) throws SSLException { - this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter, - apn, sessionCacheSize, sessionTimeout); - } - - /** - * Creates a new instance. - * - * - * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. - * This provides the certificate collection used for mutual authentication. - * {@code null} to use the system default - * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s - * that verifies the certificates sent from clients. - * {@code null} to use the default or the results of parsing - * {@code trustCertCollectionFile}. - * @param keyCertChainFile an X.509 certificate chain file in PEM format - * @param keyFile a PKCS#8 private key file in PEM format - * @param keyPassword the password of the {@code keyFile}. - * {@code null} if it's not password-protected. - * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s - * that is used to encrypt data being sent to clients. - * {@code null} to use the default or the results of parsing - * {@code keyCertChainFile} and {@code keyFile}. - * @param ciphers the cipher suites to enable, in the order of preference. - * {@code null} to use the default cipher suites. - * @param cipherFilter a filter to apply over the supplied list of ciphers - * Only required if {@code provider} is {@link SslProvider#JDK} - * @param apn Application Protocol Negotiator object - * @param sessionCacheSize the size of the cache used for storing SSL session objects. - * {@code 0} to use the default value. - * @param sessionTimeout the timeout for the cached SSL session objects, in seconds. - * {@code 0} to use the default value. - * @deprecated use {@link SslContextBuilder} - */ - @Deprecated - public OpenSslServerContext( - File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, - File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, - Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, - long sessionCacheSize, long sessionTimeout) throws SSLException { - this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, - toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), - keyPassword, keyManagerFactory, ciphers, cipherFilter, - apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, false); - } - - OpenSslServerContext( - X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, - X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, - Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, - long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, 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<String> 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 <a href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context.html"> - * man SSL_CTX_set_session_id_context</a> - * - * @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name - * of the application and/or the hostname and/or service name - * @return {@code true} if success, {@code false} otherwise. - */ - public boolean setSessionIdContext(byte[] sidCtx) { - 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<byte[]> EMPTY = new EmptyEnumeration(); - - private final OpenSslSessionStats stats; - final ReferenceCountedOpenSslContext context; - - // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent - // the GC to collect OpenSslContext as this would also free the pointer and so could result in a - // segfault when the user calls any of the methods here that try to pass the pointer down to the native - // level. - OpenSslSessionContext(ReferenceCountedOpenSslContext context) { - this.context = context; - stats = new OpenSslSessionStats(context); - } - - @Override - public SSLSession getSession(byte[] bytes) { - if (bytes == null) { - throw new NullPointerException("bytes"); - } - return null; - } - - @Override - public Enumeration<byte[]> getIds() { - return EMPTY; - } - - /** - * Sets the SSL session ticket keys of this context. - * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}. - */ - @Deprecated - public void setTicketKeys(byte[] keys) { - 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<byte[]> { - @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 <a href="https://www.openssl.org/docs/ssl/SSL_CTX_sess_number.html"><code>SSL_CTX_sess_number</code></a> - */ -public final class OpenSslSessionStats { - - private final ReferenceCountedOpenSslContext context; - - // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent - // the GC to collect OpenSslContext as this would also free the pointer and so could result in a - // segfault when the user calls any of the methods here that try to pass the pointer down to the native - // level. - OpenSslSessionStats(ReferenceCountedOpenSslContext context) { - this.context = context; - } - - /** - * Returns the current number of sessions in the internal session cache. - */ - public long number() { - 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. - * <p>Instances of this class must be {@link #release() released} or else native memory will leak! - * - * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine} - * which depends upon the instance of this class is released. Otherwise if any method of - * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. - */ -public final class ReferenceCountedOpenSslClientContext extends ReferenceCountedOpenSslContext { - private static final InternalLogger logger = - InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class); - private final OpenSslSessionContext sessionContext; - - ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, - X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, - KeyManagerFactory keyManagerFactory, Iterable<String> 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<String> keyTypesSet = supportedClientKeyTypes(keyTypeBytes); - final String[] keyTypes = keyTypesSet.toArray(new String[keyTypesSet.size()]); - final X500Principal[] issuers; - if (asn1DerEncodedPrincipals == null) { - issuers = null; - } else { - issuers = new X500Principal[asn1DerEncodedPrincipals.length]; - for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) { - issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]); - } - } - return keyManagerHolder.keyMaterial(engine, keyTypes, issuers); - } catch (Throwable cause) { - logger.debug("request of key failed", cause); - SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem"); - e.initCause(cause); - engine.handshakeException = e; - return null; - } - } - - /** - * Gets the supported key types for client certificates. - * - * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server. - * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml. - * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and - * {@code X509ExtendedKeyManager.chooseEngineClientAlias}. - */ - private static Set<String> supportedClientKeyTypes(byte[] clientCertificateTypes) { - Set<String> result = new HashSet<String>(clientCertificateTypes.length); - for (byte keyTypeCode : clientCertificateTypes) { - String keyType = clientKeyType(keyTypeCode); - if (keyType == null) { - // Unsupported client key type -- ignore - continue; - } - result.add(keyType); - } - 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 - * <a href="https://www.openssl.org/">OpenSsl</a> C library API. - * <p>Instances of this class must be {@link #release() released} or else native memory will leak! - * - * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine} - * which depends upon the instance of this class is released. Otherwise if any method of - * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. - */ -public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted { - private static final InternalLogger logger = - InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class); - /** - * 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. - * <p> - * See also <a href="http://blog.ivanristic.com/2014/03/ssl-tls-improvements-in-java-8.html"> - * Significant SSL/TLS improvements in Java 8</a> - */ - private static final boolean JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION = - AccessController.doPrivileged(new PrivilegedAction<Boolean>() { - @Override - public Boolean run() { - return SystemPropertyUtil.getBoolean("jdk.tls.rejectClientInitiatedRenegotiation", false); - } - }); - private static final List<String> DEFAULT_CIPHERS; - private static final Integer DH_KEY_LENGTH; - private static final ResourceLeakDetector<ReferenceCountedOpenSslContext> leakDetector = - ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class); - - // 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<String> 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<String> protocols() { - return Collections.emptyList(); - } - - @Override - public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() { - return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL; - } - - @Override - public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() { - return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT; - } - }; - - static { - List<String> ciphers = new ArrayList<String>(); - // XXX: Make sure to sync this list with JdkSslEngineFactory. - Collections.addAll( - ciphers, - "ECDHE-ECDSA-AES256-GCM-SHA384", - "ECDHE-ECDSA-AES128-GCM-SHA256", - "ECDHE-RSA-AES128-GCM-SHA256", - "ECDHE-RSA-AES128-SHA", - "ECDHE-RSA-AES256-SHA", - "AES128-GCM-SHA256", - "AES128-SHA", - "AES256-SHA"); - DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers); - - if (logger.isDebugEnabled()) { - logger.debug("Default cipher suite (OpenSSL): " + ciphers); - } - - Integer dhLen = null; - - try { - String dhKeySize = AccessController.doPrivileged(new PrivilegedAction<String>() { - @Override - public String run() { - return SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize"); - } - }); - if (dhKeySize != null) { - try { - dhLen = Integer.valueOf(dhKeySize); - } catch (NumberFormatException e) { - logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: " - + dhKeySize); - } - } - } catch (Throwable ignore) { - // ignore - } - DH_KEY_LENGTH = dhLen; - } - - ReferenceCountedOpenSslContext(Iterable<String> 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<String> 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<String> convertedCiphers; - if (ciphers == null) { - convertedCiphers = null; - } else { - convertedCiphers = new ArrayList<String>(); - for (String c : ciphers) { - if (c == null) { - break; - } - - String converted = CipherSuiteConverter.toOpenSsl(c); - if (converted != null) { - c = converted; - } - convertedCiphers.add(c); - } - } - - 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<String> 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<String> 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<Long, ReferenceCountedOpenSslEngine> engines = PlatformDependent.newConcurrentHashMap(); - - @Override - public ReferenceCountedOpenSslEngine remove(long ssl) { - return engines.remove(ssl); - } - - @Override - public void add(ReferenceCountedOpenSslEngine engine) { - engines.put(engine.sslPointer(), engine); - } - - @Override - public ReferenceCountedOpenSslEngine get(long ssl) { - return engines.get(ssl); - } - } - - static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword) - throws SSLException { - /* Load the certificate file and private key. */ - long keyBio = 0; - long keyCertChainBio = 0; - long keyCertChainBio2 = 0; - PemEncoded encoded = null; - try { - // Only encode one time - encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain); - keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); - keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); - - if (key != null) { - keyBio = toBIO(key); - } - - SSLContext.setCertificateBio( - ctx, keyCertChainBio, keyBio, - keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword); - // We may have more then one cert in the chain so add all of them now. - SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true); - } catch (SSLException e) { - throw e; - } catch (Exception e) { - throw new SSLException("failed to set certificate and key", e); - } finally { - freeBio(keyBio); - freeBio(keyCertChainBio); - freeBio(keyCertChainBio2); - if (encoded != null) { - encoded.release(); - } - } - } - - static void freeBio(long bio) { - if (bio != 0) { - SSL.freeBIO(bio); - } - } - - /** - * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a> - * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}. - */ - static long toBIO(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 <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a> - * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}. - */ - static long toBIO(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 - * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>. - * <p>Instances of this class must be {@link #release() released} or else native memory will leak! - * - * <p>Instances of this class <strong>must</strong> be released before the {@link ReferenceCountedOpenSslContext} - * the instance depends upon are released. Otherwise if any method of this class is called which uses the - * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash. - */ -public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted { - - 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<ReferenceCountedOpenSslEngine> leakDetector = - ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class); - - static { - AtomicIntegerFieldUpdater<ReferenceCountedOpenSslEngine> 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<ReferenceCountedOpenSslEngine> 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<String> 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<String, Object> 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<String, Object> values = this.values; - if (values == null) { - // Use size of 2 to keep the memory overhead small - values = this.values = new HashMap<String, Object>(2); - } - Object old = values.put(name, value); - if (value instanceof SSLSessionBindingListener) { - ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name)); - } - notifyUnbound(old, name); - } - - @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<String, Object> values = this.values; - if (values == null) { - return; - } - Object old = values.remove(name); - notifyUnbound(old, name); - } - - @Override - public String[] getValueNames() { - Map<String, Object> values = this.values; - if (values == null || values.isEmpty()) { - return EmptyArrays.EMPTY_STRINGS; - } - return values.keySet().toArray(new String[values.size()]); - } - - 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<String> protocols = apn.protocols(); - String applicationProtocol; - switch (apn.protocol()) { - case NONE: - break; - // We always need to check for applicationProtocol == null as the remote peer may not support - // the TLS extension or may have returned an empty selection. - case ALPN: - applicationProtocol = SSL.getAlpnSelected(ssl); - if (applicationProtocol != null) { - this.applicationProtocol = selectApplicationProtocol( - protocols, behavior, applicationProtocol); - } - break; - case NPN: - applicationProtocol = SSL.getNextProtoNegotiated(ssl); - if (applicationProtocol != null) { - this.applicationProtocol = selectApplicationProtocol( - protocols, behavior, applicationProtocol); - } - break; - case NPN_AND_ALPN: - applicationProtocol = SSL.getAlpnSelected(ssl); - if (applicationProtocol == null) { - applicationProtocol = SSL.getNextProtoNegotiated(ssl); - } - if (applicationProtocol != null) { - this.applicationProtocol = selectApplicationProtocol( - protocols, behavior, applicationProtocol); - } - break; - default: - throw new Error(); - } - } - - private String selectApplicationProtocol(List<String> protocols, - ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior, - String applicationProtocol) throws SSLException { - if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) { - return applicationProtocol; - } else { - int size = protocols.size(); - assert size > 0; - if (protocols.contains(applicationProtocol)) { - return applicationProtocol; - } else { - if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) { - return protocols.get(size - 1); - } else { - throw new SSLException("unknown protocol " + applicationProtocol); - } - } - } - } - - @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. - * <p>Instances of this class must be {@link #release() released} or else native memory will leak! - * - * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine} - * which depends upon the instance of this class is released. Otherwise if any method of - * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. - */ -public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext { - private static final 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<String> 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<String> 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