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

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

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

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

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

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

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

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

- * See also - * Significant SSL/TLS improvements in Java 8 - */ - private static final boolean JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION = - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Boolean run() { - return SystemPropertyUtil.getBoolean("jdk.tls.rejectClientInitiatedRenegotiation", false); - } - }); - - private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE = - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Integer run() { - return Math.max(1, - SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize", - 2048)); - } - }); - - private static final List DEFAULT_CIPHERS; - private static final Integer DH_KEY_LENGTH; - private static final ResourceLeakDetector leakDetector = - ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class); - - // TODO: Maybe make configurable ? - protected static final int VERIFY_DEPTH = 10; - - /** - * The OpenSSL SSL_CTX object. - * - * {@link #ctxLock} must be hold while using ctx! - */ - protected long ctx; - private final List unmodifiableCiphers; - private final long sessionCacheSize; - private final long sessionTimeout; - private final OpenSslApplicationProtocolNegotiator apn; - private final int mode; - - // Reference Counting - private final ResourceLeakTracker leak; - private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() { - @Override - public ReferenceCounted touch(Object hint) { - if (leak != null) { - leak.record(hint); - } - - return ReferenceCountedOpenSslContext.this; - } - - @Override - protected void deallocate() { - destroy(); - if (leak != null) { - boolean closed = leak.close(ReferenceCountedOpenSslContext.this); - assert closed; - } - } - }; - - final Certificate[] keyCertChain; - final ClientAuth clientAuth; - final String[] protocols; - final boolean enableOcsp; - final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap(); - final ReadWriteLock ctxLock = new ReentrantReadWriteLock(); - - private volatile boolean rejectRemoteInitiatedRenegotiation; - private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE; - - static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR = - new OpenSslApplicationProtocolNegotiator() { - @Override - public ApplicationProtocolConfig.Protocol protocol() { - return ApplicationProtocolConfig.Protocol.NONE; - } - - @Override - public List protocols() { - return Collections.emptyList(); - } - - @Override - public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() { - return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL; - } - - @Override - public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() { - return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT; - } - }; - - static { - List ciphers = new ArrayList(); - // XXX: Make sure to sync this list with JdkSslEngineFactory. - Collections.addAll( - ciphers, - "ECDHE-ECDSA-AES256-GCM-SHA384", - "ECDHE-ECDSA-AES128-GCM-SHA256", - "ECDHE-RSA-AES128-GCM-SHA256", - "ECDHE-RSA-AES128-SHA", - "ECDHE-RSA-AES256-SHA", - "AES128-GCM-SHA256", - "AES128-SHA", - "AES256-SHA"); - DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers); - - if (logger.isDebugEnabled()) { - logger.debug("Default cipher suite (OpenSSL): " + ciphers); - } - - Integer dhLen = null; - - try { - String dhKeySize = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public String run() { - return SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize"); - } - }); - if (dhKeySize != null) { - try { - dhLen = Integer.valueOf(dhKeySize); - } catch (NumberFormatException e) { - logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: " - + dhKeySize); - } - } - } catch (Throwable ignore) { - // ignore - } - DH_KEY_LENGTH = dhLen; - } - - ReferenceCountedOpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, - ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout, - int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols, - boolean startTls, boolean enableOcsp, boolean leakDetection) throws SSLException { - this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain, - clientAuth, protocols, startTls, enableOcsp, leakDetection); - } - - ReferenceCountedOpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, - OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, - long sessionTimeout, int mode, Certificate[] keyCertChain, - ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp, - boolean leakDetection) throws SSLException { - super(startTls); - - OpenSsl.ensureAvailability(); - - if (enableOcsp && !OpenSsl.isOcspSupported()) { - throw new IllegalStateException("OCSP is not supported."); - } - - if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) { - throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT"); - } - leak = leakDetection ? leakDetector.track(this) : null; - this.mode = mode; - this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE; - this.protocols = protocols; - this.enableOcsp = enableOcsp; - - if (mode == SSL.SSL_MODE_SERVER) { - rejectRemoteInitiatedRenegotiation = - JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION; - } - this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone(); - final List convertedCiphers; - if (ciphers == null) { - convertedCiphers = null; - } else { - convertedCiphers = new ArrayList(); - for (String c : ciphers) { - if (c == null) { - break; - } - - String converted = CipherSuiteConverter.toOpenSsl(c); - if (converted != null) { - c = converted; - } - convertedCiphers.add(c); - } - } - - unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites( - convertedCiphers, DEFAULT_CIPHERS, OpenSsl.availableOpenSslCipherSuites())); - - this.apn = checkNotNull(apn, "apn"); - - // Create a new SSL_CTX and configure it. - boolean success = false; - try { - try { - ctx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, mode); - } catch (Exception e) { - throw new SSLException("failed to create an SSL_CTX", e); - } - - SSLContext.setOptions(ctx, SSLContext.getOptions(ctx) | - SSL.SSL_OP_NO_SSLv2 | - SSL.SSL_OP_NO_SSLv3 | - SSL.SSL_OP_CIPHER_SERVER_PREFERENCE | - - // We do not support compression at the moment so we should explicitly disable it. - SSL.SSL_OP_NO_COMPRESSION | - - // Disable ticket support by default to be more inline with SSLEngineImpl of the JDK. - // This also let SSLSession.getId() work the same way for the JDK implementation and the - // OpenSSLEngine. If tickets are supported SSLSession.getId() will only return an ID on the - // server-side if it could make use of tickets. - SSL.SSL_OP_NO_TICKET); - - // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between - // calling OpenSSLEngine.wrap(...). - // See https://github.com/netty/netty-tcnative/issues/100 - SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - - if (DH_KEY_LENGTH != null) { - SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH); - } - - /* List the ciphers that are permitted to negotiate. */ - try { - SSLContext.setCipherSuite(ctx, CipherSuiteConverter.toOpenSsl(unmodifiableCiphers)); - } catch (SSLException e) { - throw e; - } catch (Exception e) { - throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e); - } - - List nextProtoList = apn.protocols(); - /* Set next protocols for next protocol negotiation extension, if specified */ - if (!nextProtoList.isEmpty()) { - String[] appProtocols = nextProtoList.toArray(new String[nextProtoList.size()]); - int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior()); - - switch (apn.protocol()) { - case NPN: - SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior); - break; - case ALPN: - SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior); - break; - case NPN_AND_ALPN: - SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior); - SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior); - break; - default: - throw new Error(); - } - } - - /* Set session cache size, if specified */ - if (sessionCacheSize > 0) { - this.sessionCacheSize = sessionCacheSize; - SSLContext.setSessionCacheSize(ctx, sessionCacheSize); - } else { - // Get the default session cache size using SSLContext.setSessionCacheSize() - this.sessionCacheSize = sessionCacheSize = SSLContext.setSessionCacheSize(ctx, 20480); - // Revert the session cache size to the default value. - SSLContext.setSessionCacheSize(ctx, sessionCacheSize); - } - - /* Set session timeout, if specified */ - if (sessionTimeout > 0) { - this.sessionTimeout = sessionTimeout; - SSLContext.setSessionCacheTimeout(ctx, sessionTimeout); - } else { - // Get the default session timeout using SSLContext.setSessionCacheTimeout() - this.sessionTimeout = sessionTimeout = SSLContext.setSessionCacheTimeout(ctx, 300); - // Revert the session timeout to the default value. - SSLContext.setSessionCacheTimeout(ctx, sessionTimeout); - } - - if (enableOcsp) { - SSLContext.enableOcsp(ctx, isClient()); - } - success = true; - } finally { - if (!success) { - release(); - } - } - } - - private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) { - switch (behavior) { - case NO_ADVERTISE: - return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE; - case CHOOSE_MY_LAST_PROTOCOL: - return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL; - default: - throw new Error(); - } - } - - @Override - public final List cipherSuites() { - return unmodifiableCiphers; - } - - @Override - public final long sessionCacheSize() { - return sessionCacheSize; - } - - @Override - public final long sessionTimeout() { - return sessionTimeout; - } - - @Override - public ApplicationProtocolNegotiator applicationProtocolNegotiator() { - return apn; - } - - @Override - public final boolean isClient() { - return mode == SSL.SSL_MODE_CLIENT; - } - - @Override - public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) { - return newEngine0(alloc, peerHost, peerPort); - } - - SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) { - return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, true); - } - - abstract OpenSslKeyMaterialManager keyMaterialManager(); - - /** - * Returns a new server-side {@link SSLEngine} with the current configuration. - */ - @Override - public final SSLEngine newEngine(ByteBufAllocator alloc) { - return newEngine(alloc, null, -1); - } - - /** - * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}. - * Be aware that it is freed as soon as the {@link #finalize()} method is called. - * At this point {@code 0} will be returned. - * - * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it! - */ - @Deprecated - public final long context() { - Lock readerLock = ctxLock.readLock(); - readerLock.lock(); - try { - return ctx; - } finally { - readerLock.unlock(); - } - } - - /** - * Returns the stats of this context. - * - * @deprecated use {@link #sessionContext#stats()} - */ - @Deprecated - public final OpenSslSessionStats stats() { - return sessionContext().stats(); - } - - /** - * Specify if remote initiated renegotiation is supported or not. If not supported and the remote side tries - * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during decoding. - */ - public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) { - this.rejectRemoteInitiatedRenegotiation = rejectRemoteInitiatedRenegotiation; - } - - /** - * Returns if remote initiated renegotiation is supported or not. - */ - public boolean getRejectRemoteInitiatedRenegotiation() { - return rejectRemoteInitiatedRenegotiation; - } - - /** - * Set the size of the buffer used by the BIO for non-application based writes - * (e.g. handshake, renegotiation, etc...). - */ - public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) { - this.bioNonApplicationBufferSize = - checkPositiveOrZero(bioNonApplicationBufferSize, "bioNonApplicationBufferSize"); - } - - /** - * Returns the size of the buffer used by the BIO for non-application based writes - */ - public int getBioNonApplicationBufferSize() { - return bioNonApplicationBufferSize; - } - - /** - * Sets the SSL session ticket keys of this context. - * - * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])} - */ - @Deprecated - public final void setTicketKeys(byte[] keys) { - sessionContext().setTicketKeys(keys); - } - - @Override - public abstract OpenSslSessionContext sessionContext(); - - /** - * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}. - * Be aware that it is freed as soon as the {@link #release()} method is called. - * At this point {@code 0} will be returned. - * - * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it! - */ - @Deprecated - public final long sslCtxPointer() { - Lock readerLock = ctxLock.readLock(); - readerLock.lock(); - try { - return ctx; - } finally { - readerLock.unlock(); - } - } - - // IMPORTANT: This method must only be called from either the constructor or the finalizer as a user MUST never - // get access to an OpenSslSessionContext after this method was called to prevent the user from - // producing a segfault. - private void destroy() { - Lock writerLock = ctxLock.writeLock(); - writerLock.lock(); - try { - if (ctx != 0) { - if (enableOcsp) { - SSLContext.disableOcsp(ctx); - } - - SSLContext.free(ctx); - ctx = 0; - } - } finally { - writerLock.unlock(); - } - } - - protected static X509Certificate[] certificates(byte[][] chain) { - X509Certificate[] peerCerts = new X509Certificate[chain.length]; - for (int i = 0; i < peerCerts.length; i++) { - peerCerts[i] = new OpenSslX509Certificate(chain[i]); - } - return peerCerts; - } - - protected static X509TrustManager chooseTrustManager(TrustManager[] managers) { - for (TrustManager m : managers) { - if (m instanceof X509TrustManager) { - return (X509TrustManager) m; - } - } - throw new IllegalStateException("no X509TrustManager found"); - } - - protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) { - for (KeyManager km : kms) { - if (km instanceof X509KeyManager) { - return (X509KeyManager) km; - } - } - throw new IllegalStateException("no X509KeyManager found"); - } - - /** - * Translate a {@link ApplicationProtocolConfig} object to a - * {@link OpenSslApplicationProtocolNegotiator} object. - * - * @param config The configuration which defines the translation - * @return The results of the translation - */ - static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) { - if (config == null) { - return NONE_PROTOCOL_NEGOTIATOR; - } - - switch (config.protocol()) { - case NONE: - return NONE_PROTOCOL_NEGOTIATOR; - case ALPN: - case NPN: - case NPN_AND_ALPN: - switch (config.selectedListenerFailureBehavior()) { - case CHOOSE_MY_LAST_PROTOCOL: - case ACCEPT: - switch (config.selectorFailureBehavior()) { - case CHOOSE_MY_LAST_PROTOCOL: - case NO_ADVERTISE: - return new OpenSslDefaultApplicationProtocolNegotiator( - config); - default: - throw new UnsupportedOperationException( - new StringBuilder("OpenSSL provider does not support ") - .append(config.selectorFailureBehavior()) - .append(" behavior").toString()); - } - default: - throw new UnsupportedOperationException( - new StringBuilder("OpenSSL provider does not support ") - .append(config.selectedListenerFailureBehavior()) - .append(" behavior").toString()); - } - default: - throw new Error(); - } - } - - static boolean useExtendedTrustManager(X509TrustManager trustManager) { - return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager; - } - - static boolean useExtendedKeyManager(X509KeyManager keyManager) { - return PlatformDependent.javaVersion() >= 7 && keyManager instanceof X509ExtendedKeyManager; - } - - @Override - public final int refCnt() { - return refCnt.refCnt(); - } - - @Override - public final ReferenceCounted retain() { - refCnt.retain(); - return this; - } - - @Override - public final ReferenceCounted retain(int increment) { - refCnt.retain(increment); - return this; - } - - @Override - public final ReferenceCounted touch() { - refCnt.touch(); - return this; - } - - @Override - public final ReferenceCounted touch(Object hint) { - refCnt.touch(hint); - return this; - } - - @Override - public final boolean release() { - return refCnt.release(); - } - - @Override - public final boolean release(int decrement) { - return refCnt.release(decrement); - } - - abstract static class AbstractCertificateVerifier extends CertificateVerifier { - private final OpenSslEngineMap engineMap; - - AbstractCertificateVerifier(OpenSslEngineMap engineMap) { - this.engineMap = engineMap; - } - - @Override - public final int verify(long ssl, byte[][] chain, String auth) { - X509Certificate[] peerCerts = certificates(chain); - final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); - try { - verify(engine, peerCerts, auth); - return CertificateVerifier.X509_V_OK; - } catch (Throwable cause) { - logger.debug("verification of certificate failed", cause); - SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem"); - e.initCause(cause); - engine.handshakeException = e; - - // Try to extract the correct error code that should be used. - if (cause instanceof OpenSslCertificateException) { - // This will never return a negative error code as its validated when constructing the - // OpenSslCertificateException. - return ((OpenSslCertificateException) cause).errorCode(); - } - if (cause instanceof CertificateExpiredException) { - return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED; - } - if (cause instanceof CertificateNotYetValidException) { - return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID; - } - if (PlatformDependent.javaVersion() >= 7) { - if (cause instanceof CertificateRevokedException) { - return CertificateVerifier.X509_V_ERR_CERT_REVOKED; - } - - // The X509TrustManagerImpl uses a Validator which wraps a CertPathValidatorException into - // an CertificateException. So we need to handle the wrapped CertPathValidatorException to be - // able to send the correct alert. - Throwable wrapped = cause.getCause(); - while (wrapped != null) { - if (wrapped instanceof CertPathValidatorException) { - CertPathValidatorException ex = (CertPathValidatorException) wrapped; - CertPathValidatorException.Reason reason = ex.getReason(); - if (reason == CertPathValidatorException.BasicReason.EXPIRED) { - return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED; - } - if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) { - return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID; - } - if (reason == CertPathValidatorException.BasicReason.REVOKED) { - return CertificateVerifier.X509_V_ERR_CERT_REVOKED; - } - } - wrapped = wrapped.getCause(); - } - } - - // Could not detect a specific error code to use, so fallback to a default code. - return CertificateVerifier.X509_V_ERR_UNSPECIFIED; - } - } - - abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, - String auth) throws Exception; - } - - private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap { - private final Map engines = PlatformDependent.newConcurrentHashMap(); - - @Override - public ReferenceCountedOpenSslEngine remove(long ssl) { - return engines.remove(ssl); - } - - @Override - public void add(ReferenceCountedOpenSslEngine engine) { - engines.put(engine.sslPointer(), engine); - } - - @Override - public ReferenceCountedOpenSslEngine get(long ssl) { - return engines.get(ssl); - } - } - - static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword) - throws SSLException { - /* Load the certificate file and private key. */ - long keyBio = 0; - long keyCertChainBio = 0; - long keyCertChainBio2 = 0; - PemEncoded encoded = null; - try { - // Only encode one time - encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain); - keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); - keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain()); - - if (key != null) { - keyBio = toBIO(key); - } - - SSLContext.setCertificateBio( - ctx, keyCertChainBio, keyBio, - keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword); - // We may have more then one cert in the chain so add all of them now. - SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true); - } catch (SSLException e) { - throw e; - } catch (Exception e) { - throw new SSLException("failed to set certificate and key", e); - } finally { - freeBio(keyBio); - freeBio(keyCertChainBio); - freeBio(keyCertChainBio2); - if (encoded != null) { - encoded.release(); - } - } - } - - static void freeBio(long bio) { - if (bio != 0) { - SSL.freeBIO(bio); - } - } - - /** - * Return the pointer to a in-memory BIO - * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}. - */ - static long toBIO(PrivateKey key) throws Exception { - if (key == null) { - return 0; - } - - ByteBufAllocator allocator = ByteBufAllocator.DEFAULT; - PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key); - try { - return toBIO(allocator, pem.retain()); - } finally { - pem.release(); - } - } - - /** - * Return the pointer to a in-memory BIO - * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}. - */ - static long toBIO(X509Certificate... certChain) throws Exception { - if (certChain == null) { - return 0; - } - - if (certChain.length == 0) { - throw new IllegalArgumentException("certChain can't be empty"); - } - - ByteBufAllocator allocator = ByteBufAllocator.DEFAULT; - PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain); - try { - return toBIO(allocator, pem.retain()); - } finally { - pem.release(); - } - } - - static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception { - try { - // We can turn direct buffers straight into BIOs. No need to - // make a yet another copy. - ByteBuf content = pem.content(); - - if (content.isDirect()) { - return newBIO(content.retainedSlice()); - } - - ByteBuf buffer = allocator.directBuffer(content.readableBytes()); - try { - buffer.writeBytes(content, content.readerIndex(), content.readableBytes()); - return newBIO(buffer.retainedSlice()); - } finally { - try { - // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we - // need to zero out the bytes of the copy before we're releasing it. - if (pem.isSensitive()) { - SslUtils.zeroout(buffer); - } - } finally { - buffer.release(); - } - } - } finally { - pem.release(); - } - } - - private static long newBIO(ByteBuf buffer) throws Exception { - try { - long bio = SSL.newMemBIO(); - int readable = buffer.readableBytes(); - if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) { - SSL.freeBIO(bio); - throw new IllegalStateException("Could not write data to memory BIO"); - } - return bio; - } finally { - buffer.release(); - } - } -} diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java deleted file mode 100644 index 27460c7..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java +++ /dev/null @@ -1,2037 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.internal.tcnative.Buffer; -import io.netty.internal.tcnative.SSL; -import io.netty.util.AbstractReferenceCounted; -import io.netty.util.ReferenceCounted; -import io.netty.util.ResourceLeakDetector; -import io.netty.util.ResourceLeakDetectorFactory; -import io.netty.util.ResourceLeakTracker; -import io.netty.util.internal.EmptyArrays; -import io.netty.util.internal.PlatformDependent; -import io.netty.util.internal.StringUtil; -import io.netty.util.internal.ThrowableUtil; -import io.netty.util.internal.UnstableApi; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; - -import java.nio.ByteBuffer; -import java.nio.ReadOnlyBufferException; -import java.security.Principal; -import java.security.cert.Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; - -import java.util.concurrent.locks.Lock; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLParameters; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSessionBindingEvent; -import javax.net.ssl.SSLSessionBindingListener; -import javax.net.ssl.SSLSessionContext; -import javax.security.cert.X509Certificate; - -import static io.netty.handler.ssl.OpenSsl.memoryAddress; -import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH; -import static io.netty.util.internal.EmptyArrays.EMPTY_CERTIFICATES; -import static io.netty.util.internal.EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES; -import static io.netty.util.internal.ObjectUtil.checkNotNull; -import static java.lang.Math.min; -import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED; -import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP; -import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP; -import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; -import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW; -import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW; -import static javax.net.ssl.SSLEngineResult.Status.CLOSED; -import static javax.net.ssl.SSLEngineResult.Status.OK; - -/** - * Implements a {@link SSLEngine} using - * OpenSSL BIO abstractions. - *

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

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

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

Instances of this class must not be released before any {@link ReferenceCountedOpenSslEngine} - * which depends upon the instance of this class is released. Otherwise if any method of - * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash. - */ -public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext { - private static final InternalLogger logger = - InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class); - private static final byte[] ID = {'n', 'e', 't', 't', 'y'}; - private final OpenSslServerSessionContext sessionContext; - private final OpenSslKeyMaterialManager keyMaterialManager; - - ReferenceCountedOpenSslServerContext( - X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, - X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, - Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, - long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, - boolean enableOcsp) throws SSLException { - this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, - cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, - enableOcsp); - } - - private ReferenceCountedOpenSslServerContext( - X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, - X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, - Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, - long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, - boolean enableOcsp) throws SSLException { - super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, - clientAuth, protocols, startTls, enableOcsp, true); - // Create a new SSL_CTX and configure it. - boolean success = false; - try { - ServerContext context = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, - keyCertChain, key, keyPassword, keyManagerFactory); - sessionContext = context.sessionContext; - keyMaterialManager = context.keyMaterialManager; - success = true; - } finally { - if (!success) { - release(); - } - } - } - - @Override - public OpenSslServerSessionContext sessionContext() { - return sessionContext; - } - - @Override - OpenSslKeyMaterialManager keyMaterialManager() { - return keyMaterialManager; - } - - static final class ServerContext { - OpenSslServerSessionContext sessionContext; - OpenSslKeyMaterialManager keyMaterialManager; - } - - static ServerContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx, OpenSslEngineMap engineMap, - X509Certificate[] trustCertCollection, - TrustManagerFactory trustManagerFactory, - X509Certificate[] keyCertChain, PrivateKey key, - String keyPassword, KeyManagerFactory keyManagerFactory) - throws SSLException { - ServerContext result = new ServerContext(); - try { - SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); - if (!OpenSsl.useKeyManagerFactory()) { - if (keyManagerFactory != null) { - throw new IllegalArgumentException( - "KeyManagerFactory not supported"); - } - checkNotNull(keyCertChain, "keyCertChain"); - - setKeyMaterial(ctx, keyCertChain, key, keyPassword); - } else { - // javadocs state that keyManagerFactory has precedent over keyCertChain, and we must have a - // keyManagerFactory for the server so build one if it is not specified. - if (keyManagerFactory == null) { - keyManagerFactory = buildKeyManagerFactory( - keyCertChain, key, keyPassword, keyManagerFactory); - } - X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers()); - result.keyMaterialManager = useExtendedKeyManager(keyManager) ? - new OpenSslExtendedKeyMaterialManager( - (X509ExtendedKeyManager) keyManager, keyPassword) : - new OpenSslKeyMaterialManager(keyManager, keyPassword); - } - } catch (Exception e) { - throw new SSLException("failed to set certificate and key", e); - } - try { - if (trustCertCollection != null) { - trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory); - } else if (trustManagerFactory == null) { - // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works - trustManagerFactory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init((KeyStore) null); - } - - final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); - - // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as - // otherwise the context can never be collected. This is because the JNI code holds - // a global reference to the callbacks. - // - // See https://github.com/netty/netty/issues/5372 - - // Use this to prevent an error when running on java < 7 - if (useExtendedTrustManager(manager)) { - SSLContext.setCertVerifyCallback(ctx, - new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager)); - } else { - SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager)); - } - - X509Certificate[] issuers = manager.getAcceptedIssuers(); - if (issuers != null && issuers.length > 0) { - long bio = 0; - try { - bio = toBIO(issuers); - if (!SSLContext.setCACertificateBio(ctx, bio)) { - throw new SSLException("unable to setup accepted issuers for trustmanager " + manager); - } - } finally { - freeBio(bio); - } - } - - if (PlatformDependent.javaVersion() >= 8) { - // Only do on Java8+ as SNIMatcher is not supported in earlier releases. - // IMPORTANT: The callbacks set for hostname matching must be static to prevent memory leak as - // otherwise the context can never be collected. This is because the JNI code holds - // a global reference to the matcher. - SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engineMap)); - } - } catch (SSLException e) { - throw e; - } catch (Exception e) { - throw new SSLException("unable to setup trustmanager", e); - } - - result.sessionContext = new OpenSslServerSessionContext(thiz); - result.sessionContext.setSessionIdContext(ID); - return result; - } - - private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier { - private final X509TrustManager manager; - - TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) { - super(engineMap); - this.manager = manager; - } - - @Override - void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) - throws Exception { - manager.checkClientTrusted(peerCerts, auth); - } - } - - private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier { - private final X509ExtendedTrustManager manager; - - ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) { - super(engineMap); - this.manager = manager; - } - - @Override - void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth) - throws Exception { - manager.checkClientTrusted(peerCerts, auth, engine); - } - } - - private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher { - private final OpenSslEngineMap engineMap; - - OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) { - this.engineMap = engineMap; - } - - @Override - public boolean match(long ssl, String hostname) { - ReferenceCountedOpenSslEngine engine = engineMap.get(ssl); - if (engine != null) { - return engine.checkSniHostnameMatch(hostname); - } - logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl); - return false; - } - } -} diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java index 4998d0d..8dbc3cf 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java @@ -115,11 +115,7 @@ public abstract class SslContext { } private static SslProvider defaultProvider() { - if (OpenSsl.isAvailable()) { - return SslProvider.OPENSSL; - } else { - return SslProvider.JDK; - } + return SslProvider.JDK; } /** @@ -416,18 +412,6 @@ public abstract class SslContext { trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls); - case OPENSSL: - verifyNullSslContextProvider(provider, sslContextProvider); - return new OpenSslServerContext( - trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, - keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, - clientAuth, protocols, startTls, enableOcsp); - case OPENSSL_REFCNT: - verifyNullSslContextProvider(provider, sslContextProvider); - return new ReferenceCountedOpenSslServerContext( - trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, - keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, - clientAuth, protocols, startTls, enableOcsp); default: throw new Error(provider.toString()); } @@ -770,18 +754,6 @@ public abstract class SslContext { return new JdkSslClientContext(sslContextProvider, trustCert, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout); - case OPENSSL: - verifyNullSslContextProvider(provider, sslContextProvider); - return new OpenSslClientContext( - trustCert, trustManagerFactory, keyCertChain, key, keyPassword, - keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, - enableOcsp); - case OPENSSL_REFCNT: - verifyNullSslContextProvider(provider, sslContextProvider); - return new ReferenceCountedOpenSslClientContext( - trustCert, trustManagerFactory, keyCertChain, key, keyPassword, - keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, - enableOcsp); default: throw new Error(provider.toString()); } diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java index c054964..05c451a 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java @@ -159,6 +159,12 @@ import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength; * #832 in our issue tracker. */ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler { + private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14 + private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024; + private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024; + // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256) + static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256; + static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = MAX_ENCRYPTED_PACKET_LENGTH - MAX_PLAINTEXT_LENGTH; private static final InternalLogger logger = InternalLoggerFactory.getInstance(SslHandler.class); @@ -181,40 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH new ClosedChannelException(), SslHandler.class, "channelInactive(...)"); private enum SslEngineType { - TCNATIVE(true, COMPOSITE_CUMULATOR) { - @Override - SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) - throws SSLException { - int nioBufferCount = in.nioBufferCount(); - int writerIndex = out.writerIndex(); - final SSLEngineResult result; - if (nioBufferCount > 1) { - /* - * If {@link OpenSslEngine} is in use, - * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method - * that accepts multiple {@link ByteBuffer}s without additional memory copies. - */ - ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine; - try { - handler.singleBuffer[0] = toByteBuffer(out, writerIndex, - out.writableBytes()); - result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer); - } finally { - handler.singleBuffer[0] = null; - } - } else { - result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len), - toByteBuffer(out, writerIndex, out.writableBytes())); - } - out.writerIndex(writerIndex + result.bytesProduced()); - return result; - } - - @Override - int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) { - return ReferenceCountedOpenSslEngine.calculateOutNetBufSize(pendingBytes, numComponents); - } - }, CONSCRYPT(true, COMPOSITE_CUMULATOR) { @Override SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) @@ -265,9 +237,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH }; static SslEngineType forEngine(SSLEngine engine) { - if (engine instanceof ReferenceCountedOpenSslEngine) { - return TCNATIVE; - } if (engine instanceof ConscryptAlpnSslEngine) { return CONSCRYPT; } @@ -1034,7 +1003,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH boolean nonSslRecord = false; - while (totalLength < ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { + while (totalLength < MAX_ENCRYPTED_PACKET_LENGTH) { final int readableBytes = endOffset - offset; if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) { break; @@ -1055,7 +1024,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH } int newTotalLength = totalLength + packetLength; - if (newTotalLength > ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { + if (newTotalLength > MAX_ENCRYPTED_PACKET_LENGTH) { // Don't read too much. break; } diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java deleted file mode 100644 index aff0949..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl.ocsp; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.handler.ssl.ReferenceCountedOpenSslContext; -import io.netty.handler.ssl.ReferenceCountedOpenSslEngine; -import io.netty.handler.ssl.SslHandshakeCompletionEvent; -import io.netty.util.internal.ObjectUtil; -import io.netty.util.internal.ThrowableUtil; -import io.netty.util.internal.UnstableApi; - -import javax.net.ssl.SSLHandshakeException; - -/** - * A handler for SSL clients to handle and act upon stapled OCSP responses. - * - * @see ReferenceCountedOpenSslContext#enableOcsp() - * @see ReferenceCountedOpenSslEngine#getOcspResponse() - */ -@UnstableApi -public abstract class OcspClientHandler extends ChannelInboundHandlerAdapter { - - private static final SSLHandshakeException OCSP_VERIFICATION_EXCEPTION = ThrowableUtil.unknownStackTrace( - new SSLHandshakeException("Bad OCSP response"), OcspClientHandler.class, "verify(...)"); - - private final ReferenceCountedOpenSslEngine engine; - - protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) { - this.engine = ObjectUtil.checkNotNull(engine, "engine"); - } - - /** - * @see ReferenceCountedOpenSslEngine#getOcspResponse() - */ - protected abstract boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception; - - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - if (evt instanceof SslHandshakeCompletionEvent) { - ctx.pipeline().remove(this); - - SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt; - if (event.isSuccess() && !verify(ctx, engine)) { - throw OCSP_VERIFICATION_EXCEPTION; - } - } - - ctx.fireUserEventTriggered(evt); - } -} diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java deleted file mode 100644 index 2883ff4..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -/** - * OCSP stapling, - * formally known as the TLS Certificate Status Request extension, is an - * alternative approach to the Online Certificate Status Protocol (OCSP) - * for checking the revocation status of X.509 digital certificates. - */ -package io.netty.handler.ssl.ocsp; diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java deleted file mode 100644 index d696d6b..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory; -import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED; -import static org.junit.Assume.assumeTrue; - -@RunWith(Parameterized.class) -public class JdkOpenSslEngineInteroptTest extends SSLEngineTest { - - @Parameterized.Parameters(name = "{index}: bufferType = {0}") - public static Collection data() { - List params = new ArrayList(); - for (BufferType type: BufferType.values()) { - params.add(type); - } - return params; - } - - public JdkOpenSslEngineInteroptTest(BufferType type) { - super(type); - } - - @BeforeClass - public static void checkOpenSsl() { - assumeTrue(OpenSsl.isAvailable()); - } - - @Override - protected SslProvider sslClientProvider() { - return SslProvider.JDK; - } - - @Override - protected SslProvider sslServerProvider() { - return SslProvider.OPENSSL; - } - - @Override - @Test - public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth(); - } - - @Override - @Test - public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth(); - } - - @Override - @Test - public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth(); - } - - @Override - @Test - public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth(); - } - - @Override - @Test - public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth(); - } - - @Override - protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) { - ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) handler.engine(); - engine.setVerify(SSL_CVERIFY_IGNORED, 1); - } - - @Override - protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) { - // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. - return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause); - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java deleted file mode 100644 index 229e853..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import io.netty.internal.tcnative.CertificateVerifier; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.lang.reflect.Field; - -public class OpenSslCertificateExceptionTest { - - @BeforeClass - public static void assumeOpenSsl() { - Assume.assumeTrue(OpenSsl.isAvailable()); - } - - @Test - public void testValidErrorCode() throws Exception { - Field[] fields = CertificateVerifier.class.getFields(); - for (Field field : fields) { - if (field.isAccessible()) { - int errorCode = field.getInt(null); - OpenSslCertificateException exception = new OpenSslCertificateException(errorCode); - Assert.assertEquals(errorCode, exception.errorCode()); - } - } - } - - @Test(expected = IllegalArgumentException.class) - public void testNonValidErrorCode() { - new OpenSslCertificateException(Integer.MIN_VALUE); - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java deleted file mode 100644 index 6011cf7..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import org.junit.BeforeClass; - -import javax.net.ssl.SSLException; -import java.io.File; - -import static org.junit.Assume.assumeTrue; - -public class OpenSslClientContextTest extends SslContextTest { - - @BeforeClass - public static void checkOpenSsl() { - assumeTrue(OpenSsl.isAvailable()); - } - - @Override - protected SslContext newServerContext(File crtFile, File keyFile, String pass) throws SSLException { - return new OpenSslClientContext(crtFile, InsecureTrustManagerFactory.INSTANCE, crtFile, keyFile, pass, - null, null, IdentityCipherSuiteFilter.INSTANCE, ApplicationProtocolConfig.DISABLED, 0, 0); - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java deleted file mode 100644 index 5939b66..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java +++ /dev/null @@ -1,661 +0,0 @@ -/* - * Copyright 2015 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; -import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior; -import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import io.netty.handler.ssl.util.SelfSignedCertificate; -import io.netty.util.internal.PlatformDependent; -import org.junit.Assume; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.nio.ByteBuffer; -import java.security.AlgorithmConstraints; -import java.security.AlgorithmParameters; -import java.security.CryptoPrimitive; -import java.security.Key; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLParameters; - -import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory; -import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH; -import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH; -import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_PLAINTEXT_LENGTH; -import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED; -import static java.lang.Integer.MAX_VALUE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; - -@RunWith(Parameterized.class) -public class OpenSslEngineTest extends SSLEngineTest { - private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2"; - private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1"; - - @Parameterized.Parameters(name = "{index}: bufferType = {0}") - public static Collection data() { - List params = new ArrayList(); - for (BufferType type: BufferType.values()) { - params.add(type); - } - return params; - } - - public OpenSslEngineTest(BufferType type) { - super(type); - } - - @BeforeClass - public static void checkOpenSsl() { - assumeTrue(OpenSsl.isAvailable()); - } - - @Override - @Test - public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth(); - } - - @Override - @Test - public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth(); - } - - @Override - @Test - public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth(); - } - - @Override - @Test - public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth(); - } - - @Override - @Test - public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth(); - } - - @Override - @Test - public void testClientHostnameValidationSuccess() throws InterruptedException, SSLException { - assumeTrue(OpenSsl.supportsHostnameValidation()); - super.testClientHostnameValidationSuccess(); - } - - @Override - @Test - public void testClientHostnameValidationFail() throws InterruptedException, SSLException { - assumeTrue(OpenSsl.supportsHostnameValidation()); - super.testClientHostnameValidationFail(); - } - - @Test - public void testNpn() throws Exception { - ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.NPN, - PREFERRED_APPLICATION_LEVEL_PROTOCOL); - setupHandlers(apn); - runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); - } - - @Test - public void testAlpn() throws Exception { - assumeTrue(OpenSsl.isAlpnSupported()); - ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.ALPN, - PREFERRED_APPLICATION_LEVEL_PROTOCOL); - setupHandlers(apn); - runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); - } - - @Test - public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception { - assumeTrue(OpenSsl.isAlpnSupported()); - ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN, - FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL); - ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN, - PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL); - setupHandlers(serverApn, clientApn); - assertNull(serverException); - runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL); - } - - @Test - public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception { - testEnablingAnAlreadyDisabledSslProtocol(new String[]{PROTOCOL_SSL_V2_HELLO}, - new String[]{PROTOCOL_SSL_V2_HELLO, PROTOCOL_TLS_V1_2}); - } - @Test - public void testWrapBuffersNoWritePendingError() throws Exception { - clientSslCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .sslProvider(sslClientProvider()) - .build(); - SelfSignedCertificate ssc = new SelfSignedCertificate(); - serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslServerProvider()) - .build(); - SSLEngine clientEngine = null; - SSLEngine serverEngine = null; - try { - clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - handshake(clientEngine, serverEngine); - - ByteBuffer src = allocateBuffer(1024 * 10); - byte[] data = new byte[src.capacity()]; - PlatformDependent.threadLocalRandom().nextBytes(data); - src.put(data).flip(); - ByteBuffer dst = allocateBuffer(1); - // Try to wrap multiple times so we are more likely to hit the issue. - for (int i = 0; i < 100; i++) { - src.position(0); - dst.position(0); - assertSame(SSLEngineResult.Status.BUFFER_OVERFLOW, clientEngine.wrap(src, dst).getStatus()); - } - } finally { - cleanupClientSslEngine(clientEngine); - cleanupServerSslEngine(serverEngine); - } - } - - @Test - public void testOnlySmallBufferNeededForWrap() throws Exception { - clientSslCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .sslProvider(sslClientProvider()) - .build(); - SelfSignedCertificate ssc = new SelfSignedCertificate(); - serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslServerProvider()) - .build(); - SSLEngine clientEngine = null; - SSLEngine serverEngine = null; - try { - clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - handshake(clientEngine, serverEngine); - - // Allocate a buffer which is small enough and set the limit to the capacity to mark its whole content - // as readable. - int srcLen = 1024; - ByteBuffer src = allocateBuffer(srcLen); - - ByteBuffer dstTooSmall = allocateBuffer( - src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH - 1); - ByteBuffer dst = allocateBuffer( - src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH); - - // Check that we fail to wrap if the dst buffers capacity is not at least - // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH - SSLEngineResult result = clientEngine.wrap(src, dstTooSmall); - assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); - assertEquals(0, result.bytesConsumed()); - assertEquals(0, result.bytesProduced()); - assertEquals(src.remaining(), src.capacity()); - assertEquals(dst.remaining(), dst.capacity()); - - // Check that we can wrap with a dst buffer that has the capacity of - // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH - result = clientEngine.wrap(src, dst); - assertEquals(SSLEngineResult.Status.OK, result.getStatus()); - assertEquals(srcLen, result.bytesConsumed()); - assertEquals(0, src.remaining()); - assertTrue(result.bytesProduced() > srcLen); - assertEquals(src.capacity() - result.bytesConsumed(), src.remaining()); - assertEquals(dst.capacity() - result.bytesProduced(), dst.remaining()); - } finally { - cleanupClientSslEngine(clientEngine); - cleanupServerSslEngine(serverEngine); - } - } - - @Test - public void testNeededDstCapacityIsCorrectlyCalculated() throws Exception { - clientSslCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .sslProvider(sslClientProvider()) - .build(); - SelfSignedCertificate ssc = new SelfSignedCertificate(); - serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslServerProvider()) - .build(); - SSLEngine clientEngine = null; - SSLEngine serverEngine = null; - try { - clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - handshake(clientEngine, serverEngine); - - ByteBuffer src = allocateBuffer(1024); - ByteBuffer src2 = src.duplicate(); - - ByteBuffer dst = allocateBuffer(src.capacity() - + MAX_TLS_RECORD_OVERHEAD_LENGTH); - - SSLEngineResult result = clientEngine.wrap(new ByteBuffer[] { src, src2 }, dst); - assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); - assertEquals(0, src.position()); - assertEquals(0, src2.position()); - assertEquals(0, dst.position()); - assertEquals(0, result.bytesConsumed()); - assertEquals(0, result.bytesProduced()); - } finally { - cleanupClientSslEngine(clientEngine); - cleanupServerSslEngine(serverEngine); - } - } - - @Test - public void testSrcsLenOverFlowCorrectlyHandled() throws Exception { - clientSslCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .sslProvider(sslClientProvider()) - .build(); - SelfSignedCertificate ssc = new SelfSignedCertificate(); - serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslServerProvider()) - .build(); - SSLEngine clientEngine = null; - SSLEngine serverEngine = null; - try { - clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - handshake(clientEngine, serverEngine); - - ByteBuffer src = allocateBuffer(1024); - List srcList = new ArrayList(); - long srcsLen = 0; - long maxLen = ((long) MAX_VALUE) * 2; - - while (srcsLen < maxLen) { - ByteBuffer dup = src.duplicate(); - srcList.add(dup); - srcsLen += dup.capacity(); - } - - ByteBuffer[] srcs = srcList.toArray(new ByteBuffer[srcList.size()]); - - ByteBuffer dst = allocateBuffer(MAX_ENCRYPTED_PACKET_LENGTH - 1); - - SSLEngineResult result = clientEngine.wrap(srcs, dst); - assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); - - for (ByteBuffer buffer : srcs) { - assertEquals(0, buffer.position()); - } - assertEquals(0, dst.position()); - assertEquals(0, result.bytesConsumed()); - assertEquals(0, result.bytesProduced()); - } finally { - cleanupClientSslEngine(clientEngine); - cleanupServerSslEngine(serverEngine); - } - } - - @Test - public void testCalculateOutNetBufSizeOverflow() { - assertEquals(MAX_ENCRYPTED_PACKET_LENGTH, - ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_VALUE, 1)); - } - - @Test - public void testCalculateOutNetBufSize0() { - assertEquals(MAX_TLS_RECORD_OVERHEAD_LENGTH, - ReferenceCountedOpenSslEngine.calculateOutNetBufSize(0, 1)); - } - - @Test - public void testCalculateOutNetBufSizeMaxEncryptedPacketLength() { - assertEquals(MAX_ENCRYPTED_PACKET_LENGTH, - ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_ENCRYPTED_PACKET_LENGTH + 1, 2)); - } - - @Override - protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) { - ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) handler.engine(); - engine.setVerify(SSL_CVERIFY_IGNORED, 1); - } - - @Test - public void testWrapWithDifferentSizesTLSv1() throws Exception { - clientSslCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .sslProvider(sslClientProvider()) - .build(); - SelfSignedCertificate ssc = new SelfSignedCertificate(); - serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslServerProvider()) - .build(); - - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-MD5"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "EDH-RSA-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-RC4-MD5"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "IDEA-CBC-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-RC4-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-RC4-SHA"); - } - - @Test - public void testWrapWithDifferentSizesTLSv1_1() throws Exception { - clientSslCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .sslProvider(sslClientProvider()) - .build(); - SelfSignedCertificate ssc = new SelfSignedCertificate(); - serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslServerProvider()) - .build(); - - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "IDEA-CBC-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-RC4-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-RC4-MD5"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "RC4-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "EDH-RSA-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DES-CBC3-SHA"); - } - - @Test - public void testWrapWithDifferentSizesTLSv1_2() throws Exception { - clientSslCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .sslProvider(sslClientProvider()) - .build(); - SelfSignedCertificate ssc = new SelfSignedCertificate(); - serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslServerProvider()) - .build(); - - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-GCM-SHA384"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-GCM-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-GCM-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-SHA384"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-GCM-SHA384"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-GCM-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-MD5"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "EDH-RSA-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-RC4-MD5"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "IDEA-CBC-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-GCM-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-RC4-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-GCM-SHA384"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-GCM-SHA384"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-SHA256"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-RC4-SHA"); - } - - @Test - public void testWrapWithDifferentSizesSSLv3() throws Exception { - clientSslCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .sslProvider(sslClientProvider()) - .build(); - SelfSignedCertificate ssc = new SelfSignedCertificate(); - serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslServerProvider()) - .build(); - - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-MD5"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "EDH-RSA-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-RC4-MD5"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "IDEA-CBC-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-AES128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-RC4-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-SEED-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-AES256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ECDHE-RSA-DES-CBC3-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-CAMELLIA256-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-CAMELLIA128-SHA"); - testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ECDHE-RSA-RC4-SHA"); - } - - private void testWrapWithDifferentSizes(String protocol, String cipher) throws Exception { - assumeTrue(OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocol)); - if (!OpenSsl.isCipherSuiteAvailable(cipher)) { - return; - } - - SSLEngine clientEngine = null; - SSLEngine serverEngine = null; - try { - clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - clientEngine.setEnabledCipherSuites(new String[] { cipher }); - clientEngine.setEnabledProtocols(new String[] { protocol }); - serverEngine.setEnabledCipherSuites(new String[] { cipher }); - serverEngine.setEnabledProtocols(new String[] { protocol }); - - try { - handshake(clientEngine, serverEngine); - } catch (SSLException e) { - if (e.getMessage().contains("unsupported protocol")) { - Assume.assumeNoException(protocol + " not supported with cipher " + cipher, e); - } - throw e; - } - - int srcLen = 64; - do { - testWrapDstBigEnough(clientEngine, srcLen); - srcLen += 64; - } while (srcLen < MAX_PLAINTEXT_LENGTH); - - testWrapDstBigEnough(clientEngine, MAX_PLAINTEXT_LENGTH); - } finally { - cleanupClientSslEngine(clientEngine); - cleanupServerSslEngine(serverEngine); - } - } - - private void testWrapDstBigEnough(SSLEngine engine, int srcLen) throws SSLException { - ByteBuffer src = allocateBuffer(srcLen); - ByteBuffer dst = allocateBuffer(srcLen + MAX_TLS_RECORD_OVERHEAD_LENGTH); - - SSLEngineResult result = engine.wrap(src, dst); - assertEquals(SSLEngineResult.Status.OK, result.getStatus()); - int consumed = result.bytesConsumed(); - int produced = result.bytesProduced(); - assertEquals(srcLen, consumed); - assertTrue(produced > consumed); - - dst.flip(); - assertEquals(produced, dst.remaining()); - assertFalse(src.hasRemaining()); - } - - @Test - public void testSNIMatchersDoesNotThrow() throws Exception { - assumeTrue(PlatformDependent.javaVersion() >= 8); - SelfSignedCertificate ssc = new SelfSignedCertificate(); - serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslServerProvider()) - .build(); - - SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - try { - SSLParameters parameters = new SSLParameters(); - Java8SslTestUtils.setSNIMatcher(parameters); - engine.setSSLParameters(parameters); - } finally { - cleanupServerSslEngine(engine); - ssc.delete(); - } - } - - @Test(expected = IllegalArgumentException.class) - public void testAlgorithmConstraintsThrows() throws Exception { - SelfSignedCertificate ssc = new SelfSignedCertificate(); - serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslServerProvider()) - .build(); - - SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - try { - SSLParameters parameters = new SSLParameters(); - parameters.setAlgorithmConstraints(new AlgorithmConstraints() { - @Override - public boolean permits( - Set primitives, String algorithm, AlgorithmParameters parameters) { - return false; - } - - @Override - public boolean permits(Set primitives, Key key) { - return false; - } - - @Override - public boolean permits( - Set primitives, String algorithm, Key key, AlgorithmParameters parameters) { - return false; - } - }); - engine.setSSLParameters(parameters); - } finally { - cleanupServerSslEngine(engine); - ssc.delete(); - } - } - - @Override - protected SslProvider sslClientProvider() { - return SslProvider.OPENSSL; - } - - @Override - protected SslProvider sslServerProvider() { - return SslProvider.OPENSSL; - } - - private static ApplicationProtocolConfig acceptingNegotiator(Protocol protocol, - String... supportedProtocols) { - return new ApplicationProtocolConfig(protocol, - SelectorFailureBehavior.NO_ADVERTISE, - SelectedListenerFailureBehavior.ACCEPT, - supportedProtocols); - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java deleted file mode 100644 index f63a16f..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - -import javax.net.ssl.SSLException; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory; -import static org.junit.Assume.assumeTrue; - -@RunWith(Parameterized.class) -public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest { - - @Parameterized.Parameters(name = "{index}: bufferType = {0}") - public static Collection data() { - List params = new ArrayList(); - for (BufferType type: BufferType.values()) { - params.add(type); - } - return params; - } - - public OpenSslJdkSslEngineInteroptTest(BufferType type) { - super(type); - } - - @BeforeClass - public static void checkOpenSsl() { - assumeTrue(OpenSsl.isAvailable()); - } - - @Override - protected SslProvider sslClientProvider() { - return SslProvider.OPENSSL; - } - - @Override - protected SslProvider sslServerProvider() { - return SslProvider.JDK; - } - - @Ignore /* Does the JDK support a "max certificate chain length"? */ - @Override - public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { - } - - @Ignore /* Does the JDK support a "max certificate chain length"? */ - @Override - public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { - } - - @Override - @Test - public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth(); - } - - @Override - @Test - public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth(); - } - - @Override - @Test - public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception { - checkShouldUseKeyManagerFactory(); - super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth(); - } - - @Override - @Test - public void testClientHostnameValidationSuccess() throws InterruptedException, SSLException { - assumeTrue(OpenSsl.supportsHostnameValidation()); - super.testClientHostnameValidationSuccess(); - } - - @Override - @Test - public void testClientHostnameValidationFail() throws InterruptedException, SSLException { - assumeTrue(OpenSsl.supportsHostnameValidation()); - super.testClientHostnameValidationFail(); - } - - @Override - protected boolean mySetupMutualAuthServerIsValidServerException(Throwable cause) { - // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. - return super.mySetupMutualAuthServerIsValidServerException(cause) || causedBySSLException(cause); - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java deleted file mode 100644 index 3959e64..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -public class OpenSslRenegotiateSmallBIOTest extends OpenSslRenegotiateTest { - @Override - protected void initSslServerContext(SslContext context) { - ((ReferenceCountedOpenSslContext) context).setBioNonApplicationBufferSize(1); - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java deleted file mode 100644 index 8f3dfee..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import org.junit.BeforeClass; - -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeTrue; - -public class OpenSslRenegotiateTest extends RenegotiateTest { - - @BeforeClass - public static void checkOpenSsl() { - assumeTrue(OpenSsl.isAvailable()); - // BoringSSL does not support renegotiation intentionally. - assumeFalse("BoringSSL".equals(OpenSsl.versionString())); - } - - @Override - protected SslProvider serverSslProvider() { - return SslProvider.OPENSSL; - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java deleted file mode 100644 index f22d045..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package io.netty.handler.ssl; - -import org.junit.Assume; -import org.junit.BeforeClass; - -import javax.net.ssl.SSLException; -import java.io.File; - -import static org.junit.Assume.assumeTrue; - -public class OpenSslServerContextTest extends SslContextTest { - - @BeforeClass - public static void checkOpenSsl() { - assumeTrue(OpenSsl.isAvailable()); - } - - @Override - protected SslContext newServerContext(File crtFile, File keyFile, String pass) throws SSLException { - Assume.assumeTrue(OpenSsl.isAvailable()); - return new OpenSslServerContext(crtFile, keyFile, pass); - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java deleted file mode 100644 index 7882a61..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import static org.junit.Assume.assumeTrue; - -final class OpenSslTestUtils { - private OpenSslTestUtils() { - } - - static void checkShouldUseKeyManagerFactory() { - assumeTrue(OpenSsl.supportsKeyManagerFactory() && OpenSsl.useKeyManagerFactory()); - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java b/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java deleted file mode 100644 index 793f772..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package io.netty.handler.ssl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeTrue; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; - -import org.junit.Test; - -import io.netty.handler.ssl.util.SelfSignedCertificate; -import io.netty.util.ReferenceCountUtil; - -public class PemEncodedTest { - - @Test - public void testPemEncodedOpenSsl() throws Exception { - testPemEncoded(SslProvider.OPENSSL); - } - - @Test - public void testPemEncodedOpenSslRef() throws Exception { - testPemEncoded(SslProvider.OPENSSL_REFCNT); - } - - private static void testPemEncoded(SslProvider provider) throws Exception { - assumeTrue(OpenSsl.isAvailable()); - assumeFalse(OpenSsl.useKeyManagerFactory()); - PemPrivateKey pemKey; - PemX509Certificate pemCert; - SelfSignedCertificate ssc = new SelfSignedCertificate(); - try { - pemKey = PemPrivateKey.valueOf(toByteArray(ssc.privateKey())); - pemCert = PemX509Certificate.valueOf(toByteArray(ssc.certificate())); - } finally { - ssc.delete(); - } - - SslContext context = SslContextBuilder.forServer(pemKey, pemCert) - .sslProvider(provider) - .build(); - assertEquals(1, pemKey.refCnt()); - assertEquals(1, pemCert.refCnt()); - try { - assertTrue(context instanceof ReferenceCountedOpenSslContext); - } finally { - ReferenceCountUtil.release(context); - assertRelease(pemKey); - assertRelease(pemCert); - } - } - - private static void assertRelease(PemEncoded encoded) { - assertTrue(encoded.release()); - } - - private static byte[] toByteArray(File file) throws Exception { - FileInputStream in = new FileInputStream(file); - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) != -1) { - baos.write(buf, 0, len); - } - } finally { - baos.close(); - } - - return baos.toByteArray(); - } finally { - in.close(); - } - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java deleted file mode 100644 index 6d38940..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import io.netty.util.ReferenceCountUtil; - -import javax.net.ssl.SSLEngine; - -public class ReferenceCountedOpenSslEngineTest extends OpenSslEngineTest { - - public ReferenceCountedOpenSslEngineTest(BufferType type) { - super(type); - } - - @Override - protected SslProvider sslClientProvider() { - return SslProvider.OPENSSL_REFCNT; - } - - @Override - protected SslProvider sslServerProvider() { - return SslProvider.OPENSSL_REFCNT; - } - - @Override - protected void cleanupClientSslContext(SslContext ctx) { - ReferenceCountUtil.release(ctx); - } - - @Override - protected void cleanupClientSslEngine(SSLEngine engine) { - ReferenceCountUtil.release(engine); - } - - @Override - protected void cleanupServerSslContext(SslContext ctx) { - ReferenceCountUtil.release(ctx); - } - - @Override - protected void cleanupServerSslEngine(SSLEngine engine) { - ReferenceCountUtil.release(engine); - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java deleted file mode 100644 index 3193d20..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import io.netty.bootstrap.Bootstrap; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.DefaultEventLoopGroup; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.local.LocalAddress; -import io.netty.channel.local.LocalChannel; -import io.netty.channel.local.LocalServerChannel; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import io.netty.handler.ssl.util.SelfSignedCertificate; -import io.netty.util.Mapping; -import io.netty.util.concurrent.Promise; -import io.netty.util.internal.PlatformDependent; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Test; - -import java.nio.channels.ClosedChannelException; - -public class SniClientTest { - - @Test(timeout = 30000) - public void testSniClientJdkSslServerJdkSsl() throws Exception { - testSniClient(SslProvider.JDK, SslProvider.JDK); - } - - @Test(timeout = 30000) - public void testSniClientOpenSslServerOpenSsl() throws Exception { - Assume.assumeTrue(OpenSsl.isAvailable()); - testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL); - } - - @Test(timeout = 30000) - public void testSniClientJdkSslServerOpenSsl() throws Exception { - Assume.assumeTrue(OpenSsl.isAvailable()); - testSniClient(SslProvider.JDK, SslProvider.OPENSSL); - } - - @Test(timeout = 30000) - public void testSniClientOpenSslServerJdkSsl() throws Exception { - Assume.assumeTrue(OpenSsl.isAvailable()); - testSniClient(SslProvider.OPENSSL, SslProvider.JDK); - } - - @Test(timeout = 30000) - public void testSniSNIMatcherMatchesClientJdkSslServerJdkSsl() throws Exception { - Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); - SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, true); - } - - @Test(timeout = 30000, expected = ClosedChannelException.class) - public void testSniSNIMatcherDoesNotMatchClientJdkSslServerJdkSsl() throws Exception { - Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); - SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, false); - } - - @Test(timeout = 30000) - public void testSniSNIMatcherMatchesClientOpenSslServerOpenSsl() throws Exception { - Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); - Assume.assumeTrue(OpenSsl.isAvailable()); - SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL, true); - } - - @Test(timeout = 30000, expected = ClosedChannelException.class) - public void testSniSNIMatcherDoesNotMatchClientOpenSslServerOpenSsl() throws Exception { - Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); - Assume.assumeTrue(OpenSsl.isAvailable()); - SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL, false); - } - - @Test(timeout = 30000) - public void testSniSNIMatcherMatchesClientJdkSslServerOpenSsl() throws Exception { - Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); - Assume.assumeTrue(OpenSsl.isAvailable()); - SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL, true); - } - - @Test(timeout = 30000, expected = ClosedChannelException.class) - public void testSniSNIMatcherDoesNotMatchClientJdkSslServerOpenSsl() throws Exception { - Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); - Assume.assumeTrue(OpenSsl.isAvailable()); - SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL, false); - } - - @Test(timeout = 30000) - public void testSniSNIMatcherMatchesClientOpenSslServerJdkSsl() throws Exception { - Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); - Assume.assumeTrue(OpenSsl.isAvailable()); - SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK, true); - } - - @Test(timeout = 30000, expected = ClosedChannelException.class) - public void testSniSNIMatcherDoesNotMatchClientOpenSslServerJdkSsl() throws Exception { - Assume.assumeTrue(PlatformDependent.javaVersion() >= 8); - Assume.assumeTrue(OpenSsl.isAvailable()); - SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK, false); - } - - private static void testSniClient(SslProvider sslClientProvider, SslProvider sslServerProvider) throws Exception { - final String sniHost = "sni.netty.io"; - LocalAddress address = new LocalAddress("test"); - EventLoopGroup group = new DefaultEventLoopGroup(1); - Channel sc = null; - Channel cc = null; - try { - SelfSignedCertificate cert = new SelfSignedCertificate(); - final SslContext sslServerContext = SslContextBuilder.forServer(cert.key(), cert.cert()) - .sslProvider(sslServerProvider).build(); - - final Promise promise = group.next().newPromise(); - ServerBootstrap sb = new ServerBootstrap(); - sc = sb.group(group).channel(LocalServerChannel.class).childHandler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline().addFirst(new SniHandler(new Mapping() { - @Override - public SslContext map(String input) { - promise.setSuccess(input); - return sslServerContext; - } - })); - } - }).bind(address).syncUninterruptibly().channel(); - - SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE) - .sslProvider(sslClientProvider).build(); - Bootstrap cb = new Bootstrap(); - cc = cb.group(group).channel(LocalChannel.class).handler(new SslHandler( - sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost, -1))) - .connect(address).syncUninterruptibly().channel(); - Assert.assertEquals(sniHost, promise.syncUninterruptibly().getNow()); - } finally { - if (cc != null) { - cc.close().syncUninterruptibly(); - } - if (sc != null) { - sc.close().syncUninterruptibly(); - } - group.shutdownGracefully(); - } - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java b/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java deleted file mode 100644 index 07c87c6..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package io.netty.handler.ssl; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; - -import java.io.File; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.net.ssl.SSLEngine; - -import org.junit.Test; - -import io.netty.bootstrap.Bootstrap; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.DefaultEventLoopGroup; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.embedded.EmbeddedChannel; -import io.netty.channel.local.LocalAddress; -import io.netty.channel.local.LocalChannel; -import io.netty.channel.local.LocalServerChannel; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.handler.codec.DecoderException; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import io.netty.handler.ssl.util.SelfSignedCertificate; -import io.netty.util.DomainNameMapping; -import io.netty.util.DomainNameMappingBuilder; -import io.netty.util.Mapping; -import io.netty.util.ReferenceCountUtil; -import io.netty.util.ReferenceCounted; -import io.netty.util.concurrent.Promise; -import io.netty.util.internal.ObjectUtil; -import io.netty.util.internal.StringUtil; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -@RunWith(Parameterized.class) -public class SniHandlerTest { - - private static ApplicationProtocolConfig newApnConfig() { - return new ApplicationProtocolConfig( - ApplicationProtocolConfig.Protocol.ALPN, - // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers. - ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, - // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers. - ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, - "myprotocol"); - } - - private static void assumeApnSupported(SslProvider provider) { - switch (provider) { - case OPENSSL: - case OPENSSL_REFCNT: - assumeTrue(OpenSsl.isAlpnSupported()); - break; - case JDK: - assumeTrue(JettyAlpnSslEngine.isAvailable()); - break; - default: - throw new Error(); - } - } - - private static SslContext makeSslContext(SslProvider provider, boolean apn) throws Exception { - if (apn) { - assumeApnSupported(provider); - } - - File keyFile = new File(SniHandlerTest.class.getResource("test_encrypted.pem").getFile()); - File crtFile = new File(SniHandlerTest.class.getResource("test.crt").getFile()); - - SslContextBuilder sslCtxBuilder = SslContextBuilder.forServer(crtFile, keyFile, "12345") - .sslProvider(provider); - if (apn) { - sslCtxBuilder.applicationProtocolConfig(newApnConfig()); - } - return sslCtxBuilder.build(); - } - - private static SslContext makeSslClientContext(SslProvider provider, boolean apn) throws Exception { - if (apn) { - assumeApnSupported(provider); - } - - File crtFile = new File(SniHandlerTest.class.getResource("test.crt").getFile()); - - SslContextBuilder sslCtxBuilder = SslContextBuilder.forClient().trustManager(crtFile).sslProvider(provider); - if (apn) { - sslCtxBuilder.applicationProtocolConfig(newApnConfig()); - } - return sslCtxBuilder.build(); - } - - @Parameterized.Parameters(name = "{index}: sslProvider={0}") - public static Iterable data() { - List params = new ArrayList(3); - if (OpenSsl.isAvailable()) { - params.add(SslProvider.OPENSSL); - params.add(SslProvider.OPENSSL_REFCNT); - } - params.add(SslProvider.JDK); - return params; - } - - private final SslProvider provider; - - public SniHandlerTest(SslProvider provider) { - this.provider = provider; - } - - @Test - public void testServerNameParsing() throws Exception { - SslContext nettyContext = makeSslContext(provider, false); - SslContext leanContext = makeSslContext(provider, false); - SslContext leanContext2 = makeSslContext(provider, false); - - try { - DomainNameMapping mapping = new DomainNameMappingBuilder(nettyContext) - .add("*.netty.io", nettyContext) - // input with custom cases - .add("*.LEANCLOUD.CN", leanContext) - // a hostname conflict with previous one, since we are using order-sensitive config, - // the engine won't be used with the handler. - .add("chat4.leancloud.cn", leanContext2) - .build(); - - SniHandler handler = new SniHandler(mapping); - EmbeddedChannel ch = new EmbeddedChannel(handler); - - try { - // hex dump of a client hello packet, which contains hostname "CHAT4.LEANCLOUD.CN" - String tlsHandshakeMessageHex1 = "16030100"; - // part 2 - String tlsHandshakeMessageHex = "c6010000c20303bb0855d66532c05a0ef784f7c384feeafa68b3" + - "b655ac7288650d5eed4aa3fb52000038c02cc030009fcca9cca8ccaac02b" + - "c02f009ec024c028006bc023c0270067c00ac0140039c009c0130033009d" + - "009c003d003c0035002f00ff010000610000001700150000124348415434" + - "2e4c45414e434c4f55442e434e000b000403000102000a000a0008001d00" + - "170019001800230000000d0020001e060106020603050105020503040104" + - "0204030301030203030201020202030016000000170000"; - - ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1))); - ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex))); - - // This should produce an alert - assertTrue(ch.finish()); - - assertThat(handler.hostname(), is("chat4.leancloud.cn")); - assertThat(handler.sslContext(), is(leanContext)); - } finally { - ch.finishAndReleaseAll(); - } - } finally { - releaseAll(leanContext, leanContext2, nettyContext); - } - } - - @Test(expected = DecoderException.class) - public void testNonAsciiServerNameParsing() throws Exception { - SslContext nettyContext = makeSslContext(provider, false); - SslContext leanContext = makeSslContext(provider, false); - SslContext leanContext2 = makeSslContext(provider, false); - - try { - DomainNameMapping mapping = new DomainNameMappingBuilder(nettyContext) - .add("*.netty.io", nettyContext) - // input with custom cases - .add("*.LEANCLOUD.CN", leanContext) - // a hostname conflict with previous one, since we are using order-sensitive config, - // the engine won't be used with the handler. - .add("chat4.leancloud.cn", leanContext2) - .build(); - - SniHandler handler = new SniHandler(mapping); - EmbeddedChannel ch = new EmbeddedChannel(handler); - - try { - // hex dump of a client hello packet, which contains an invalid hostname "CHAT4。LEANCLOUD。CN" - String tlsHandshakeMessageHex1 = "16030100"; - // part 2 - String tlsHandshakeMessageHex = "bd010000b90303a74225676d1814ba57faff3b366" + - "3656ed05ee9dbb2a4dbb1bb1c32d2ea5fc39e0000000100008c0000001700150000164348" + - "415434E380824C45414E434C4F5544E38082434E000b000403000102000a00340032000e0" + - "00d0019000b000c00180009000a0016001700080006000700140015000400050012001300" + - "0100020003000f0010001100230000000d0020001e0601060206030501050205030401040" + - "20403030103020303020102020203000f00010133740000"; - - // Push the handshake message. - // Decode should fail because of the badly encoded "HostName" string in the SNI extension - // that isn't ASCII as per RFC 6066 - https://tools.ietf.org/html/rfc6066#page-6 - ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1))); - ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex))); - } finally { - ch.finishAndReleaseAll(); - } - } finally { - releaseAll(leanContext, leanContext2, nettyContext); - } - } - - @Test - public void testFallbackToDefaultContext() throws Exception { - SslContext nettyContext = makeSslContext(provider, false); - SslContext leanContext = makeSslContext(provider, false); - SslContext leanContext2 = makeSslContext(provider, false); - - try { - DomainNameMapping mapping = new DomainNameMappingBuilder(nettyContext) - .add("*.netty.io", nettyContext) - // input with custom cases - .add("*.LEANCLOUD.CN", leanContext) - // a hostname conflict with previous one, since we are using order-sensitive config, - // the engine won't be used with the handler. - .add("chat4.leancloud.cn", leanContext2) - .build(); - - SniHandler handler = new SniHandler(mapping); - EmbeddedChannel ch = new EmbeddedChannel(handler); - - // invalid - byte[] message = {22, 3, 1, 0, 0}; - - try { - // Push the handshake message. - ch.writeInbound(Unpooled.wrappedBuffer(message)); - } catch (Exception e) { - // expected - } - - assertThat(ch.finish(), is(false)); - assertThat(handler.hostname(), nullValue()); - assertThat(handler.sslContext(), is(nettyContext)); - } finally { - releaseAll(leanContext, leanContext2, nettyContext); - } - } - - @Test - public void testSniWithApnHandler() throws Exception { - SslContext nettyContext = makeSslContext(provider, true); - SslContext sniContext = makeSslContext(provider, true); - final SslContext clientContext = makeSslClientContext(provider, true); - try { - final CountDownLatch serverApnDoneLatch = new CountDownLatch(1); - final CountDownLatch clientApnDoneLatch = new CountDownLatch(1); - - final DomainNameMapping mapping = new DomainNameMappingBuilder(nettyContext) - .add("*.netty.io", nettyContext) - .add("sni.fake.site", sniContext).build(); - final SniHandler handler = new SniHandler(mapping); - EventLoopGroup group = new NioEventLoopGroup(2); - Channel serverChannel = null; - Channel clientChannel = null; - try { - ServerBootstrap sb = new ServerBootstrap(); - sb.group(group); - sb.channel(NioServerSocketChannel.class); - sb.childHandler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ChannelPipeline p = ch.pipeline(); - // Server side SNI. - p.addLast(handler); - // Catch the notification event that APN has completed successfully. - p.addLast(new ApplicationProtocolNegotiationHandler("foo") { - @Override - protected void configurePipeline(ChannelHandlerContext ctx, String protocol) { - serverApnDoneLatch.countDown(); - } - }); - } - }); - - Bootstrap cb = new Bootstrap(); - cb.group(group); - cb.channel(NioSocketChannel.class); - cb.handler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline().addLast(new SslHandler(clientContext.newEngine( - ch.alloc(), "sni.fake.site", -1))); - // Catch the notification event that APN has completed successfully. - ch.pipeline().addLast(new ApplicationProtocolNegotiationHandler("foo") { - @Override - protected void configurePipeline(ChannelHandlerContext ctx, String protocol) { - clientApnDoneLatch.countDown(); - } - }); - } - }); - - serverChannel = sb.bind(new InetSocketAddress(0)).sync().channel(); - - ChannelFuture ccf = cb.connect(serverChannel.localAddress()); - assertTrue(ccf.awaitUninterruptibly().isSuccess()); - clientChannel = ccf.channel(); - - assertTrue(serverApnDoneLatch.await(5, TimeUnit.SECONDS)); - assertTrue(clientApnDoneLatch.await(5, TimeUnit.SECONDS)); - assertThat(handler.hostname(), is("sni.fake.site")); - assertThat(handler.sslContext(), is(sniContext)); - } finally { - if (serverChannel != null) { - serverChannel.close().sync(); - } - if (clientChannel != null) { - clientChannel.close().sync(); - } - group.shutdownGracefully(0, 0, TimeUnit.MICROSECONDS); - } - } finally { - releaseAll(clientContext, nettyContext, sniContext); - } - } - - @Test(timeout = 30000) - public void testReplaceHandler() throws Exception { - switch (provider) { - case OPENSSL: - case OPENSSL_REFCNT: - final String sniHost = "sni.netty.io"; - LocalAddress address = new LocalAddress("testReplaceHandler-" + Math.random()); - EventLoopGroup group = new DefaultEventLoopGroup(1); - Channel sc = null; - Channel cc = null; - SslContext sslContext = null; - - SelfSignedCertificate cert = new SelfSignedCertificate(); - - try { - final SslContext sslServerContext = SslContextBuilder - .forServer(cert.key(), cert.cert()) - .sslProvider(provider) - .build(); - - final Mapping mapping = new Mapping() { - @Override - public SslContext map(String input) { - return sslServerContext; - } - }; - - final Promise releasePromise = group.next().newPromise(); - - final SniHandler handler = new SniHandler(mapping) { - @Override - protected void replaceHandler(ChannelHandlerContext ctx, - String hostname, final SslContext sslContext) - throws Exception { - - boolean success = false; - try { - // The SniHandler's replaceHandler() method allows us to implement custom behavior. - // As an example, we want to release() the SslContext upon channelInactive() or rather - // when the SslHandler closes it's SslEngine. If you take a close look at SslHandler - // you'll see that it's doing it in the #handlerRemoved0() method. - - SSLEngine sslEngine = sslContext.newEngine(ctx.alloc()); - try { - SslHandler customSslHandler = new CustomSslHandler(sslContext, sslEngine) { - @Override - public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { - try { - super.handlerRemoved0(ctx); - } finally { - releasePromise.trySuccess(null); - } - } - }; - ctx.pipeline().replace(this, CustomSslHandler.class.getName(), customSslHandler); - success = true; - } finally { - if (!success) { - ReferenceCountUtil.safeRelease(sslEngine); - } - } - } finally { - if (!success) { - ReferenceCountUtil.safeRelease(sslContext); - releasePromise.cancel(true); - } - } - } - }; - - ServerBootstrap sb = new ServerBootstrap(); - sc = sb.group(group).channel(LocalServerChannel.class) - .childHandler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline().addFirst(handler); - } - }).bind(address).syncUninterruptibly().channel(); - - sslContext = SslContextBuilder.forClient().sslProvider(provider) - .trustManager(InsecureTrustManagerFactory.INSTANCE).build(); - - Bootstrap cb = new Bootstrap(); - cc = cb.group(group).channel(LocalChannel.class).handler(new SslHandler( - sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost, -1))) - .connect(address).syncUninterruptibly().channel(); - - cc.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes())) - .syncUninterruptibly(); - - // Notice how the server's SslContext refCnt is 1 - assertEquals(1, ((ReferenceCounted) sslServerContext).refCnt()); - - // The client disconnects - cc.close().syncUninterruptibly(); - if (!releasePromise.awaitUninterruptibly(10L, TimeUnit.SECONDS)) { - throw new IllegalStateException("It doesn't seem #replaceHandler() got called."); - } - - // We should have successfully release() the SslContext - assertEquals(0, ((ReferenceCounted) sslServerContext).refCnt()); - } finally { - if (cc != null) { - cc.close().syncUninterruptibly(); - } - if (sc != null) { - sc.close().syncUninterruptibly(); - } - if (sslContext != null) { - ReferenceCountUtil.release(sslContext); - } - group.shutdownGracefully(); - - cert.delete(); - } - case JDK: - return; - default: - throw new Error(); - } - } - - /** - * This is a {@link SslHandler} that will call {@code release()} on the {@link SslContext} when - * the client disconnects. - * - * @see SniHandlerTest#testReplaceHandler() - */ - private static class CustomSslHandler extends SslHandler { - private final SslContext sslContext; - - public CustomSslHandler(SslContext sslContext, SSLEngine sslEngine) { - super(sslEngine); - this.sslContext = ObjectUtil.checkNotNull(sslContext, "sslContext"); - } - - @Override - public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { - super.handlerRemoved0(ctx); - ReferenceCountUtil.release(sslContext); - } - } - - private static void releaseAll(SslContext... contexts) { - for (SslContext ctx: contexts) { - ReferenceCountUtil.release(ctx); - } - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java b/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java deleted file mode 100644 index 752424c..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2015 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.handler.ssl.util.SelfSignedCertificate; -import org.junit.Assume; -import org.junit.Test; - -import javax.net.ssl.SSLEngine; - -public class SslContextBuilderTest { - - @Test - public void testClientContextFromFileJdk() throws Exception { - testClientContextFromFile(SslProvider.JDK); - } - - @Test - public void testClientContextFromFileOpenssl() throws Exception { - Assume.assumeTrue(OpenSsl.isAvailable()); - testClientContextFromFile(SslProvider.OPENSSL); - } - - @Test - public void testClientContextJdk() throws Exception { - testClientContext(SslProvider.JDK); - } - - @Test - public void testClientContextOpenssl() throws Exception { - Assume.assumeTrue(OpenSsl.isAvailable()); - testClientContext(SslProvider.OPENSSL); - } - - @Test - public void testServerContextFromFileJdk() throws Exception { - testServerContextFromFile(SslProvider.JDK); - } - - @Test - public void testServerContextFromFileOpenssl() throws Exception { - Assume.assumeTrue(OpenSsl.isAvailable()); - testServerContextFromFile(SslProvider.OPENSSL); - } - - @Test - public void testServerContextJdk() throws Exception { - testServerContext(SslProvider.JDK); - } - - @Test - public void testServerContextOpenssl() throws Exception { - Assume.assumeTrue(OpenSsl.isAvailable()); - testServerContext(SslProvider.OPENSSL); - } - - private static void testClientContextFromFile(SslProvider provider) throws Exception { - SelfSignedCertificate cert = new SelfSignedCertificate(); - SslContextBuilder builder = SslContextBuilder.forClient() - .sslProvider(provider) - .keyManager(cert.certificate(), - cert.privateKey()) - .trustManager(cert.certificate()) - .clientAuth(ClientAuth.OPTIONAL); - SslContext context = builder.build(); - SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); - assertFalse(engine.getWantClientAuth()); - assertFalse(engine.getNeedClientAuth()); - engine.closeInbound(); - engine.closeOutbound(); - } - - private static void testClientContext(SslProvider provider) throws Exception { - SelfSignedCertificate cert = new SelfSignedCertificate(); - SslContextBuilder builder = SslContextBuilder.forClient() - .sslProvider(provider) - .keyManager(cert.key(), cert.cert()) - .trustManager(cert.cert()) - .clientAuth(ClientAuth.OPTIONAL); - SslContext context = builder.build(); - SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); - assertFalse(engine.getWantClientAuth()); - assertFalse(engine.getNeedClientAuth()); - engine.closeInbound(); - engine.closeOutbound(); - } - - private static void testServerContextFromFile(SslProvider provider) throws Exception { - SelfSignedCertificate cert = new SelfSignedCertificate(); - SslContextBuilder builder = SslContextBuilder.forServer(cert.certificate(), cert.privateKey()) - .sslProvider(provider) - .trustManager(cert.certificate()) - .clientAuth(ClientAuth.OPTIONAL); - SslContext context = builder.build(); - SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); - assertTrue(engine.getWantClientAuth()); - assertFalse(engine.getNeedClientAuth()); - engine.closeInbound(); - engine.closeOutbound(); - } - - private static void testServerContext(SslProvider provider) throws Exception { - SelfSignedCertificate cert = new SelfSignedCertificate(); - SslContextBuilder builder = SslContextBuilder.forServer(cert.key(), cert.cert()) - .sslProvider(provider) - .trustManager(cert.cert()) - .clientAuth(ClientAuth.REQUIRE); - SslContext context = builder.build(); - SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT); - assertFalse(engine.getWantClientAuth()); - assertTrue(engine.getNeedClientAuth()); - engine.closeInbound(); - engine.closeOutbound(); - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java b/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java deleted file mode 100644 index aacdb69..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import io.netty.bootstrap.Bootstrap; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.handler.logging.LogLevel; -import io.netty.handler.logging.LoggingHandler; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import io.netty.handler.ssl.util.SelfSignedCertificate; -import io.netty.handler.ssl.util.SimpleTrustManagerFactory; -import io.netty.util.ReferenceCountUtil; -import io.netty.util.concurrent.Promise; -import io.netty.util.internal.EmptyArrays; -import org.junit.Assume; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import javax.net.ssl.ManagerFactoryParameters; -import javax.net.ssl.SSLException; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; -import javax.security.auth.x500.X500Principal; -import java.io.File; -import java.security.KeyStore; -import java.security.cert.CRLReason; -import java.security.cert.CertPathValidatorException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; -import java.security.cert.CertificateRevokedException; -import java.security.cert.Extension; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Locale; - - -@RunWith(Parameterized.class) -public class SslErrorTest { - - @Parameterized.Parameters(name = "{index}: serverProvider = {0}, clientProvider = {1}, exception = {2}") - public static Collection data() { - List serverProviders = new ArrayList(2); - List clientProviders = new ArrayList(3); - - if (OpenSsl.isAvailable()) { - serverProviders.add(SslProvider.OPENSSL); - serverProviders.add(SslProvider.OPENSSL_REFCNT); - clientProviders.add(SslProvider.OPENSSL); - clientProviders.add(SslProvider.OPENSSL_REFCNT); - } - // We not test with SslProvider.JDK on the server side as the JDK implementation currently just send the same - // alert all the time, sigh..... - clientProviders.add(SslProvider.JDK); - - List exceptions = new ArrayList(6); - exceptions.add(new CertificateExpiredException()); - exceptions.add(new CertificateNotYetValidException()); - exceptions.add(new CertificateRevokedException( - new Date(), CRLReason.AA_COMPROMISE, new X500Principal(""), - Collections.emptyMap())); - - // Also use wrapped exceptions as this is what the JDK implementation of X509TrustManagerFactory is doing. - exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.EXPIRED)); - exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.NOT_YET_VALID)); - exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.REVOKED)); - - List params = new ArrayList(); - for (SslProvider serverProvider: serverProviders) { - for (SslProvider clientProvider: clientProviders) { - for (CertificateException exception: exceptions) { - params.add(new Object[] { serverProvider, clientProvider, exception}); - } - } - } - return params; - } - - private static CertificateException newCertificateException(CertPathValidatorException.Reason reason) { - return new TestCertificateException( - new CertPathValidatorException("x", null, null, -1, reason)); - } - - private final SslProvider serverProvider; - private final SslProvider clientProvider; - private final CertificateException exception; - - public SslErrorTest(SslProvider serverProvider, SslProvider clientProvider, CertificateException exception) { - this.serverProvider = serverProvider; - this.clientProvider = clientProvider; - this.exception = exception; - } - - @Test(timeout = 30000) - public void testCorrectAlert() throws Exception { - // As this only works correctly at the moment when OpenSslEngine is used on the server-side there is - // no need to run it if there is no openssl is available at all. - Assume.assumeTrue(OpenSsl.isAvailable()); - - SelfSignedCertificate ssc = new SelfSignedCertificate(); - final SslContext sslServerCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(serverProvider) - .trustManager(new SimpleTrustManagerFactory() { - @Override - protected void engineInit(KeyStore keyStore) { } - @Override - protected void engineInit(ManagerFactoryParameters managerFactoryParameters) { } - - @Override - protected TrustManager[] engineGetTrustManagers() { - return new TrustManager[] { new X509TrustManager() { - - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) - throws CertificateException { - throw exception; - } - - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) - throws CertificateException { - // NOOP - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return EmptyArrays.EMPTY_X509_CERTIFICATES; - } - } }; - } - }).clientAuth(ClientAuth.REQUIRE).build(); - - final SslContext sslClientCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .keyManager(new File(getClass().getResource("test.crt").getFile()), - new File(getClass().getResource("test_unencrypted.pem").getFile())) - .sslProvider(clientProvider).build(); - - Channel serverChannel = null; - Channel clientChannel = null; - EventLoopGroup group = new NioEventLoopGroup(); - try { - serverChannel = new ServerBootstrap().group(group) - .channel(NioServerSocketChannel.class) - .handler(new LoggingHandler(LogLevel.INFO)) - .childHandler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline().addLast(sslServerCtx.newHandler(ch.alloc())); - ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - ctx.close(); - } - }); - } - }).bind(0).sync().channel(); - - final Promise promise = group.next().newPromise(); - - clientChannel = new Bootstrap().group(group) - .channel(NioSocketChannel.class) - .handler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline().addLast(sslClientCtx.newHandler(ch.alloc())); - ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - // Unwrap as its wrapped by a DecoderException - Throwable unwrappedCause = cause.getCause(); - if (unwrappedCause instanceof SSLException) { - if (exception instanceof TestCertificateException) { - CertPathValidatorException.Reason reason = - ((CertPathValidatorException) exception.getCause()).getReason(); - if (reason == CertPathValidatorException.BasicReason.EXPIRED) { - verifyException(unwrappedCause, "expired", promise); - } else if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) { - verifyException(unwrappedCause, "bad", promise); - } else if (reason == CertPathValidatorException.BasicReason.REVOKED) { - verifyException(unwrappedCause, "revoked", promise); - } - } else if (exception instanceof CertificateExpiredException) { - verifyException(unwrappedCause, "expired", promise); - } else if (exception instanceof CertificateNotYetValidException) { - verifyException(unwrappedCause, "bad", promise); - } else if (exception instanceof CertificateRevokedException) { - verifyException(unwrappedCause, "revoked", promise); - } - } - } - }); - } - }).connect(serverChannel.localAddress()).syncUninterruptibly().channel(); - // Block until we received the correct exception - promise.syncUninterruptibly(); - } finally { - if (clientChannel != null) { - clientChannel.close().syncUninterruptibly(); - } - if (serverChannel != null) { - serverChannel.close().syncUninterruptibly(); - } - group.shutdownGracefully(); - - ReferenceCountUtil.release(sslServerCtx); - ReferenceCountUtil.release(sslClientCtx); - } - } - - // Its a bit hacky to verify against the message that is part of the exception but there is no other way - // at the moment as there are no different exceptions for the different alerts. - private static void verifyException(Throwable cause, String messagePart, Promise promise) { - String message = cause.getMessage(); - if (message.toLowerCase(Locale.UK).contains(messagePart.toLowerCase(Locale.UK))) { - promise.setSuccess(null); - } else { - promise.setFailure(new AssertionError("message not contains '" + messagePart + "': " + message)); - } - } - - private static final class TestCertificateException extends CertificateException { - - public TestCertificateException(Throwable cause) { - super(cause); - } - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java index 5ef43de..52c4d22 100644 --- a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java +++ b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java @@ -121,35 +121,6 @@ public class SslHandlerTest { } } - @Test - public void testReleaseSslEngine() throws Exception { - assumeTrue(OpenSsl.isAvailable()); - - SelfSignedCertificate cert = new SelfSignedCertificate(); - try { - SslContext sslContext = SslContextBuilder.forServer(cert.certificate(), cert.privateKey()) - .sslProvider(SslProvider.OPENSSL) - .build(); - try { - SSLEngine sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT); - EmbeddedChannel ch = new EmbeddedChannel(new SslHandler(sslEngine)); - - assertEquals(1, ((ReferenceCounted) sslContext).refCnt()); - assertEquals(1, ((ReferenceCounted) sslEngine).refCnt()); - - assertTrue(ch.finishAndReleaseAll()); - ch.close().syncUninterruptibly(); - - assertEquals(1, ((ReferenceCounted) sslContext).refCnt()); - assertEquals(0, ((ReferenceCounted) sslEngine).refCnt()); - } finally { - ReferenceCountUtil.release(sslContext); - } - } finally { - cert.delete(); - } - } - private static final class TlsReadTest extends ChannelOutboundHandlerAdapter { private volatile boolean readIssued; @@ -279,13 +250,6 @@ public class SslHandlerTest { testAlertProducedAndSend(SslProvider.JDK); } - @Test(timeout = 30000) - public void testAlertProducedAndSendOpenSsl() throws Exception { - assumeTrue(OpenSsl.isAvailable()); - testAlertProducedAndSend(SslProvider.OPENSSL); - testAlertProducedAndSend(SslProvider.OPENSSL_REFCNT); - } - private void testAlertProducedAndSend(SslProvider provider) throws Exception { SelfSignedCertificate ssc = new SelfSignedCertificate(); @@ -425,12 +389,6 @@ public class SslHandlerTest { testCloseNotify(SslProvider.JDK, 5000, false); } - @Test(timeout = 30000) - public void testCloseNotifyReceivedOpenSsl() throws Exception { - assumeTrue(OpenSsl.isAvailable()); - testCloseNotify(SslProvider.OPENSSL, 5000, false); - testCloseNotify(SslProvider.OPENSSL_REFCNT, 5000, false); - } @Test(timeout = 30000) public void testCloseNotifyReceivedJdkTimeout() throws Exception { @@ -438,24 +396,10 @@ public class SslHandlerTest { } @Test(timeout = 30000) - public void testCloseNotifyReceivedOpenSslTimeout() throws Exception { - assumeTrue(OpenSsl.isAvailable()); - testCloseNotify(SslProvider.OPENSSL, 100, true); - testCloseNotify(SslProvider.OPENSSL_REFCNT, 100, true); - } - - @Test(timeout = 30000) public void testCloseNotifyNotWaitForResponseJdk() throws Exception { testCloseNotify(SslProvider.JDK, 0, false); } - @Test(timeout = 30000) - public void testCloseNotifyNotWaitForResponseOpenSsl() throws Exception { - assumeTrue(OpenSsl.isAvailable()); - testCloseNotify(SslProvider.OPENSSL, 0, false); - testCloseNotify(SslProvider.OPENSSL_REFCNT, 0, false); - } - private static void testCloseNotify(SslProvider provider, final long closeNotifyReadTimeout, final boolean timeout) throws Exception { SelfSignedCertificate ssc = new SelfSignedCertificate(); @@ -720,7 +664,7 @@ public class SslHandlerTest { switch (provider) { case OPENSSL: case OPENSSL_REFCNT: - return OpenSsl.isAvailable(); + return false; default: return true; } diff --git a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java b/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java deleted file mode 100644 index 4aecc74..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package io.netty.handler.ssl.ocsp; - -import io.netty.bootstrap.Bootstrap; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.DefaultEventLoopGroup; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.local.LocalAddress; -import io.netty.channel.local.LocalChannel; -import io.netty.channel.local.LocalServerChannel; -import io.netty.handler.ssl.OpenSsl; -import io.netty.handler.ssl.ReferenceCountedOpenSslEngine; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; -import io.netty.handler.ssl.SslHandler; -import io.netty.handler.ssl.SslProvider; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import io.netty.handler.ssl.util.SelfSignedCertificate; -import io.netty.util.CharsetUtil; -import io.netty.util.ReferenceCountUtil; - -import java.net.SocketAddress; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicReference; - -import javax.net.ssl.SSLHandshakeException; - -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; - -public class OcspTest { - - @BeforeClass - public static void checkOcspSupported() { - assumeTrue(OpenSsl.isOcspSupported()); - } - - @Test(expected = IllegalArgumentException.class) - public void testJdkClientEnableOcsp() throws Exception { - SslContextBuilder.forClient() - .sslProvider(SslProvider.JDK) - .enableOcsp(true) - .build(); - } - - @Test(expected = IllegalArgumentException.class) - public void testJdkServerEnableOcsp() throws Exception { - SelfSignedCertificate ssc = new SelfSignedCertificate(); - try { - SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(SslProvider.JDK) - .enableOcsp(true) - .build(); - } finally { - ssc.delete(); - } - } - - @Test(expected = IllegalStateException.class) - public void testClientOcspNotEnabledOpenSsl() throws Exception { - testClientOcspNotEnabled(SslProvider.OPENSSL); - } - - @Test(expected = IllegalStateException.class) - public void testClientOcspNotEnabledOpenSslRefCnt() throws Exception { - testClientOcspNotEnabled(SslProvider.OPENSSL_REFCNT); - } - - private void testClientOcspNotEnabled(SslProvider sslProvider) throws Exception { - SslContext context = SslContextBuilder.forClient() - .sslProvider(sslProvider) - .build(); - try { - SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT); - ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); - try { - engine.getOcspResponse(); - } finally { - engine.release(); - } - } finally { - ReferenceCountUtil.release(context); - } - } - - @Test(expected = IllegalStateException.class) - public void testServerOcspNotEnabledOpenSsl() throws Exception { - testServerOcspNotEnabled(SslProvider.OPENSSL); - } - - @Test(expected = IllegalStateException.class) - public void testServerOcspNotEnabledOpenSslRefCnt() throws Exception { - testServerOcspNotEnabled(SslProvider.OPENSSL_REFCNT); - } - - private void testServerOcspNotEnabled(SslProvider sslProvider) throws Exception { - SelfSignedCertificate ssc = new SelfSignedCertificate(); - try { - SslContext context = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslProvider) - .build(); - try { - SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT); - ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); - try { - engine.setOcspResponse(new byte[] { 1, 2, 3 }); - } finally { - engine.release(); - } - } finally { - ReferenceCountUtil.release(context); - } - } finally { - ssc.delete(); - } - } - - @Test(timeout = 10000L) - public void testClientAcceptingOcspStapleOpenSsl() throws Exception { - testClientAcceptingOcspStaple(SslProvider.OPENSSL); - } - - @Test(timeout = 10000L) - public void testClientAcceptingOcspStapleOpenSslRefCnt() throws Exception { - testClientAcceptingOcspStaple(SslProvider.OPENSSL_REFCNT); - } - - /** - * The Server provides an OCSP staple and the Client accepts it. - */ - private void testClientAcceptingOcspStaple(SslProvider sslProvider) throws Exception { - final CountDownLatch latch = new CountDownLatch(1); - ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter() { - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes())); - ctx.fireChannelActive(); - } - }; - - ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - try { - ReferenceCountUtil.release(msg); - } finally { - latch.countDown(); - } - } - }; - - byte[] response = newOcspResponse(); - TestClientOcspContext callback = new TestClientOcspContext(true); - - handshake(sslProvider, latch, serverHandler, response, clientHandler, callback); - - byte[] actual = callback.response(); - - assertNotNull(actual); - assertNotSame(response, actual); - assertArrayEquals(response, actual); - } - - @Test(timeout = 10000L) - public void testClientRejectingOcspStapleOpenSsl() throws Exception { - testClientRejectingOcspStaple(SslProvider.OPENSSL); - } - - @Test(timeout = 10000L) - public void testClientRejectingOcspStapleOpenSslRefCnt() throws Exception { - testClientRejectingOcspStaple(SslProvider.OPENSSL_REFCNT); - } - - /** - * The Server provides an OCSP staple and the Client rejects it. - */ - private void testClientRejectingOcspStaple(SslProvider sslProvider) throws Exception { - final AtomicReference causeRef = new AtomicReference(); - final CountDownLatch latch = new CountDownLatch(1); - - ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - try { - causeRef.set(cause); - } finally { - latch.countDown(); - } - } - }; - - byte[] response = newOcspResponse(); - TestClientOcspContext callback = new TestClientOcspContext(false); - - handshake(sslProvider, latch, null, response, clientHandler, callback); - - byte[] actual = callback.response(); - - assertNotNull(actual); - assertNotSame(response, actual); - assertArrayEquals(response, actual); - - Throwable cause = causeRef.get(); - assertTrue("" + cause, cause instanceof SSLHandshakeException); - } - - @Test(timeout = 10000L) - public void testServerHasNoStapleOpenSsl() throws Exception { - testServerHasNoStaple(SslProvider.OPENSSL); - } - - @Test(timeout = 10000L) - public void testServerHasNoStapleOpenSslRefCnt() throws Exception { - testServerHasNoStaple(SslProvider.OPENSSL_REFCNT); - } - - /** - * The server has OCSP stapling enabled but doesn't provide a staple. - */ - private void testServerHasNoStaple(SslProvider sslProvider) throws Exception { - final CountDownLatch latch = new CountDownLatch(1); - ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter() { - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes())); - ctx.fireChannelActive(); - } - }; - - ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - try { - ReferenceCountUtil.release(msg); - } finally { - latch.countDown(); - } - } - }; - - byte[] response = null; - TestClientOcspContext callback = new TestClientOcspContext(true); - - handshake(sslProvider, latch, serverHandler, response, clientHandler, callback); - - byte[] actual = callback.response(); - - assertNull(response); - assertNull(actual); - } - - @Test(timeout = 10000L) - public void testClientExceptionOpenSsl() throws Exception { - testClientException(SslProvider.OPENSSL); - } - - @Test(timeout = 10000L) - public void testClientExceptionOpenSslRefCnt() throws Exception { - testClientException(SslProvider.OPENSSL_REFCNT); - } - - /** - * Testing what happens if the {@link OcspClientCallback} throws an {@link Exception}. - * - * The exception should bubble up on the client side and the connection should get closed. - */ - private void testClientException(SslProvider sslProvider) throws Exception { - final AtomicReference causeRef = new AtomicReference(); - final CountDownLatch latch = new CountDownLatch(1); - - ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() { - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - try { - causeRef.set(cause); - } finally { - latch.countDown(); - } - } - }; - - final OcspTestException clientException = new OcspTestException("testClientException"); - byte[] response = newOcspResponse(); - OcspClientCallback callback = new OcspClientCallback() { - @Override - public boolean verify(byte[] response) throws Exception { - throw clientException; - } - }; - - handshake(sslProvider, latch, null, response, clientHandler, callback); - - assertSame(clientException, causeRef.get()); - } - - private static void handshake(SslProvider sslProvider, CountDownLatch latch, ChannelHandler serverHandler, - byte[] response, ChannelHandler clientHandler, OcspClientCallback callback) throws Exception { - - SelfSignedCertificate ssc = new SelfSignedCertificate(); - try { - SslContext serverSslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) - .sslProvider(sslProvider) - .enableOcsp(true) - .build(); - - try { - SslContext clientSslContext = SslContextBuilder.forClient() - .sslProvider(sslProvider) - .enableOcsp(true) - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .build(); - - try { - EventLoopGroup group = new DefaultEventLoopGroup(); - try { - LocalAddress address = new LocalAddress("handshake-" + Math.random()); - Channel server = newServer(group, address, serverSslContext, response, serverHandler); - Channel client = newClient(group, address, clientSslContext, callback, clientHandler); - try { - assertTrue("Something went wrong.", latch.await(10L, TimeUnit.SECONDS)); - } finally { - client.close().syncUninterruptibly(); - server.close().syncUninterruptibly(); - } - } finally { - group.shutdownGracefully(1L, 1L, TimeUnit.SECONDS); - } - } finally { - ReferenceCountUtil.release(clientSslContext); - } - } finally { - ReferenceCountUtil.release(serverSslContext); - } - } finally { - ssc.delete(); - } - } - - private static Channel newServer(EventLoopGroup group, SocketAddress address, - SslContext context, byte[] response, ChannelHandler handler) { - - ServerBootstrap bootstrap = new ServerBootstrap() - .channel(LocalServerChannel.class) - .group(group) - .childHandler(newServerHandler(context, response, handler)); - - return bootstrap.bind(address) - .syncUninterruptibly() - .channel(); - } - - private static Channel newClient(EventLoopGroup group, SocketAddress address, - SslContext context, OcspClientCallback callback, ChannelHandler handler) { - - Bootstrap bootstrap = new Bootstrap() - .channel(LocalChannel.class) - .group(group) - .handler(newClientHandler(context, callback, handler)); - - return bootstrap.connect(address) - .syncUninterruptibly() - .channel(); - } - - private static ChannelHandler newServerHandler(final SslContext context, - final byte[] response, final ChannelHandler handler) { - return new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ChannelPipeline pipeline = ch.pipeline(); - SslHandler sslHandler = context.newHandler(ch.alloc()); - - if (response != null) { - ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); - engine.setOcspResponse(response); - } - - pipeline.addLast(sslHandler); - - if (handler != null) { - pipeline.addLast(handler); - } - } - }; - } - - private static ChannelHandler newClientHandler(final SslContext context, - final OcspClientCallback callback, final ChannelHandler handler) { - return new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ChannelPipeline pipeline = ch.pipeline(); - - SslHandler sslHandler = context.newHandler(ch.alloc()); - ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine(); - - pipeline.addLast(sslHandler); - pipeline.addLast(new OcspClientCallbackHandler(engine, callback)); - - if (handler != null) { - pipeline.addLast(handler); - } - } - }; - } - - private static byte[] newOcspResponse() { - // Assume we got the OCSP staple from somewhere. Using a bogus byte[] - // in the test because getting a true staple from the CA is quite involved. - // It requires HttpCodec and Bouncycastle and the test may be very unreliable - // because the OCSP responder servers are basically being DDoS'd by the - // Internet. - - return "I am a bogus OCSP staple. OpenSSL does not care about the format of the byte[]!" - .getBytes(CharsetUtil.US_ASCII); - } - - private interface OcspClientCallback { - boolean verify(byte[] staple) throws Exception; - } - - private static final class TestClientOcspContext implements OcspClientCallback { - - private final CountDownLatch latch = new CountDownLatch(1); - private final boolean valid; - - private volatile byte[] response; - - public TestClientOcspContext(boolean valid) { - this.valid = valid; - } - - public byte[] response() throws InterruptedException, TimeoutException { - assertTrue(latch.await(10L, TimeUnit.SECONDS)); - return response; - } - - @Override - public boolean verify(byte[] response) throws Exception { - this.response = response; - latch.countDown(); - - return valid; - } - } - - private static final class OcspClientCallbackHandler extends OcspClientHandler { - - private final OcspClientCallback callback; - - public OcspClientCallbackHandler(ReferenceCountedOpenSslEngine engine, OcspClientCallback callback) { - super(engine); - this.callback = callback; - } - - @Override - protected boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception { - byte[] response = engine.getOcspResponse(); - return callback.verify(response); - } - } - - private static final class OcspTestException extends IllegalStateException { - public OcspTestException(String message) { - super(message); - } - } -} -- 2.9.4