From 99ce156e92be8ffabdef23a225b1284bb1fd52aa Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Tue, 11 Jul 2017 15:00:26 +0200 Subject: [PATCH] Update to upstream version 4.1.13 --- .gitignore | 1 + ...-OpenSSL-parts-depending-on-tcnative.patch | 5262 +++++++++++++---- 0002-Remove-NPN.patch | 353 ++ 0003-Remove-conscrypt-ALPN.patch | 511 ++ codegen.bash | 22 + netty.spec | 84 +- sources | 2 +- 7 files changed, 5061 insertions(+), 1174 deletions(-) create mode 100644 0002-Remove-NPN.patch create mode 100644 0003-Remove-conscrypt-ALPN.patch create mode 100755 codegen.bash diff --git a/.gitignore b/.gitignore index abd244f..859e799 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /netty-4.0.42.Final.tar.gz +/netty-4.1.13.Final.tar.gz diff --git a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch b/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch index 087ae53..aee0650 100644 --- a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch +++ b/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch @@ -1,40 +1,49 @@ -From 8b7286b1c8cd740e85fc483c1be6fcc8ce478ec4 Mon Sep 17 00:00:00 2001 +From 39b320920d3473d8cbc94d4a35dad37fa236e278 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Thu, 20 Oct 2016 15:54:52 +0200 -Subject: [PATCH 1/2] Remove OpenSSL parts depending on tcnative. +Subject: [PATCH 1/3] Remove OpenSSL parts depending on tcnative. --- - .../main/java/io/netty/handler/ssl/OpenSsl.java | 479 ----- - .../handler/ssl/OpenSslCertificateException.java | 80 - - .../io/netty/handler/ssl/OpenSslClientContext.java | 210 --- - .../java/io/netty/handler/ssl/OpenSslContext.java | 57 - - .../java/io/netty/handler/ssl/OpenSslEngine.java | 42 - + 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 | 370 ---- - .../handler/ssl/OpenSslServerSessionContext.java | 79 - - .../netty/handler/ssl/OpenSslSessionContext.java | 111 -- - .../io/netty/handler/ssl/OpenSslSessionStats.java | 155 -- + .../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 | 300 --- - .../ssl/ReferenceCountedOpenSslContext.java | 751 -------- - .../handler/ssl/ReferenceCountedOpenSslEngine.java | 1936 -------------------- - .../ssl/ReferenceCountedOpenSslServerContext.java | 195 -- - .../main/java/io/netty/handler/ssl/SslContext.java | 24 +- - .../main/java/io/netty/handler/ssl/SslHandler.java | 38 +- - .../handler/ssl/JdkOpenSslEngineInteroptTest.java | 37 - + .../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 | 129 -- - .../ssl/OpenSslJdkSslEngineInteroptTest.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 | 52 - - .../java/io/netty/handler/ssl/SniClientTest.java | 18 - - .../netty/handler/ssl/SslContextBuilderTest.java | 24 - - .../java/io/netty/handler/ssl/SslHandlerTest.java | 28 - - 30 files changed, 14 insertions(+), 5679 deletions(-) + .../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 @@ -52,21 +61,48 @@ Subject: [PATCH 1/2] Remove OpenSSL parts depending on tcnative. 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 c77d6cd..0000000 +index d2f091a..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java +++ /dev/null -@@ -1,479 +0,0 @@ +@@ -1,503 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -93,23 +129,16 @@ index c77d6cd..0000000 -import io.netty.util.internal.SystemPropertyUtil; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; --import org.apache.tomcat.Apr; --import org.apache.tomcat.jni.Buffer; --import org.apache.tomcat.jni.Library; --import org.apache.tomcat.jni.Pool; --import org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; +-import 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.io.IOException; --import java.io.InputStream; -import java.security.AccessController; -import java.security.PrivilegedAction; --import java.util.Arrays; -import java.util.Collections; --import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Locale; --import java.util.Properties; -import java.util.Set; - -/** @@ -127,7 +156,9 @@ index c77d6cd..0000000 - 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"; @@ -137,23 +168,14 @@ index c77d6cd..0000000 - static final String PROTOCOL_TLS_V1_1 = "TLSv1.1"; - static final String PROTOCOL_TLS_V1_2 = "TLSv1.2"; - -- private static final String[] SUPPORTED_PROTOCOLS = { -- PROTOCOL_SSL_V2_HELLO, -- PROTOCOL_SSL_V2, -- PROTOCOL_SSL_V3, -- PROTOCOL_TLS_V1, -- PROTOCOL_TLS_V1_1, -- PROTOCOL_TLS_V1_2 -- }; -- static final Set SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet( -- new HashSet(Arrays.asList(SUPPORTED_PROTOCOLS))); +- static final Set SUPPORTED_PROTOCOLS_SET; - - static { - Throwable cause = null; - - // Test if netty-tcnative is in the classpath first. - try { -- Class.forName("org.apache.tomcat.jni.SSL", false, OpenSsl.class.getClassLoader()); +- Class.forName("io.netty.internal.tcnative.SSL", false, OpenSsl.class.getClassLoader()); - } catch (ClassNotFoundException t) { - cause = t; - logger.debug( @@ -193,66 +215,69 @@ index c77d6cd..0000000 - } - } - -- if (cause == null && !isNettyTcnative()) { -- logger.debug("incompatible tcnative in the classpath; " -- + OpenSslEngine.class.getSimpleName() + " will be unavailable."); -- cause = new ClassNotFoundException("incompatible tcnative in the classpath"); -- } -- - UNAVAILABILITY_CAUSE = cause; - - if (cause == null) { +- logger.debug("netty-tcnative using native library: {}", SSL.versionString()); +- - final Set availableOpenSslCipherSuites = new LinkedHashSet(128); - boolean supportsKeyManagerFactory = false; - boolean useKeyManagerFactory = false; -- final long aprPool = Pool.create(0); +- boolean supportsHostNameValidation = false; - try { -- final long sslCtx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER); -- long privateKeyBio = 0; +- final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER); - long certBio = 0; +- SelfSignedCertificate cert = null; - try { -- SSLContext.setOptions(sslCtx, SSL.SSL_OP_ALL); - SSLContext.setCipherSuite(sslCtx, "ALL"); - final long ssl = SSL.newSSL(sslCtx, true); - try { - for (String c: SSL.getCiphers(ssl)) { - // Filter out bad input. -- if (c == null || c.length() == 0 || availableOpenSslCipherSuites.contains(c)) { +- if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c)) { - continue; - } - availableOpenSslCipherSuites.add(c); - } - try { -- SelfSignedCertificate cert = new SelfSignedCertificate(); -- certBio = OpenSslContext.toBIO(cert.cert()); +- 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; -- useKeyManagerFactory = AccessController.doPrivileged(new PrivilegedAction() { -- @Override -- public Boolean run() { -- return SystemPropertyUtil.getBoolean( -- "io.netty.handler.ssl.openssl.useKeyManagerFactory", 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 (privateKeyBio != 0) { -- SSL.freeBIO(privateKeyBio); -- } - 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); -- } finally { -- Pool.destroy(aprPool); - } - AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites); - @@ -267,48 +292,77 @@ index c77d6cd..0000000 - - final Set availableCipherSuites = new LinkedHashSet( - AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size()); -- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) { -- availableCipherSuites.add(cipher); -- } -- for (String cipher: AVAILABLE_JAVA_CIPHER_SUITES) { -- availableCipherSuites.add(cipher); -- } +- 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 isNettyTcnative() { -- return AccessController.doPrivileged(new PrivilegedAction() { -- @Override -- public Boolean run() { -- InputStream is = null; -- try { -- is = Apr.class.getResourceAsStream("/org/apache/tomcat/apr.properties"); -- Properties props = new Properties(); -- props.load(is); -- String info = props.getProperty("tcn.info"); -- return info != null && info.startsWith("netty-tcnative"); -- } catch (Throwable ignore) { -- return false; -- } finally { -- if (is != null) { -- try { -- is.close(); -- } catch (IOException ignore) { -- // ignore -- } -- } +- 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); +- } +- } - } - - /** @@ -329,14 +383,18 @@ index c77d6cd..0000000 - } - - /** +- * 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() { -- if (isAvailable()) { -- return SSL.version(); -- } -- return -1; +- return isAvailable() ? SSL.version() : -1; - } - - /** @@ -344,10 +402,7 @@ index c77d6cd..0000000 - * returns {@code false}. - */ - public static String versionString() { -- if (isAvailable()) { -- return SSL.versionString(); -- } -- return null; +- return isAvailable() ? SSL.versionString() : null; - } - - /** @@ -416,12 +471,16 @@ index c77d6cd..0000000 - return SUPPORTS_KEYMANAGER_FACTORY; - } - -- static boolean useKeyManagerFactory() { -- return USE_KEYMANAGER_FACTORY; +- /** +- * Returns {@code true} if Hostname Validation +- * is supported when using OpenSSL. +- */ +- public static boolean supportsHostnameValidation() { +- return SUPPORTS_HOSTNAME_VALIDATION; - } - -- static boolean isError(long errorCode) { -- return errorCode != SSL.SSL_ERROR_NONE; +- static boolean useKeyManagerFactory() { +- return USE_KEYMANAGER_FACTORY; - } - - static long memoryAddress(ByteBuf buf) { @@ -435,7 +494,7 @@ index c77d6cd..0000000 - String os = normalizeOs(SystemPropertyUtil.get("os.name", "")); - String arch = normalizeArch(SystemPropertyUtil.get("os.arch", "")); - -- Set libNames = new LinkedHashSet(3); +- 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); @@ -445,14 +504,15 @@ index c77d6cd..0000000 - } - // 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 void initializeTcNative() throws Exception { -- Library.initialize("provided"); -- SSL.initialize(null); +- private static boolean initializeTcNative() throws Exception { +- return Library.initialize(); - } - - private static String normalizeOs(String value) { @@ -548,10 +608,10 @@ index c77d6cd..0000000 -} diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java deleted file mode 100644 -index 5d9bce0..0000000 +index 4672d00..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java +++ /dev/null -@@ -1,80 +0,0 @@ +@@ -1,79 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * @@ -569,13 +629,13 @@ index 5d9bce0..0000000 - */ -package io.netty.handler.ssl; - --import org.apache.tomcat.jni.CertificateVerifier; +-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} is used. +- * 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; @@ -617,27 +677,26 @@ index 5d9bce0..0000000 - } - - /** -- * Return the error code to use. +- * Return the error code to use. - */ - public int errorCode() { - return errorCode; - } - - private static int checkErrorCode(int errorCode) { -- if (errorCode < CertificateVerifier.X509_V_OK || errorCode > CertificateVerifier.X509_V_ERR_DANE_NO_MATCH) { -- throw new IllegalArgumentException("errorCode must be " + CertificateVerifier.X509_V_OK + " => " -- + CertificateVerifier.X509_V_ERR_DANE_NO_MATCH + -- ". See https://www.openssl.org/docs/manmaster/apps/verify.html ."); +- 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 bbbbbee..0000000 +index 46412e9..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java +++ /dev/null -@@ -1,210 +0,0 @@ +@@ -1,211 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -655,7 +714,7 @@ index bbbbbee..0000000 - */ -package io.netty.handler.ssl; - --import org.apache.tomcat.jni.SSL; +-import io.netty.internal.tcnative.SSL; - -import java.io.File; -import java.security.PrivateKey; @@ -815,17 +874,18 @@ index bbbbbee..0000000 - throws SSLException { - this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, - toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), -- keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); +- 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, -- long sessionCacheSize, long sessionTimeout) +- 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, false); +- ClientAuth.NONE, protocols, false, enableOcsp); - boolean success = false; - try { - sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, @@ -850,10 +910,10 @@ index bbbbbee..0000000 -} diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java deleted file mode 100644 -index 4cafbfb..0000000 +index c4ca6b5..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java +++ /dev/null -@@ -1,57 +0,0 @@ +@@ -1,58 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -885,18 +945,19 @@ index 4cafbfb..0000000 -public abstract class OpenSslContext extends ReferenceCountedOpenSslContext { - OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg, - long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain, -- ClientAuth clientAuth, boolean startTls) +- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp) - throws SSLException { - super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain, -- clientAuth, startTls, false); +- clientAuth, protocols, startTls, enableOcsp, false); - } - - OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, - OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, - long sessionTimeout, int mode, Certificate[] keyCertChain, -- ClientAuth clientAuth, boolean startTls) throws SSLException { -- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, startTls, -- false); +- ClientAuth clientAuth, String[] protocols, boolean startTls, +- boolean enableOcsp) throws SSLException { +- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, protocols, +- startTls, enableOcsp, false); - } - - @Override @@ -913,10 +974,10 @@ index 4cafbfb..0000000 -} diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java deleted file mode 100644 -index 2ab7c5c..0000000 +index cbc7ee4..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java +++ /dev/null -@@ -1,42 +0,0 @@ +@@ -1,40 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -938,8 +999,6 @@ index 2ab7c5c..0000000 - -import javax.net.ssl.SSLEngine; - --import static io.netty.util.ReferenceCountUtil.safeRelease; -- -/** - * Implements a {@link SSLEngine} using - * OpenSSL BIO abstractions. @@ -1048,7 +1107,7 @@ index 38f6a7f..0000000 -} diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java deleted file mode 100644 -index 95a38fd..0000000 +index 2e48e8b..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java +++ /dev/null @@ -1,179 +0,0 @@ @@ -1070,8 +1129,8 @@ index 95a38fd..0000000 -package io.netty.handler.ssl; - -import io.netty.buffer.ByteBufAllocator; --import org.apache.tomcat.jni.CertificateRequestedCallback; --import org.apache.tomcat.jni.SSL; +-import io.netty.internal.tcnative.CertificateRequestedCallback; +-import io.netty.internal.tcnative.SSL; - -import javax.net.ssl.SSLException; -import javax.net.ssl.X509KeyManager; @@ -1233,10 +1292,10 @@ index 95a38fd..0000000 -} diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java deleted file mode 100644 -index a65e07d..0000000 +index f57434b..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java +++ /dev/null -@@ -1,370 +0,0 @@ +@@ -1,373 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -1255,7 +1314,7 @@ index a65e07d..0000000 -package io.netty.handler.ssl; - -import io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.ServerContext; --import org.apache.tomcat.jni.SSL; +-import io.netty.internal.tcnative.SSL; - -import java.io.File; -import java.security.PrivateKey; @@ -1562,16 +1621,18 @@ index a65e07d..0000000 - this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, - toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), - keyPassword, keyManagerFactory, ciphers, cipherFilter, -- apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, false); +- 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, boolean startTls) throws SSLException { +- 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, startTls); +- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, +- enableOcsp); - } - - @SuppressWarnings("deprecation") @@ -1579,9 +1640,10 @@ index a65e07d..0000000 - X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, - X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, - Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, -- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, boolean startTls) throws SSLException { +- 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, startTls); +- clientAuth, protocols, startTls, enableOcsp); - // Create a new SSL_CTX and configure it. - boolean success = false; - try { @@ -1609,10 +1671,10 @@ index a65e07d..0000000 -} diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java deleted file mode 100644 -index c6687f6..0000000 +index 8c92deb..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java +++ /dev/null -@@ -1,79 +0,0 @@ +@@ -1,124 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -1630,8 +1692,10 @@ index c6687f6..0000000 - */ -package io.netty.handler.ssl; - --import org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; +-import io.netty.internal.tcnative.SSL; +-import io.netty.internal.tcnative.SSLContext; +- +-import java.util.concurrent.locks.Lock; - - -/** @@ -1647,12 +1711,24 @@ index c6687f6..0000000 - if (seconds < 0) { - throw new IllegalArgumentException(); - } -- SSLContext.setSessionCacheTimeout(context.ctx, seconds); +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.setSessionCacheTimeout(context.ctx, seconds); +- } finally { +- writerLock.unlock(); +- } - } - - @Override - public int getSessionTimeout() { -- return (int) SSLContext.getSessionCacheTimeout(context.ctx); +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return (int) SSLContext.getSessionCacheTimeout(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - - @Override @@ -1660,23 +1736,48 @@ index c6687f6..0000000 - if (size < 0) { - throw new IllegalArgumentException(); - } -- SSLContext.setSessionCacheSize(context.ctx, size); +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.setSessionCacheSize(context.ctx, size); +- } finally { +- writerLock.unlock(); +- } - } - - @Override - public int getSessionCacheSize() { -- return (int) SSLContext.getSessionCacheSize(context.ctx); +- 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; -- SSLContext.setSessionCacheMode(context.ctx, mode); +- +- Lock writerLock = context.ctxLock.writeLock(); +- writerLock.lock(); +- try { +- SSLContext.setSessionCacheMode(context.ctx, mode); +- } finally { +- writerLock.unlock(); +- } - } - - @Override - public boolean isSessionCacheEnabled() { -- return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER; +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER; +- } finally { +- readerLock.unlock(); +- } - } - - /** @@ -1689,15 +1790,21 @@ index c6687f6..0000000 - * @return {@code true} if success, {@code false} otherwise. - */ - public boolean setSessionIdContext(byte[] sidCtx) { -- return SSLContext.setSessionIdContext(context.ctx, 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 df13d6a..0000000 +index 846a968..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java +++ /dev/null -@@ -1,111 +0,0 @@ +@@ -1,137 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -1716,14 +1823,16 @@ index df13d6a..0000000 -package io.netty.handler.ssl; - -import io.netty.util.internal.ObjectUtil; --import org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; --import org.apache.tomcat.jni.SessionTicketKey; +-import 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. @@ -1762,9 +1871,27 @@ index df13d6a..0000000 - */ - @Deprecated - public void setTicketKeys(byte[] keys) { -- ObjectUtil.checkNotNull(keys, "keys"); -- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET); -- SSLContext.setSessionTicketKeys(context.ctx, 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(); +- } - } - - /** @@ -1772,12 +1899,18 @@ index df13d6a..0000000 - */ - public void setTicketKeys(OpenSslSessionTicketKey... keys) { - ObjectUtil.checkNotNull(keys, "keys"); -- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET); - SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length]; - for (int i = 0; i < ticketKeys.length; i++) { - ticketKeys[i] = keys[i].key; - } -- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys); +- 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(); +- } - } - - /** @@ -1811,10 +1944,10 @@ index df13d6a..0000000 -} diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java deleted file mode 100644 -index ff93a04..0000000 +index f49b95f..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java +++ /dev/null -@@ -1,155 +0,0 @@ +@@ -1,253 +0,0 @@ -/* - * Copyright 2014 The Netty Project - * @@ -1833,12 +1966,14 @@ index ff93a04..0000000 - -package io.netty.handler.ssl; - --import org.apache.tomcat.jni.SSLContext; +-import io.netty.internal.tcnative.SSLContext; +- +-import java.util.concurrent.locks.Lock; - -/** - * Stats exposed by an OpenSSL session context. - * -- * @see SSL_CTX_sess_number +- * @see SSL_CTX_sess_number - */ -public final class OpenSslSessionStats { - @@ -1856,49 +1991,91 @@ index ff93a04..0000000 - * Returns the current number of sessions in the internal session cache. - */ - public long number() { -- return SSLContext.sessionNumber(context.ctx); +- 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() { -- return SSLContext.sessionConnect(context.ctx); +- 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() { -- return SSLContext.sessionConnectGood(context.ctx); +- 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() { -- return SSLContext.sessionConnectRenegotiate(context.ctx); +- 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() { -- return SSLContext.sessionAccept(context.ctx); +- 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() { -- return SSLContext.sessionAcceptGood(context.ctx); +- 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() { -- return SSLContext.sessionAcceptRenegotiate(context.ctx); +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionAcceptRenegotiate(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - - /** @@ -1907,14 +2084,26 @@ index ff93a04..0000000 - * external cache is counted as a hit. - */ - public long hits() { -- return SSLContext.sessionHits(context.ctx); +- 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() { -- return SSLContext.sessionCbHits(context.ctx); +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionCbHits(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - - /** @@ -1922,7 +2111,13 @@ index ff93a04..0000000 - * in server mode. - */ - public long misses() { -- return SSLContext.sessionMisses(context.ctx); +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionMisses(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - - /** @@ -1931,28 +2126,52 @@ index ff93a04..0000000 - * count. - */ - public long timeouts() { -- return SSLContext.sessionTimeouts(context.ctx); +- 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() { -- return SSLContext.sessionCacheFull(context.ctx); +- 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() { -- return SSLContext.sessionTicketKeyFail(context.ctx); +- 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() { -- return SSLContext.sessionTicketKeyNew(context.ctx); +- Lock readerLock = context.ctxLock.readLock(); +- readerLock.lock(); +- try { +- return SSLContext.sessionTicketKeyNew(context.ctx); +- } finally { +- readerLock.unlock(); +- } - } - - /** @@ -1960,19 +2179,31 @@ index ff93a04..0000000 - * and we upgraded to the primary key. - */ - public long ticketKeyRenew() { -- return SSLContext.sessionTicketKeyRenew(context.ctx); +- 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() { -- return SSLContext.sessionTicketKeyResume(context.ctx); +- 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 f3af820..0000000 +index 79f71a6..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java +++ /dev/null @@ -1,78 +0,0 @@ @@ -1993,7 +2224,7 @@ index f3af820..0000000 - */ -package io.netty.handler.ssl; - --import org.apache.tomcat.jni.SessionTicketKey; +-import io.netty.internal.tcnative.SessionTicketKey; - -/** - * Session Ticket Key @@ -2056,10 +2287,10 @@ index f3af820..0000000 -} diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java deleted file mode 100644 -index 97cd3e3..0000000 +index b213573..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java +++ /dev/null -@@ -1,300 +0,0 @@ +@@ -1,298 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * @@ -2079,9 +2310,9 @@ index 97cd3e3..0000000 - -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; --import org.apache.tomcat.jni.CertificateRequestedCallback; --import org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; +-import 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; @@ -2116,10 +2347,10 @@ index 97cd3e3..0000000 - X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, - KeyManagerFactory keyManagerFactory, Iterable ciphers, - CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, -- long sessionCacheSize, long sessionTimeout) -- throws SSLException { +- String[] protocols, long sessionCacheSize, long sessionTimeout, +- boolean enableOcsp) throws SSLException { - super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, -- ClientAuth.NONE, false, true); +- ClientAuth.NONE, protocols, false, enableOcsp, true); - boolean success = false; - try { - sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, @@ -2152,65 +2383,63 @@ index 97cd3e3..0000000 - throw new IllegalArgumentException( - "Either both keyCertChain and key needs to be null or none of them"); - } -- synchronized (ReferenceCountedOpenSslContext.class) { -- try { -- if (!OpenSsl.useKeyManagerFactory()) { -- if (keyManagerFactory != null) { -- throw new IllegalArgumentException( -- "KeyManagerFactory not supported"); -- } -- if (keyCertChain != null/* && key != null*/) { -- setKeyMaterial(ctx, keyCertChain, key, keyPassword); -- } -- } else { -- // javadocs state that keyManagerFactory has precedent over keyCertChain -- if (keyManagerFactory == null && keyCertChain != null) { -- keyManagerFactory = buildKeyManagerFactory( -- keyCertChain, key, keyPassword, keyManagerFactory); -- } -- -- if (keyManagerFactory != null) { -- X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers()); -- OpenSslKeyMaterialManager materialManager = useExtendedKeyManager(keyManager) ? -- new OpenSslExtendedKeyMaterialManager( -- (X509ExtendedKeyManager) keyManager, keyPassword) : -- new OpenSslKeyMaterialManager(keyManager, keyPassword); -- SSLContext.setCertRequestedCallback(ctx, new OpenSslCertificateRequestedCallback( -- engineMap, materialManager)); -- } +- 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); - } +- } catch (Exception e) { +- throw new SSLException("failed to set certificate and key", e); +- } - -- SSLContext.setVerify(ctx, SSL.SSL_VERIFY_NONE, VERIFY_DEPTH); +- 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); +- 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); - } @@ -2362,10 +2591,10 @@ index 97cd3e3..0000000 -} diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java deleted file mode 100644 -index 82e90a9..0000000 +index ee049ab..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java +++ /dev/null -@@ -1,751 +0,0 @@ +@@ -1,867 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * @@ -2385,24 +2614,24 @@ index 82e90a9..0000000 - -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.ResourceLeak; -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 org.apache.tomcat.jni.CertificateVerifier; --import org.apache.tomcat.jni.Pool; --import org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; - -import java.security.AccessController; -import java.security.PrivateKey; -import java.security.PrivilegedAction; +-import java.security.cert.CertPathValidatorException; -import java.security.cert.Certificate; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; @@ -2414,6 +2643,9 @@ index 82e90a9..0000000 -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; @@ -2425,6 +2657,7 @@ index 82e90a9..0000000 -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 @@ -2439,7 +2672,7 @@ index 82e90a9..0000000 - private static final InternalLogger logger = - InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class); - /** -- * To make it easier for users to replace JDK implemention with OpenSsl version we also use +- * 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. - *

@@ -2453,6 +2686,17 @@ index 82e90a9..0000000 - 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 = @@ -2462,12 +2706,11 @@ index 82e90a9..0000000 - protected static final int VERIFY_DEPTH = 10; - - /** -- * The OpenSSL SSL_CTX object +- * The OpenSSL SSL_CTX object. +- * +- * {@link #ctxLock} must be hold while using ctx! - */ -- protected volatile long ctx; -- long aprPool; -- @SuppressWarnings({ "unused", "FieldMayBeFinal" }) -- private volatile int aprPoolDestroyed; +- protected long ctx; - private final List unmodifiableCiphers; - private final long sessionCacheSize; - private final long sessionTimeout; @@ -2475,21 +2718,36 @@ index 82e90a9..0000000 - private final int mode; - - // Reference Counting -- private final ResourceLeak leak; +- 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) { -- leak.close(); +- 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(); -- volatile boolean rejectRemoteInitiatedRenegotiation; +- 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() { @@ -2558,26 +2816,33 @@ index 82e90a9..0000000 - - ReferenceCountedOpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, - ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout, -- int mode, Certificate[] keyCertChain, ClientAuth clientAuth, boolean startTls, -- boolean leakDetection) throws SSLException { +- 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, startTls, leakDetection); +- clientAuth, protocols, startTls, enableOcsp, leakDetection); - } - - ReferenceCountedOpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, - OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, - long sessionTimeout, int mode, Certificate[] keyCertChain, -- ClientAuth clientAuth, boolean startTls, boolean leakDetection) throws SSLException { +- 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.open(this) : null; +- 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 = @@ -2603,97 +2868,97 @@ index 82e90a9..0000000 - } - - unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites( -- convertedCiphers, DEFAULT_CIPHERS, OpenSsl.availableCipherSuites())); +- convertedCiphers, DEFAULT_CIPHERS, OpenSsl.availableOpenSslCipherSuites())); - - this.apn = checkNotNull(apn, "apn"); - -- // Allocate a new APR pool. -- aprPool = Pool.create(0); -- - // Create a new SSL_CTX and configure it. - boolean success = false; - try { -- synchronized (ReferenceCountedOpenSslContext.class) { -- try { -- ctx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, mode); -- } catch (Exception e) { -- throw new SSLException("failed to create an SSL_CTX", e); -- } +- 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, SSL.SSL_OP_ALL); -- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SSLv2); -- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SSLv3); -- SSLContext.setOptions(ctx, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); -- SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_ECDH_USE); -- SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_DH_USE); -- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); -- // Disable ticket support by default to be more inline with SSLEngineImpl of the JDK. -- // This also let SSLSession.getId() work the same way for the JDK implementation and the OpenSSLEngine. -- // If tickets are supported SSLSession.getId() will only return an ID on the server-side if it could -- // make use of tickets. -- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_TICKET); +- SSLContext.setOptions(ctx, SSLContext.getOptions(ctx) | +- SSL.SSL_OP_NO_SSLv2 | +- SSL.SSL_OP_NO_SSLv3 | +- SSL.SSL_OP_CIPHER_SERVER_PREFERENCE | - -- // 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); +- // We do not support compression at the moment so we should explicitly disable it. +- SSL.SSL_OP_NO_COMPRESSION | - -- if (DH_KEY_LENGTH != null) { -- SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH); -- } +- // 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); -- } +- 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(); +- List nextProtoList = apn.protocols(); - /* Set next protocols for next protocol negotiation extension, if specified */ -- if (!nextProtoList.isEmpty()) { -- String[] protocols = nextProtoList.toArray(new String[nextProtoList.size()]); -- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior()); +- if (!nextProtoList.isEmpty()) { +- String[] appProtocols = nextProtoList.toArray(new String[nextProtoList.size()]); +- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior()); - -- switch (apn.protocol()) { -- case NPN: -- SSLContext.setNpnProtos(ctx, protocols, selectorBehavior); -- break; -- case ALPN: -- SSLContext.setAlpnProtos(ctx, protocols, selectorBehavior); -- break; -- case NPN_AND_ALPN: -- SSLContext.setNpnProtos(ctx, protocols, selectorBehavior); -- SSLContext.setAlpnProtos(ctx, protocols, selectorBehavior); -- break; -- default: -- throw new Error(); -- } +- 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 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); -- } +- /* 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 { @@ -2763,11 +3028,17 @@ index 82e90a9..0000000 - * Be aware that it is freed as soon as the {@link #finalize()} method is called. - * At this point {@code 0} will be returned. - * -- * @deprecated use {@link #sslCtxPointer()} +- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it! - */ - @Deprecated - public final long context() { -- return ctx; +- Lock readerLock = ctxLock.readLock(); +- readerLock.lock(); +- try { +- return ctx; +- } finally { +- readerLock.unlock(); +- } - } - - /** @@ -2789,6 +3060,29 @@ index 82e90a9..0000000 - } - - /** +- * 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[])} @@ -2803,28 +3097,39 @@ index 82e90a9..0000000 - - /** - * 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. +- * 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() { -- return ctx; +- 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. -- final void destroy() { -- synchronized (ReferenceCountedOpenSslContext.class) { +- private void destroy() { +- Lock writerLock = ctxLock.writeLock(); +- writerLock.lock(); +- try { - if (ctx != 0) { +- if (enableOcsp) { +- SSLContext.disableOcsp(ctx); +- } +- - SSLContext.free(ctx); - ctx = 0; - } -- -- // Guard against multiple destroyPools() calls triggered by construction exception and finalize() later -- if (aprPool != 0) { -- Pool.destroy(aprPool); -- aprPool = 0; -- } +- } finally { +- writerLock.unlock(); - } - } - @@ -2923,6 +3228,18 @@ index 82e90a9..0000000 - } - - @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(); - } @@ -2932,7 +3249,7 @@ index 82e90a9..0000000 - return refCnt.release(decrement); - } - -- abstract static class AbstractCertificateVerifier implements CertificateVerifier { +- abstract static class AbstractCertificateVerifier extends CertificateVerifier { - private final OpenSslEngineMap engineMap; - - AbstractCertificateVerifier(OpenSslEngineMap engineMap) { @@ -2952,7 +3269,10 @@ index 82e90a9..0000000 - 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) { @@ -2961,9 +3281,34 @@ index 82e90a9..0000000 - if (cause instanceof CertificateNotYetValidException) { - return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID; - } -- if (PlatformDependent.javaVersion() >= 7 && cause instanceof CertificateRevokedException) { -- return CertificateVerifier.X509_V_ERR_CERT_REVOKED; +- 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; - } - } @@ -3080,13 +3425,13 @@ index 82e90a9..0000000 - ByteBuf content = pem.content(); - - if (content.isDirect()) { -- return newBIO(content.slice().retain()); +- return newBIO(content.retainedSlice()); - } - - ByteBuf buffer = allocator.directBuffer(content.readableBytes()); - try { - buffer.writeBytes(content, content.readerIndex(), content.readableBytes()); -- return newBIO(buffer.slice().retain()); +- return newBIO(buffer.retainedSlice()); - } finally { - try { - // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we @@ -3107,7 +3452,7 @@ index 82e90a9..0000000 - try { - long bio = SSL.newMemBIO(); - int readable = buffer.readableBytes(); -- if (SSL.writeToBIO(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) { +- if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) { - SSL.freeBIO(bio); - throw new IllegalStateException("Could not write data to memory BIO"); - } @@ -3119,10 +3464,10 @@ index 82e90a9..0000000 -} diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java deleted file mode 100644 -index 6b28ca0..0000000 +index 27460c7..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java +++ /dev/null -@@ -1,1936 +0,0 @@ +@@ -1,2037 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * @@ -3142,35 +3487,34 @@ index 6b28ca0..0000000 - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; --import io.netty.buffer.Unpooled; +-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.ResourceLeak; -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.InternalThreadLocalMap; -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 org.apache.tomcat.jni.Buffer; --import org.apache.tomcat.jni.SSL; - --import java.lang.reflect.InvocationTargetException; --import java.lang.reflect.Method; -import java.nio.ByteBuffer; -import java.nio.ReadOnlyBufferException; -import java.security.Principal; -import java.security.cert.Certificate; +-import java.util.ArrayList; -import java.util.Arrays; --import java.util.Collections; +-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; @@ -3184,12 +3528,17 @@ index 6b28ca0..0000000 -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; - @@ -3212,88 +3561,37 @@ index 6b28ca0..0000000 - new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "handshake()"); - private static final SSLException RENEGOTIATION_UNSUPPORTED = ThrowableUtil.unknownStackTrace( - new SSLException("renegotiation unsupported"), ReferenceCountedOpenSslEngine.class, "beginHandshake()"); -- private static final SSLException ENCRYPTED_PACKET_OVERSIZED = ThrowableUtil.unknownStackTrace( -- new SSLException("encrypted packet oversized"), ReferenceCountedOpenSslEngine.class, "unwrap(...)"); -- private static final Class SNI_HOSTNAME_CLASS; -- private static final Method GET_SERVER_NAMES_METHOD; -- private static final Method SET_SERVER_NAMES_METHOD; -- private static final Method GET_ASCII_NAME_METHOD; -- private static final Method GET_USE_CIPHER_SUITES_ORDER_METHOD; -- private static final Method SET_USE_CIPHER_SUITES_ORDER_METHOD; - private static final ResourceLeakDetector leakDetector = - ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class); +- /** +- * The flags argument is usually 0. +- */ +- private static final int DEFAULT_HOSTNAME_VALIDATION_FLAGS = 0; - -- static { -- AtomicIntegerFieldUpdater destroyedUpdater = -- PlatformDependent.newAtomicIntegerFieldUpdater(ReferenceCountedOpenSslEngine.class, "destroyed"); -- if (destroyedUpdater == null) { -- destroyedUpdater = AtomicIntegerFieldUpdater.newUpdater(ReferenceCountedOpenSslEngine.class, "destroyed"); -- } -- DESTROYED_UPDATER = destroyedUpdater; +- static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14 - -- Method getUseCipherSuitesOrderMethod = null; -- Method setUseCipherSuitesOrderMethod = null; -- Class sniHostNameClass = null; -- Method getAsciiNameMethod = null; -- Method getServerNamesMethod = null; -- Method setServerNamesMethod = null; -- if (PlatformDependent.javaVersion() >= 8) { -- try { -- getUseCipherSuitesOrderMethod = SSLParameters.class.getDeclaredMethod("getUseCipherSuitesOrder"); -- SSLParameters parameters = new SSLParameters(); -- @SuppressWarnings("unused") -- Boolean order = (Boolean) getUseCipherSuitesOrderMethod.invoke(parameters); -- setUseCipherSuitesOrderMethod = SSLParameters.class.getDeclaredMethod("setUseCipherSuitesOrder", -- boolean.class); -- setUseCipherSuitesOrderMethod.invoke(parameters, true); -- } catch (Throwable ignore) { -- getUseCipherSuitesOrderMethod = null; -- setUseCipherSuitesOrderMethod = null; -- } -- try { -- sniHostNameClass = Class.forName("javax.net.ssl.SNIHostName", false, -- PlatformDependent.getClassLoader(ReferenceCountedOpenSslEngine.class)); -- Object sniHostName = sniHostNameClass.getConstructor(String.class).newInstance("netty.io"); -- getAsciiNameMethod = sniHostNameClass.getDeclaredMethod("getAsciiName"); -- @SuppressWarnings("unused") -- String name = (String) getAsciiNameMethod.invoke(sniHostName); +- /** +- * 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; - -- getServerNamesMethod = SSLParameters.class.getDeclaredMethod("getServerNames"); -- setServerNamesMethod = SSLParameters.class.getDeclaredMethod("setServerNames", List.class); -- SSLParameters parameters = new SSLParameters(); -- @SuppressWarnings({ "rawtypes", "unused" }) -- List serverNames = (List) getServerNamesMethod.invoke(parameters); -- setServerNamesMethod.invoke(parameters, Collections.emptyList()); -- } catch (Throwable ingore) { -- sniHostNameClass = null; -- getAsciiNameMethod = null; -- getServerNamesMethod = null; -- setServerNamesMethod = null; -- } -- } -- GET_USE_CIPHER_SUITES_ORDER_METHOD = getUseCipherSuitesOrderMethod; -- SET_USE_CIPHER_SUITES_ORDER_METHOD = setUseCipherSuitesOrderMethod; -- SNI_HOSTNAME_CLASS = sniHostNameClass; -- GET_ASCII_NAME_METHOD = getAsciiNameMethod; -- GET_SERVER_NAMES_METHOD = getServerNamesMethod; -- SET_SERVER_NAMES_METHOD = setServerNamesMethod; -- } +- static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_PLAINTEXT_LENGTH + MAX_TLS_RECORD_OVERHEAD_LENGTH; - -- private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14 -- private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024; -- private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024; -- -- // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256) -- static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256; -- -- static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = MAX_ENCRYPTED_PACKET_LENGTH - MAX_PLAINTEXT_LENGTH; -- -- private static final AtomicIntegerFieldUpdater DESTROYED_UPDATER; +- private static final AtomicIntegerFieldUpdater DESTROYED_UPDATER = +- AtomicIntegerFieldUpdater.newUpdater(ReferenceCountedOpenSslEngine.class, "destroyed"); - - private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL"; -- -- private static final long EMPTY_ADDR = Buffer.address(Unpooled.EMPTY_BUFFER.nioBuffer()); -- - private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0); - private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0); - private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0); @@ -3326,17 +3624,28 @@ index 6b28ca0..0000000 - } - - private HandshakeState handshakeState = HandshakeState.NOT_STARTED; +- private boolean renegotiationPending; - private boolean receivedShutdown; - private volatile int destroyed; - - // Reference Counting -- private final ResourceLeak leak; +- 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) { -- leak.close(); +- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this); +- assert closed; - } - } - }; @@ -3349,23 +3658,27 @@ index 6b28ca0..0000000 - private String endPointIdentificationAlgorithm; - // Store as object as AlgorithmConstraints only exists since java 7. - private Object algorithmConstraints; -- private List sniHostNames; +- 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 isOutboundDone; -- private boolean engineClosed; +- private boolean outboundClosed; - - private final boolean clientMode; - private final ByteBufAllocator alloc; - private final OpenSslEngineMap engineMap; - private final OpenSslApplicationProtocolNegotiator apn; -- private final boolean rejectRemoteInitiatedRenegation; +- 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. @@ -3383,27 +3696,84 @@ index 6b28ca0..0000000 - int peerPort, boolean leakDetection) { - super(peerHost, peerPort); - OpenSsl.ensureAvailability(); -- leak = leakDetection ? leakDetector.open(this) : null; +- leak = leakDetection ? leakDetector.track(this) : null; - this.alloc = checkNotNull(alloc, "alloc"); - apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator(); -- ssl = SSL.newSSL(context.ctx, !context.isClient()); -- session = new ReferenceCountedOpenSslEngine.OpenSslSession(context.sessionContext()); -- networkBIO = SSL.makeNetworkBIO(ssl); +- session = new OpenSslSession(context.sessionContext()); - clientMode = context.isClient(); - engineMap = context.engineMap; -- rejectRemoteInitiatedRenegation = context.rejectRemoteInitiatedRenegotiation; +- rejectRemoteInitiatedRenegotiation = context.getRejectRemoteInitiatedRenegotiation(); - localCerts = context.keyCertChain; -- -- // Set the client auth mode, this needs to be done via setClientAuth(...) method so we actually call the -- // needed JNI methods. -- setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth); -- -- // Use SNI if peerHost was specified -- // See https://github.com/netty/netty/issues/4746 -- if (clientMode && peerHost != null) { -- SSL.setTlsExtHostName(ssl, peerHost); -- } - keyMaterialManager = context.keyMaterialManager(); +- 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 @@ -3424,6 +3794,18 @@ index 6b28ca0..0000000 - } - - @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(); - } @@ -3464,11 +3846,9 @@ index 6b28ca0..0000000 - if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) { - engineMap.remove(ssl); - SSL.freeSSL(ssl); -- SSL.freeBIO(networkBIO); - ssl = networkBIO = 0; - -- // internal errors can cause shutdown without marking the engine closed -- isInboundDone = isOutboundDone = engineClosed = true; +- isInboundDone = outboundClosed = true; - } - - // On shutdown clear all errors @@ -3480,29 +3860,25 @@ index 6b28ca0..0000000 - * - * Calling this function with src.remaining == 0 is undefined. - */ -- private int writePlaintextData(final ByteBuffer src) { +- private int writePlaintextData(final ByteBuffer src, int len) { - final int pos = src.position(); - final int limit = src.limit(); -- final int len = Math.min(limit - pos, MAX_PLAINTEXT_LENGTH); - final int sslWrote; - - if (src.isDirect()) { -- final long addr = Buffer.address(src) + pos; -- sslWrote = SSL.writeToSSL(ssl, addr, len); +- sslWrote = SSL.writeToSSL(ssl, Buffer.address(src) + pos, len); - if (sslWrote > 0) { - src.position(pos + sslWrote); - } - } else { - ByteBuf buf = alloc.directBuffer(len); - try { -- final long addr = memoryAddress(buf); -- - src.limit(pos + len); - - buf.setBytes(0, src); - src.limit(limit); - -- sslWrote = SSL.writeToSSL(ssl, addr, len); +- sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len); - if (sslWrote > 0) { - src.position(pos + sslWrote); - } else { @@ -3518,35 +3894,28 @@ index 6b28ca0..0000000 - /** - * Write encrypted data to the OpenSSL network BIO. - */ -- private int writeEncryptedData(final ByteBuffer src) { +- private ByteBuf writeEncryptedData(final ByteBuffer src, int len) { - final int pos = src.position(); -- final int len = src.remaining(); -- final int netWrote; - if (src.isDirect()) { -- final long addr = Buffer.address(src) + pos; -- netWrote = SSL.writeToBIO(networkBIO, addr, len); -- if (netWrote >= 0) { -- src.position(pos + netWrote); -- } +- SSL.bioSetByteBuffer(networkBIO, Buffer.address(src) + pos, len, false); - } else { - final ByteBuf buf = alloc.directBuffer(len); - try { -- final long addr = memoryAddress(buf); +- 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); - -- buf.setBytes(0, src); -- -- netWrote = SSL.writeToBIO(networkBIO, addr, len); -- if (netWrote >= 0) { -- src.position(pos + netWrote); -- } else { -- src.position(pos); -- } -- } finally { +- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false); +- return buf; +- } catch (Throwable cause) { - buf.release(); +- PlatformDependent.throwException(cause); - } - } -- -- return netWrote; +- return null; - } - - /** @@ -3554,26 +3923,21 @@ index 6b28ca0..0000000 - */ - private int readPlaintextData(final ByteBuffer dst) { - final int sslRead; +- final int pos = dst.position(); - if (dst.isDirect()) { -- final int pos = dst.position(); -- final long addr = Buffer.address(dst) + pos; -- final int len = dst.limit() - pos; -- sslRead = SSL.readFromSSL(ssl, addr, len); +- sslRead = SSL.readFromSSL(ssl, Buffer.address(dst) + pos, dst.limit() - pos); - if (sslRead > 0) { - dst.position(pos + sslRead); - } - } else { -- final int pos = dst.position(); - final int limit = dst.limit(); -- final int len = Math.min(MAX_ENCRYPTED_PACKET_LENGTH, limit - pos); +- final int len = min(MAX_ENCRYPTED_PACKET_LENGTH, limit - pos); - final ByteBuf buf = alloc.directBuffer(len); - try { -- final long addr = memoryAddress(buf); -- -- sslRead = SSL.readFromSSL(ssl, addr, len); +- sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len); - if (sslRead > 0) { - dst.limit(pos + sslRead); -- buf.getBytes(0, dst); +- buf.getBytes(buf.readerIndex(), dst); - dst.limit(limit); - } - } finally { @@ -3584,83 +3948,9 @@ index 6b28ca0..0000000 - return sslRead; - } - -- /** -- * Read encrypted data from the OpenSSL network BIO -- */ -- private int readEncryptedData(final ByteBuffer dst, final int pending) { -- final int bioRead; -- -- if (dst.isDirect() && dst.remaining() >= pending) { -- final int pos = dst.position(); -- final long addr = Buffer.address(dst) + pos; -- bioRead = SSL.readFromBIO(networkBIO, addr, pending); -- if (bioRead > 0) { -- dst.position(pos + bioRead); -- return bioRead; -- } -- } else { -- final ByteBuf buf = alloc.directBuffer(pending); -- try { -- final long addr = memoryAddress(buf); -- -- bioRead = SSL.readFromBIO(networkBIO, addr, pending); -- if (bioRead > 0) { -- int oldLimit = dst.limit(); -- dst.limit(dst.position() + bioRead); -- buf.getBytes(0, dst); -- dst.limit(oldLimit); -- return bioRead; -- } -- } finally { -- buf.release(); -- } -- } -- -- return bioRead; -- } -- -- private SSLEngineResult readPendingBytesFromBIO(ByteBuffer dst, int bytesConsumed, int bytesProduced, -- SSLEngineResult.HandshakeStatus status) throws SSLException { -- // Check to see if the engine wrote data into the network BIO -- int pendingNet = SSL.pendingWrittenBytesInBIO(networkBIO); -- if (pendingNet > 0) { -- -- // Do we have enough room in dst to write encrypted data? -- int capacity = dst.remaining(); -- if (capacity < pendingNet) { -- return new SSLEngineResult(BUFFER_OVERFLOW, -- mayFinishHandshake(status != FINISHED ? getHandshakeStatus(pendingNet) : status), -- bytesConsumed, bytesProduced); -- } -- -- // Write the pending data from the network BIO into the dst buffer -- int produced = readEncryptedData(dst, pendingNet); -- -- if (produced <= 0) { -- // We ignore BIO_* errors here as we use in memory BIO anyway and will do another SSL_* call later -- // on in which we will produce an exception in case of an error -- SSL.clearError(); -- } else { -- bytesProduced += produced; -- pendingNet -= produced; -- } -- // If isOuboundDone is set, then the data from the network BIO -- // was the close_notify message -- we are not required to wait -- // for the receipt the peer's close_notify message -- shutdown. -- if (isOutboundDone) { -- shutdown(); -- } -- -- return new SSLEngineResult(getEngineStatus(), -- mayFinishHandshake(status != FINISHED ? getHandshakeStatus(pendingNet) : status), -- bytesConsumed, bytesProduced); -- } -- return null; -- } -- - @Override - public final SSLEngineResult wrap( -- final ByteBuffer[] srcs, final int offset, final int length, final ByteBuffer dst) throws SSLException { +- 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"); @@ -3680,105 +3970,252 @@ index 6b28ca0..0000000 - } - - synchronized (this) { -- // Check to make sure the engine has not been closed -- if (isDestroyed()) { -- return CLOSED_NOT_HANDSHAKING; +- if (isOutboundDone()) { +- // All drained in the outbound buffer +- return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_UNWRAP_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_UNWRAP) { -- return NEED_UNWRAP_OK; -- } -- -- if (engineClosed) { -- return NEED_UNWRAP_CLOSED; -- } -- } -- -- // There was no pending data in the network BIO -- encrypt any application data - int bytesProduced = 0; -- int bytesConsumed = 0; -- int endOffset = offset + length; -- for (int i = offset; i < endOffset; ++i) { -- final ByteBuffer src = srcs[i]; -- if (src == null) { -- throw new IllegalArgumentException("srcs[" + i + "] is null"); +- 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); - } -- while (src.hasRemaining()) { -- final SSLEngineResult pendingNetResult; -- // Write plaintext application data to the SSL engine -- int result = writePlaintextData(src); -- if (result > 0) { -- bytesConsumed += result; - -- pendingNetResult = readPendingBytesFromBIO(dst, bytesConsumed, bytesProduced, status); -- if (pendingNetResult != null) { -- if (pendingNetResult.getStatus() != OK) { -- return pendingNetResult; -- } -- bytesProduced = pendingNetResult.bytesProduced(); -- } +- 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, result); -- switch (sslError) { -- case SSL.SSL_ERROR_ZERO_RETURN: -- // This means the connection was shutdown correctly, close inbound and outbound -- if (!receivedShutdown) { -- closeAll(); -- } -- pendingNetResult = readPendingBytesFromBIO(dst, bytesConsumed, bytesProduced, status); -- return pendingNetResult != null ? pendingNetResult : CLOSED_NOT_HANDSHAKING; -- case SSL.SSL_ERROR_WANT_READ: -- // If there is no pending data to read from BIO we should go back to event loop and try -- // to read more data [1]. It is also possible that event loop will detect the socket -- // has been closed. [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html -- pendingNetResult = readPendingBytesFromBIO(dst, bytesConsumed, bytesProduced, status); -- return pendingNetResult != null ? pendingNetResult : -- new SSLEngineResult(getEngineStatus(), -- NEED_UNWRAP, bytesConsumed, bytesProduced); -- case SSL.SSL_ERROR_WANT_WRITE: -- // SSL_ERROR_WANT_WRITE typically means that the underlying transport is not writable -- // and we should set the "want write" flag on the selector and try again when the -- // underlying transport is writable [1]. However we are not directly writing to the -- // underlying transport and instead writing to a BIO buffer. The OpenSsl documentation -- // says we should do the following [1]: -- // -- // "When using a buffering BIO, like a BIO pair, data must be written into or retrieved -- // out of the BIO before being able to continue." -- // -- // So we attempt to drain the BIO buffer below, but if there is no data this condition -- // is undefined and we assume their is a fatal error with the openssl engine and close. -- // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html -- pendingNetResult = readPendingBytesFromBIO(dst, bytesConsumed, bytesProduced, status); -- return pendingNetResult != null ? pendingNetResult : NEED_WRAP_CLOSED; -- default: -- // Everything else is considered as error -- throw shutdownWithError("SSL_write"); +- 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"); - } - } - } -- } -- // We need to check if pendingWrittenBytesInBIO was checked yet, as we may not checked if the srcs was -- // empty, or only contained empty buffers. -- if (bytesConsumed == 0) { -- SSLEngineResult pendingNetResult = readPendingBytesFromBIO(dst, 0, bytesProduced, status); -- if (pendingNetResult != null) { -- return pendingNetResult; +- return 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(); - } - } -- -- return newResult(bytesConsumed, bytesProduced, status); - } - } - +- 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. - */ @@ -3802,7 +4239,7 @@ index 6b28ca0..0000000 - - public final SSLEngineResult unwrap( - final ByteBuffer[] srcs, int srcsOffset, final int srcsLength, -- final ByteBuffer[] dsts, final int dstsOffset, final int dstsLength) throws SSLException { +- final ByteBuffer[] dsts, int dstsOffset, final int dstsLength) throws SSLException { - - // Throw required runtime exceptions - if (srcs == null) { @@ -3823,8 +4260,8 @@ index 6b28ca0..0000000 - " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))"); - } - long capacity = 0; -- final int endOffset = dstsOffset + dstsLength; -- for (int i = dstsOffset; i < endOffset; i ++) { +- 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"); @@ -3846,18 +4283,8 @@ index 6b28ca0..0000000 - } - - synchronized (this) { -- // Check to make sure the engine has not been closed -- if (isDestroyed()) { -- return CLOSED_NOT_HANDSHAKING; -- } -- -- // protect against protocol overflow attack vector -- if (len > MAX_ENCRYPTED_PACKET_LENGTH) { -- isInboundDone = true; -- isOutboundDone = true; -- engineClosed = true; -- shutdown(); -- throw ENCRYPTED_PACKET_OVERSIZED; +- if (isInboundDone()) { +- return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_WRAP_CLOSED; - } - - SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING; @@ -3872,108 +4299,123 @@ index 6b28ca0..0000000 - if (status == NEED_WRAP) { - return NEED_WRAP_OK; - } -- if (engineClosed) { +- // Check if the inbound is considered to be closed if so let us try to wrap again. +- if (isInboundDone) { - return NEED_WRAP_CLOSED; - } - } - -- // Write encrypted data to network BIO +- 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; -- if (srcsOffset < srcsEndOffset) { -- do { +- 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. -- srcsOffset++; - continue; - } -- int written = writeEncryptedData(src); -- if (written > 0) { -- bytesConsumed += written; +- // 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; +- } - -- if (written == remaining) { -- srcsOffset++; -- } else { -- // We were not able to write everything into the BIO so break the write loop as otherwise -- // we will produce an error on the next write attempt, which will trigger a SSL.clearError() -- // later. +- 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; - } -- } else { -- // BIO_write returned a negative or zero number, this means we could not complete the write -- // operation and should retry later. -- // We ignore BIO_* errors here as we use in memory BIO anyway and will do another SSL_* call -- // later on in which we will produce an exception in case of an error -- SSL.clearError(); -- break; -- } -- } while (srcsOffset < srcsEndOffset); -- } -- -- // Number of produced bytes -- int bytesProduced = 0; -- -- if (capacity > 0) { -- // Write decrypted data to dsts buffers -- int idx = dstsOffset; -- while (idx < endOffset) { -- ByteBuffer dst = dsts[idx]; -- if (!dst.hasRemaining()) { -- idx++; -- continue; -- } -- -- int bytesRead = readPlaintextData(dst); -- -- // TODO: We may want to consider if we move this check and only do it in a less often called place -- // at the price of not being 100% accurate, like for example when calling SSL.getError(...). -- rejectRemoteInitiatedRenegation(); -- -- if (bytesRead > 0) { -- bytesProduced += bytesRead; -- -- if (!dst.hasRemaining()) { -- idx++; -- } else { -- // We read everything return now. -- return newResult(bytesConsumed, bytesProduced, status); -- } -- } else { -- int sslError = SSL.getError(ssl, bytesRead); -- switch (sslError) { -- case SSL.SSL_ERROR_ZERO_RETURN: -- // This means the connection was shutdown correctly, close inbound and outbound -- if (!receivedShutdown) { -- closeAll(); -- } -- // fall-trough! -- case SSL.SSL_ERROR_WANT_READ: -- case SSL.SSL_ERROR_WANT_WRITE: -- // break to the outer loop -- return newResult(bytesConsumed, bytesProduced, status); -- default: -- return sslReadErrorResult(SSL.getLastErrorNumber(), bytesConsumed, bytesProduced); +- } finally { +- if (bioWriteCopyBuf != null) { +- bioWriteCopyBuf.release(); - } - } - } -- } else { -- // If the capacity of all destination buffers is 0 we need to trigger a SSL_read anyway to ensure -- // everything is flushed in the BIO pair and so we can detect it in the pendingAppData() call. -- if (SSL.readFromSSL(ssl, EMPTY_ADDR, 0) <= 0) { -- // We do not check SSL_get_error as we are not interested in any error that is not fatal. -- int err = SSL.getLastErrorNumber(); -- if (OpenSsl.isError(err)) { -- return sslReadErrorResult(err, bytesConsumed, bytesProduced); -- } -- } -- } -- if (pendingAppData() > 0) { -- // We filled all buffers but there is still some data pending in the BIO buffer, return BUFFER_OVERFLOW. -- return new SSLEngineResult( -- BUFFER_OVERFLOW, mayFinishHandshake(status != FINISHED ? getHandshakeStatus() : status), -- bytesConsumed, bytesProduced); +- } finally { +- SSL.bioClearByteBuffer(networkBIO); +- rejectRemoteInitiatedRenegotiation(); - } - - // Check to see if we received a close_notify message from the peer. @@ -3981,7 +4423,7 @@ index 6b28ca0..0000000 - closeAll(); - } - -- return newResult(bytesConsumed, bytesProduced, status); +- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced); - } - } - @@ -3992,7 +4434,7 @@ index 6b28ca0..0000000 - // BIO first or can just shutdown and throw it now. - // This is needed so we ensure close_notify etc is correctly send to the remote peer. - // See https://github.com/netty/netty/issues/3900 -- if (SSL.pendingWrittenBytesInBIO(networkBIO) > 0) { +- if (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. @@ -4003,31 +4445,18 @@ index 6b28ca0..0000000 - throw shutdownWithError("SSL_read", errStr); - } - -- private int pendingAppData() { -- // There won't be any application data until we're done handshaking. -- // We first check handshakeFinished to eliminate the overhead of extra JNI call if possible. -- return handshakeState == HandshakeState.FINISHED ? SSL.pendingReadableBytesInSSL(ssl) : 0; -- } -- -- private SSLEngineResult newResult( -- int bytesConsumed, int bytesProduced, SSLEngineResult.HandshakeStatus status) throws SSLException { -- return new SSLEngineResult( -- getEngineStatus(), mayFinishHandshake(status != FINISHED ? getHandshakeStatus() : status) -- , bytesConsumed, bytesProduced); -- } -- - private void closeAll() throws SSLException { - receivedShutdown = true; - closeOutbound(); - closeInbound(); - } - -- private void rejectRemoteInitiatedRenegation() throws SSLHandshakeException { -- if (rejectRemoteInitiatedRenegation && SSL.getHandshakeCount(ssl) > 1) { +- 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 renegotation not allowed"); +- throw new SSLHandshakeException("remote-initiated renegotiation not allowed"); - } - } - @@ -4106,9 +4535,12 @@ index 6b28ca0..0000000 - } - - isInboundDone = true; -- engineClosed = true; - -- shutdown(); +- 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( @@ -4118,47 +4550,21 @@ index 6b28ca0..0000000 - - @Override - public final synchronized boolean isInboundDone() { -- return isInboundDone || engineClosed; +- return isInboundDone; - } - - @Override - public final synchronized void closeOutbound() { -- if (isOutboundDone) { +- if (outboundClosed) { - return; - } - -- isOutboundDone = true; -- engineClosed = true; +- outboundClosed = true; - - if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) { - int mode = SSL.getShutdown(ssl); - if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) { -- int err = SSL.shutdownSSL(ssl); -- if (err < 0) { -- int sslErr = SSL.getError(ssl, err); -- switch (sslErr) { -- case SSL.SSL_ERROR_NONE: -- case SSL.SSL_ERROR_WANT_ACCEPT: -- case SSL.SSL_ERROR_WANT_CONNECT: -- case SSL.SSL_ERROR_WANT_WRITE: -- case SSL.SSL_ERROR_WANT_READ: -- case SSL.SSL_ERROR_WANT_X509_LOOKUP: -- case SSL.SSL_ERROR_ZERO_RETURN: -- // Nothing to do here -- break; -- case SSL.SSL_ERROR_SYSCALL: -- case SSL.SSL_ERROR_SSL: -- if (logger.isDebugEnabled()) { -- logger.debug("SSL_shutdown failed: OpenSSL error: {}", SSL.getLastError()); -- } -- // There was an internal error -- shutdown -- shutdown(); -- break; -- default: -- SSL.clearError(); -- break; -- } -- } +- doSSLShutdown(); - } - } else { - // engine closing before initial handshake @@ -4166,9 +4572,39 @@ index 6b28ca0..0000000 - } - } - +- /** +- * 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() { -- return 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 @@ -4251,8 +4687,8 @@ index 6b28ca0..0000000 - - @Override - public final String[] getEnabledProtocols() { -- List enabled = InternalThreadLocalMap.get().arrayList(); -- // Seems like there is no way to explict disable SSLv2Hello in openssl so it is always enabled +- 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; @@ -4263,24 +4699,30 @@ index 6b28ca0..0000000 - return enabled.toArray(new String[1]); - } - } -- if ((opts & SSL.SSL_OP_NO_TLSv1) == 0) { +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, OpenSsl.PROTOCOL_TLS_V1)) { - enabled.add(OpenSsl.PROTOCOL_TLS_V1); - } -- if ((opts & SSL.SSL_OP_NO_TLSv1_1) == 0) { +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, OpenSsl.PROTOCOL_TLS_V1_1)) { - enabled.add(OpenSsl.PROTOCOL_TLS_V1_1); - } -- if ((opts & SSL.SSL_OP_NO_TLSv1_2) == 0) { +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, OpenSsl.PROTOCOL_TLS_V1_2)) { - enabled.add(OpenSsl.PROTOCOL_TLS_V1_2); - } -- if ((opts & SSL.SSL_OP_NO_SSLv2) == 0) { +- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, OpenSsl.PROTOCOL_SSL_V2)) { - enabled.add(OpenSsl.PROTOCOL_SSL_V2); - } -- if ((opts & SSL.SSL_OP_NO_SSLv3) == 0) { +- 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) { @@ -4310,9 +4752,6 @@ index 6b28ca0..0000000 - } - synchronized (this) { - if (!isDestroyed()) { -- // Enable all and then disable what we not want -- SSL.setOptions(ssl, SSL.SSL_OP_ALL); -- - // Clear out options which disable protocols - SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 | - SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2); @@ -4377,14 +4816,25 @@ index 6b28ca0..0000000 - // ssl->state = SSL_ST_ACCEPT - // SSL_do_handshake(ssl) - // -- // Bcause of this we fall-through to call handshake() after setting the state, as this will also take +- // 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 -- if (SSL.renegotiate(ssl) != 1 || SSL.doHandshake(ssl) != 1) { -- throw shutdownWithError("renegotiation failed"); +- 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); @@ -4402,7 +4852,7 @@ index 6b28ca0..0000000 - } - - private void checkEngineClosed(SSLException cause) throws SSLException { -- if (engineClosed || isDestroyed()) { +- if (isDestroyed()) { - throw cause; - } - } @@ -4412,6 +4862,14 @@ index 6b28ca0..0000000 - 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; @@ -4424,8 +4882,8 @@ index 6b28ca0..0000000 - // See https://github.com/netty/netty/issues/3900 - SSLHandshakeException exception = handshakeException; - if (exception != null) { -- if (SSL.pendingWrittenBytesInBIO(networkBIO) > 0) { -- // There is something pending, we need to consume it first via a WRAP so we not loose anything. +- 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 @@ -4458,14 +4916,11 @@ index 6b28ca0..0000000 - } - - int sslError = SSL.getError(ssl, code); -- -- switch (sslError) { -- case SSL.SSL_ERROR_WANT_READ: -- case SSL.SSL_ERROR_WANT_WRITE: -- return pendingStatus(SSL.pendingWrittenBytesInBIO(networkBIO)); -- default: -- // Everything else is considered as error -- throw shutdownWithError("SSL_do_handshake"); +- if (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. @@ -4474,10 +4929,6 @@ index 6b28ca0..0000000 - return FINISHED; - } - -- private SSLEngineResult.Status getEngineStatus() { -- return engineClosed? CLOSED : OK; -- } -- - private SSLEngineResult.HandshakeStatus mayFinishHandshake(SSLEngineResult.HandshakeStatus status) - throws SSLException { - if (status == NOT_HANDSHAKING && handshakeState != HandshakeState.FINISHED) { @@ -4491,7 +4942,7 @@ index 6b28ca0..0000000 - @Override - public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() { - // Check if we are in the initial handshake phase or shutdown phase -- return needPendingStatus() ? pendingStatus(SSL.pendingWrittenBytesInBIO(networkBIO)) : NOT_HANDSHAKING; +- return needPendingStatus() ? pendingStatus(SSL.bioLengthNonApplication(networkBIO)) : NOT_HANDSHAKING; - } - - private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) { @@ -4501,7 +4952,7 @@ index 6b28ca0..0000000 - - private boolean needPendingStatus() { - return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed() -- && (handshakeState != HandshakeState.FINISHED || engineClosed); +- && (handshakeState != HandshakeState.FINISHED || isInboundDone() || isOutboundDone()); - } - - /** @@ -4521,7 +4972,7 @@ index 6b28ca0..0000000 - */ - private static String toJavaCipherSuitePrefix(String protocolVersion) { - final char c; -- if (protocolVersion == null || protocolVersion.length() == 0) { +- if (protocolVersion == null || protocolVersion.isEmpty()) { - c = 0; - } else { - c = protocolVersion.charAt(0); @@ -4569,6 +5020,15 @@ index 6b28ca0..0000000 - 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; @@ -4580,13 +5040,13 @@ index 6b28ca0..0000000 - } - switch (mode) { - case NONE: -- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, OpenSslContext.VERIFY_DEPTH); +- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, ReferenceCountedOpenSslContext.VERIFY_DEPTH); - break; - case REQUIRE: -- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRE, OpenSslContext.VERIFY_DEPTH); +- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, ReferenceCountedOpenSslContext.VERIFY_DEPTH); - break; - case OPTIONAL: -- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, OpenSslContext.VERIFY_DEPTH); +- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, ReferenceCountedOpenSslContext.VERIFY_DEPTH); - break; - default: - throw new Error(mode.toString()); @@ -4614,27 +5074,17 @@ index 6b28ca0..0000000 - int version = PlatformDependent.javaVersion(); - if (version >= 7) { - sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm); -- SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints); +- Java7SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints); - if (version >= 8) { -- if (SET_SERVER_NAMES_METHOD != null && sniHostNames != null) { -- try { -- SET_SERVER_NAMES_METHOD.invoke(sslParameters, sniHostNames); -- } catch (IllegalAccessException e) { -- throw new Error(e); -- } catch (InvocationTargetException e) { -- throw new Error(e); -- } +- if (sniHostNames != null) { +- Java8SslUtils.setSniHostNames(sslParameters, sniHostNames); - } -- if (SET_USE_CIPHER_SUITES_ORDER_METHOD != null && !isDestroyed()) { -- try { -- SET_USE_CIPHER_SUITES_ORDER_METHOD.invoke(sslParameters, -- (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0); -- } catch (IllegalAccessException e) { -- throw new Error(e); -- } catch (InvocationTargetException e) { -- throw new Error(e); -- } +- if (!isDestroyed()) { +- Java8SslUtils.setUseCipherSuitesOrder( +- sslParameters, (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0); - } +- +- Java8SslUtils.setSNIMatchers(sslParameters, matchers); - } - } - return sslParameters; @@ -4642,66 +5092,69 @@ index 6b28ca0..0000000 - - @Override - public final synchronized void setSSLParameters(SSLParameters sslParameters) { -- super.setSSLParameters(sslParameters); -- - int version = PlatformDependent.javaVersion(); - if (version >= 7) { -- endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm(); -- algorithmConstraints = sslParameters.getAlgorithmConstraints(); -- if (version >= 8) { -- if (SNI_HOSTNAME_CLASS != null && clientMode && !isDestroyed()) { -- assert GET_SERVER_NAMES_METHOD != null; -- assert GET_ASCII_NAME_METHOD != null; -- try { -- List servernames = (List) GET_SERVER_NAMES_METHOD.invoke(sslParameters); -- if (servernames != null) { -- for (Object serverName : servernames) { -- if (SNI_HOSTNAME_CLASS.isInstance(serverName)) { -- SSL.setTlsExtHostName(ssl, (String) GET_ASCII_NAME_METHOD.invoke(serverName)); -- } else { -- throw new IllegalArgumentException("Only " + SNI_HOSTNAME_CLASS.getName() -- + " instances are supported, but found: " + -- serverName); -- } -- } -- } -- sniHostNames = servernames; -- } catch (IllegalAccessException e) { -- throw new Error(e); -- } catch (InvocationTargetException e) { -- throw new Error(e); -- } -- } -- if (GET_USE_CIPHER_SUITES_ORDER_METHOD != null && !isDestroyed()) { -- try { -- if ((Boolean) GET_USE_CIPHER_SUITES_ORDER_METHOD.invoke(sslParameters)) { -- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); -- } else { -- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); -- } -- } catch (IllegalAccessException e) { -- throw new Error(e); -- } catch (InvocationTargetException e) { -- throw new Error(e); -- } -- } +- 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 Certificate[] peerCerts; - private String cipher; - private byte[] id; - private long creationTime; @@ -4851,51 +5304,45 @@ index 6b28ca0..0000000 - private void initPeerCerts() { - // Return the full chain from the JNI layer. - byte[][] chain = SSL.getPeerCertChain(ssl); -- final byte[] clientCert; -- if (!clientMode) { +- 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 -- clientCert = SSL.getPeerCertificate(ssl); -- } else { -- clientCert = null; -- } -- -- if (chain == null || chain.length == 0) { -- if (clientCert == null || clientCert.length == 0) { -- peerCerts = EmptyArrays.EMPTY_CERTIFICATES; -- x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES; +- byte[] clientCert = SSL.getPeerCertificate(ssl); +- if (isEmpty(clientCert)) { +- peerCerts = EMPTY_CERTIFICATES; +- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES; - } else { -- peerCerts = new Certificate[1]; -- x509PeerCerts = new X509Certificate[1]; -- -- peerCerts[0] = new OpenSslX509Certificate(clientCert); -- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert); +- 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); +- } - } -- } else if (clientCert == null || clientCert.length == 0) { -- peerCerts = new Certificate[chain.length]; -- x509PeerCerts = new X509Certificate[chain.length]; +- } +- } - -- for (int a = 0; a < chain.length; ++a) { -- byte[] bytes = chain[a]; -- peerCerts[a] = new OpenSslX509Certificate(bytes); -- x509PeerCerts[a] = new OpenSslJavaxX509Certificate(bytes); -- } -- } else { -- int len = clientCert.length + 1; -- peerCerts = new Certificate[len]; -- x509PeerCerts = new X509Certificate[len]; -- -- peerCerts[0] = new OpenSslX509Certificate(clientCert); -- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert); -- -- for (int a = 0, i = 1; a < chain.length; ++a, ++i) { -- byte[] bytes = chain[a]; -- peerCerts[i] = new OpenSslX509Certificate(bytes); -- x509PeerCerts[i] = new OpenSslJavaxX509Certificate(bytes); -- } +- 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]); - } - } - @@ -4963,7 +5410,7 @@ index 6b28ca0..0000000 - @Override - public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { - synchronized (ReferenceCountedOpenSslEngine.this) { -- if (peerCerts == null || peerCerts.length == 0) { +- if (isEmpty(peerCerts)) { - throw new SSLPeerUnverifiedException("peer not verified"); - } - return peerCerts.clone(); @@ -4981,7 +5428,7 @@ index 6b28ca0..0000000 - @Override - public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { - synchronized (ReferenceCountedOpenSslEngine.this) { -- if (x509PeerCerts == null || x509PeerCerts.length == 0) { +- if (isEmpty(x509PeerCerts)) { - throw new SSLPeerUnverifiedException("peer not verified"); - } - return x509PeerCerts.clone(); @@ -5058,13 +5505,12 @@ index 6b28ca0..0000000 - } - } -} -- diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java deleted file mode 100644 -index ace2153..0000000 +index 4c9df31..0000000 --- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java +++ /dev/null -@@ -1,195 +0,0 @@ +@@ -1,239 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * @@ -5082,13 +5528,16 @@ index ace2153..0000000 - */ -package io.netty.handler.ssl; - --import org.apache.tomcat.jni.SSL; --import org.apache.tomcat.jni.SSLContext; +-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; @@ -5108,6 +5557,8 @@ index ace2153..0000000 - * {@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; @@ -5116,18 +5567,21 @@ index ace2153..0000000 - X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, - X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, - Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, -- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, boolean startTls) throws SSLException { +- 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, startTls); +- 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, boolean startTls) throws SSLException { +- 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, startTls, true); +- clientAuth, protocols, startTls, enableOcsp, true); - // Create a new SSL_CTX and configure it. - boolean success = false; - try { @@ -5165,64 +5619,82 @@ index ace2153..0000000 - String keyPassword, KeyManagerFactory keyManagerFactory) - throws SSLException { - ServerContext result = new ServerContext(); -- synchronized (ReferenceCountedOpenSslContext.class) { -- try { -- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); -- if (!OpenSsl.useKeyManagerFactory()) { -- if (keyManagerFactory != null) { -- throw new IllegalArgumentException( -- "KeyManagerFactory not supported"); -- } -- checkNotNull(keyCertChain, "keyCertChain"); -- -- /* Set certificate verification policy. */ -- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); -- -- setKeyMaterial(ctx, keyCertChain, key, keyPassword); -- } else { -- // javadocs state that keyManagerFactory has precedent over keyCertChain, and we must have a -- // keyManagerFactory for the server so build one if it is not specified. -- if (keyManagerFactory == null) { -- keyManagerFactory = buildKeyManagerFactory( -- keyCertChain, key, keyPassword, keyManagerFactory); -- } -- X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers()); -- result.keyMaterialManager = useExtendedKeyManager(keyManager) ? -- new OpenSslExtendedKeyMaterialManager( -- (X509ExtendedKeyManager) keyManager, keyPassword) : -- new OpenSslKeyMaterialManager(keyManager, keyPassword); +- try { +- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH); +- if (!OpenSsl.useKeyManagerFactory()) { +- if (keyManagerFactory != null) { +- throw new IllegalArgumentException( +- "KeyManagerFactory not supported"); - } -- } catch (Exception e) { -- throw new SSLException("failed to set certificate and key", e); +- 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); - } -- 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); +- } 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); - } +- } - -- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); -- -- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as +- 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 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); +- // 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); @@ -5259,12 +5731,30 @@ index ace2153..0000000 - 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 9a40d92..b76e4af 100644 +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 -@@ -114,11 +114,7 @@ public abstract class SslContext { +@@ -115,11 +115,7 @@ public abstract class SslContext { } private static SslProvider defaultProvider() { @@ -5273,142 +5763,240 @@ index 9a40d92..b76e4af 100644 - } else { - return SslProvider.JDK; - } -+ return SslProvider.JDK; ++ return SslProvider.JDK; } /** -@@ -410,16 +406,6 @@ public abstract class SslContext { +@@ -416,18 +412,6 @@ public abstract class SslContext { trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, - clientAuth, startTls); + clientAuth, protocols, startTls); - case OPENSSL: +- verifyNullSslContextProvider(provider, sslContextProvider); - return new OpenSslServerContext( - trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, - keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, -- clientAuth, startTls); +- 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, startTls); +- clientAuth, protocols, startTls, enableOcsp); default: throw new Error(provider.toString()); } -@@ -751,14 +737,6 @@ public abstract class SslContext { - return new JdkSslClientContext( +@@ -770,18 +754,6 @@ public abstract class SslContext { + return new JdkSslClientContext(sslContextProvider, trustCert, trustManagerFactory, keyCertChain, key, keyPassword, - keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); + keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout); - case OPENSSL: +- verifyNullSslContextProvider(provider, sslContextProvider); - return new OpenSslClientContext( - trustCert, trustManagerFactory, keyCertChain, key, keyPassword, -- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); +- 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, sessionCacheSize, sessionTimeout); +- 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 55c09ae..a9cb9ae 100644 +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,14 @@ import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength; +@@ -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 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(...)"); -@@ -281,7 +289,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - this.startTls = startTls; - maxPacketBufferSize = engine.getSession().getPacketBufferSize(); + 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 + }; -- boolean opensslEngine = engine instanceof OpenSslEngine; -+ boolean opensslEngine = false; - wantsDirectBuffer = opensslEngine; - wantsLargeOutboundNetworkBuffer = !opensslEngine; - -@@ -415,9 +423,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - // Check if queue is not empty first because create a new ChannelException is expensive - pendingUnencryptedWrites.removeAndFailAll(new ChannelException("Pending write on removal of SslHandler")); - } -- if (engine instanceof ReferenceCountedOpenSslEngine) { -- ((ReferenceCountedOpenSslEngine) engine).release(); -- } - } - - @Override -@@ -853,7 +858,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + 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 < OpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { +- 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; -@@ -874,7 +879,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH +@@ -1055,7 +1024,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH } int newTotalLength = totalLength + packetLength; -- if (newTotalLength > OpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { +- if (newTotalLength > ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) { + if (newTotalLength > MAX_ENCRYPTED_PACKET_LENGTH) { // Don't read too much. break; } -@@ -1076,27 +1081,10 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - - private SSLEngineResult unwrap( - SSLEngine engine, ByteBuf in, int readerIndex, int len, ByteBuf out) throws SSLException { -- int nioBufferCount = in.nioBufferCount(); - int writerIndex = out.writerIndex(); - final SSLEngineResult result; -- if (engine instanceof OpenSslEngine && nioBufferCount > 1) { -- /** -- * If {@link OpenSslEngine} is in use, -- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method -- * that accepts multiple {@link ByteBuffer}s without additional memory copies. -- */ -- OpenSslEngine opensslEngine = (OpenSslEngine) engine; -- try { -- singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes()); -- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), singleBuffer); -- out.writerIndex(writerIndex + result.bytesProduced()); -- } finally { -- singleBuffer[0] = null; +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; - } -- } else { -- result = engine.unwrap(toByteBuffer(in, readerIndex, len), -+ result = engine.unwrap(toByteBuffer(in, readerIndex, len), - toByteBuffer(out, writerIndex, out.writableBytes())); - } - out.writerIndex(writerIndex + result.bytesProduced()); - return result; - } -@@ -1482,7 +1470,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH - return allocate(ctx, maxPacketBufferSize); - } else { - return allocate(ctx, Math.min( -- pendingBytes + OpenSslEngine.MAX_ENCRYPTION_OVERHEAD_LENGTH, -+ pendingBytes + MAX_ENCRYPTION_OVERHEAD_LENGTH, - maxPacketBufferSize)); - } - } +- +- 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 381df73..0000000 +index d696d6b..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java +++ /dev/null -@@ -1,37 +0,0 @@ +@@ -1,108 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * @@ -5427,10 +6015,34 @@ index 381df73..0000000 -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()); @@ -5445,6 +6057,108 @@ index 381df73..0000000 - 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 @@ -5492,10 +6206,10 @@ index 6011cf7..0000000 -} diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java deleted file mode 100644 -index 2ef0a6c..0000000 +index 5939b66..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java +++ /dev/null -@@ -1,129 +0,0 @@ +@@ -1,661 +0,0 @@ -/* - * Copyright 2015 The Netty Project - * @@ -5519,28 +6233,112 @@ index 2ef0a6c..0000000 -import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import io.netty.handler.ssl.util.SelfSignedCertificate; --import io.netty.util.internal.ThreadLocalRandom; +-import 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, @@ -5576,7 +6374,7 @@ index 2ef0a6c..0000000 - new String[]{PROTOCOL_SSL_V2_HELLO, PROTOCOL_TLS_V1_2}); - } - @Test -- public void testWrapHeapBuffersNoWritePendingError() throws Exception { +- public void testWrapBuffersNoWritePendingError() throws Exception { - clientSslCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .sslProvider(sslClientProvider()) @@ -5592,9 +6390,11 @@ index 2ef0a6c..0000000 - serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); - handshake(clientEngine, serverEngine); - -- ByteBuffer src = ByteBuffer.allocate(1024 * 10); -- ThreadLocalRandom.current().nextBytes(src.array()); -- ByteBuffer dst = ByteBuffer.allocate(1); +- 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); @@ -5607,6 +6407,452 @@ index 2ef0a6c..0000000 - } - } - +- @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; @@ -5627,10 +6873,10 @@ index 2ef0a6c..0000000 -} diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java deleted file mode 100644 -index 9954f69..0000000 +index f63a16f..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java +++ /dev/null -@@ -1,38 +0,0 @@ +@@ -1,114 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * @@ -5649,11 +6895,36 @@ index 9954f69..0000000 -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()); @@ -5668,6 +6939,86 @@ index 9954f69..0000000 - 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 @@ -5756,6 +7107,39 @@ index f22d045..0000000 - 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 @@ -5859,10 +7243,10 @@ index 793f772..0000000 -} diff --git a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java deleted file mode 100644 -index 40b3193..0000000 +index 6d38940..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java +++ /dev/null -@@ -1,52 +0,0 @@ +@@ -1,57 +0,0 @@ -/* - * Copyright 2016 The Netty Project - * @@ -5885,6 +7269,11 @@ index 40b3193..0000000 -import javax.net.ssl.SSLEngine; - -public class ReferenceCountedOpenSslEngineTest extends OpenSslEngineTest { +- +- public ReferenceCountedOpenSslEngineTest(BufferType type) { +- super(type); +- } +- - @Override - protected SslProvider sslClientProvider() { - return SslProvider.OPENSSL_REFCNT; @@ -5916,89 +7305,1079 @@ index 40b3193..0000000 - } -} diff --git a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java -index 1ad3c56..2bb510d 100644 +deleted file mode 100644 +index 3193d20..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java -+++ b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java -@@ -40,24 +40,6 @@ public class SniClientTest { - testSniClient(SslProvider.JDK, SslProvider.JDK); - } - -- @Test(timeout = 5000) ++++ /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 = 5000) +- @Test(timeout = 30000) - public void testSniClientJdkSslServerOpenSsl() throws Exception { - Assume.assumeTrue(OpenSsl.isAvailable()); - testSniClient(SslProvider.JDK, SslProvider.OPENSSL); - } - -- @Test(timeout = 5000) +- @Test(timeout = 30000) - public void testSniClientOpenSslServerJdkSsl() throws Exception { - Assume.assumeTrue(OpenSsl.isAvailable()); - testSniClient(SslProvider.OPENSSL, SslProvider.JDK); - } - - @SuppressWarnings("deprecation") - private static void testSniClient(SslProvider sslClientProvider, SslProvider sslServerProvider) throws Exception { - final String sniHost = "sni.netty.io"; +- @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 -index 752424c..4cd3c76 100644 +deleted file mode 100644 +index 752424c..0000000 --- a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java -+++ b/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java -@@ -33,44 +33,20 @@ public class SslContextBuilderTest { - } - - @Test ++++ /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 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 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); - } - +- 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() +- 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 7d50460..ddcf3bd 100644 +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 -@@ -94,34 +94,6 @@ public class SslHandlerTest { - ch.writeOutbound(new Object()); +@@ -121,35 +121,6 @@ public class SslHandlerTest { + } } - @Test @@ -6017,6 +8396,7 @@ index 7d50460..ddcf3bd 100644 - assertEquals(1, ((ReferenceCounted) sslContext).refCnt()); - assertEquals(1, ((ReferenceCounted) sslEngine).refCnt()); - +- assertTrue(ch.finishAndReleaseAll()); - ch.close().syncUninterruptibly(); - - assertEquals(1, ((ReferenceCounted) sslContext).refCnt()); @@ -6032,6 +8412,574 @@ index 7d50460..ddcf3bd 100644 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.7.4 +2.9.4 diff --git a/0002-Remove-NPN.patch b/0002-Remove-NPN.patch new file mode 100644 index 0000000..77a340a --- /dev/null +++ b/0002-Remove-NPN.patch @@ -0,0 +1,353 @@ +From f7b8e27b5f55c4a21cf84fb56a616b8bfd4af8da Mon Sep 17 00:00:00 2001 +From: Michael Simacek +Date: Fri, 7 Jul 2017 16:07:23 +0200 +Subject: [PATCH 2/3] Remove NPN + +--- + handler/pom.xml | 5 - + .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 -------------------- + .../java/io/netty/handler/ssl/JdkSslContext.java | 30 ----- + .../io/netty/handler/ssl/JettyNpnSslEngine.java | 122 --------------------- + .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +- + 5 files changed, 1 insertion(+), 278 deletions(-) + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java + +diff --git a/handler/pom.xml b/handler/pom.xml +index d0ed1bc..52e63ca 100644 +--- a/handler/pom.xml ++++ b/handler/pom.xml +@@ -55,11 +55,6 @@ + true + + +- org.eclipse.jetty.npn +- npn-api +- true +- +- + org.eclipse.jetty.alpn + alpn-api + true +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java +deleted file mode 100644 +index 06b29b7..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java ++++ /dev/null +@@ -1,120 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import javax.net.ssl.SSLEngine; +- +-/** +- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}. +- */ +-public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { +- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() { +- { +- if (!JettyNpnSslEngine.isAvailable()) { +- throw new RuntimeException("NPN unsupported. Is your classpath configured correctly?" +- + " See https://wiki.eclipse.org/Jetty/Feature/NPN"); +- } +- } +- +- @Override +- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, +- boolean isServer) { +- return new JettyNpnSslEngine(engine, applicationNegotiator, isServer); +- } +- }; +- +- /** +- * Create a new instance. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(Iterable protocols) { +- this(false, protocols); +- } +- +- /** +- * Create a new instance. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(String... protocols) { +- this(false, protocols); +- } +- +- /** +- * Create a new instance. +- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable protocols) { +- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); +- } +- +- /** +- * Create a new instance. +- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) { +- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols); +- } +- +- /** +- * Create a new instance. +- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. +- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, +- boolean serverFailIfNoCommonProtocols, Iterable protocols) { +- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, +- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, +- protocols); +- } +- +- /** +- * Create a new instance. +- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected. +- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols, +- boolean serverFailIfNoCommonProtocols, String... protocols) { +- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY, +- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY, +- protocols); +- } +- +- /** +- * Create a new instance. +- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. +- * @param listenerFactory The factory which provides to be notified of which protocol was selected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, +- ProtocolSelectionListenerFactory listenerFactory, Iterable protocols) { +- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols); +- } +- +- /** +- * Create a new instance. +- * @param selectorFactory The factory which provides classes responsible for selecting the protocol. +- * @param listenerFactory The factory which provides to be notified of which protocol was selected. +- * @param protocols The order of iteration determines the preference of support for protocols. +- */ +- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory, +- ProtocolSelectionListenerFactory listenerFactory, String... protocols) { +- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols); +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java +index 0ad6639..d5b86ff 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java ++++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java +@@ -288,47 +288,17 @@ public class JdkSslContext extends SslContext { + case ALPN: + if (isServer) { + switch(config.selectorFailureBehavior()) { +- case FATAL_ALERT: +- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); +- case NO_ADVERTISE: +- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); + default: + throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") + .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); + } + } else { + switch(config.selectedListenerFailureBehavior()) { +- case ACCEPT: +- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); +- case FATAL_ALERT: +- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); + default: + throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") + .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); + } + } +- case NPN: +- if (isServer) { +- switch(config.selectedListenerFailureBehavior()) { +- case ACCEPT: +- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); +- case FATAL_ALERT: +- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); +- default: +- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") +- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); +- } +- } else { +- switch(config.selectorFailureBehavior()) { +- case FATAL_ALERT: +- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols()); +- case NO_ADVERTISE: +- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols()); +- default: +- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") +- .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); +- } +- } + default: + throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") + .append(config.protocol()).append(" protocol").toString()); +diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java +deleted file mode 100644 +index 77e7366..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java ++++ /dev/null +@@ -1,122 +0,0 @@ +-/* +- * Copyright 2014 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-package io.netty.handler.ssl; +- +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +-import io.netty.util.internal.PlatformDependent; +- +-import java.util.LinkedHashSet; +-import java.util.List; +- +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLException; +- +-import org.eclipse.jetty.npn.NextProtoNego; +-import org.eclipse.jetty.npn.NextProtoNego.ClientProvider; +-import org.eclipse.jetty.npn.NextProtoNego.ServerProvider; +- +-final class JettyNpnSslEngine extends JdkSslEngine { +- private static boolean available; +- +- static boolean isAvailable() { +- updateAvailability(); +- return available; +- } +- +- private static void updateAvailability() { +- if (available) { +- return; +- } +- try { +- // Always use bootstrap class loader. +- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null); +- available = true; +- } catch (Exception ignore) { +- // npn-boot was not loaded. +- } +- } +- +- JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) { +- super(engine); +- checkNotNull(applicationNegotiator, "applicationNegotiator"); +- +- if (server) { +- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator +- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), +- "protocolListener"); +- NextProtoNego.put(engine, new ServerProvider() { +- @Override +- public void unsupported() { +- protocolListener.unsupported(); +- } +- +- @Override +- public List protocols() { +- return applicationNegotiator.protocols(); +- } +- +- @Override +- public void protocolSelected(String protocol) { +- try { +- protocolListener.selected(protocol); +- } catch (Throwable t) { +- PlatformDependent.throwException(t); +- } +- } +- }); +- } else { +- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() +- .newSelector(this, new LinkedHashSet(applicationNegotiator.protocols())), +- "protocolSelector"); +- NextProtoNego.put(engine, new ClientProvider() { +- @Override +- public boolean supports() { +- return true; +- } +- +- @Override +- public void unsupported() { +- protocolSelector.unsupported(); +- } +- +- @Override +- public String selectProtocol(List protocols) { +- try { +- return protocolSelector.select(protocols); +- } catch (Throwable t) { +- PlatformDependent.throwException(t); +- return null; +- } +- } +- }); +- } +- } +- +- @Override +- public void closeInbound() throws SSLException { +- NextProtoNego.remove(getWrappedEngine()); +- super.closeInbound(); +- } +- +- @Override +- public void closeOutbound() { +- NextProtoNego.remove(getWrappedEngine()); +- super.closeOutbound(); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +index d6cd94d..4489b16 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java ++++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +@@ -46,7 +46,7 @@ public class JdkSslEngineTest extends SSLEngineTest { + NPN_DEFAULT { + @Override + boolean isAvailable() { +- return JettyNpnSslEngine.isAvailable(); ++ return false; + } + + @Override +-- +2.9.4 + diff --git a/0003-Remove-conscrypt-ALPN.patch b/0003-Remove-conscrypt-ALPN.patch new file mode 100644 index 0000000..e71ba5a --- /dev/null +++ b/0003-Remove-conscrypt-ALPN.patch @@ -0,0 +1,511 @@ +From 039534e20546221c3466d1ceb663625c59edb0e7 Mon Sep 17 00:00:00 2001 +From: Michael Simacek +Date: Tue, 11 Jul 2017 13:37:22 +0200 +Subject: [PATCH 3/3] Remove conscrypt ALPN + +--- + handler/pom.xml | 6 - + .../netty/handler/ssl/ConscryptAlpnSslEngine.java | 176 --------------------- + .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 6 +- + .../main/java/io/netty/handler/ssl/SslHandler.java | 35 ---- + .../ssl/ConscryptJdkSslEngineInteropTest.java | 76 --------- + .../io/netty/handler/ssl/Java8SslTestUtils.java | 7 - + .../ssl/JdkConscryptSslEngineInteropTest.java | 86 ---------- + .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +- + 8 files changed, 2 insertions(+), 392 deletions(-) + delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java + delete mode 100644 handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java + +diff --git a/handler/pom.xml b/handler/pom.xml +index 52e63ca..69af32a 100644 +--- a/handler/pom.xml ++++ b/handler/pom.xml +@@ -60,12 +60,6 @@ + true + + +- ${conscrypt.groupId} +- ${conscrypt.artifactId} +- ${conscrypt.classifier} +- true +- +- + org.mockito + mockito-core + +diff --git a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java +deleted file mode 100644 +index 8e7a544..0000000 +--- a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java ++++ /dev/null +@@ -1,176 +0,0 @@ +-/* +- * Copyright 2017 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException; +-import static io.netty.util.internal.ObjectUtil.checkNotNull; +-import static java.lang.Math.min; +- +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; +-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; +-import java.lang.reflect.Method; +-import java.nio.ByteBuffer; +-import java.util.Collections; +-import java.util.LinkedHashSet; +-import java.util.List; +-import javax.net.ssl.SSLEngine; +-import javax.net.ssl.SSLEngineResult; +-import javax.net.ssl.SSLException; +- +-import io.netty.util.internal.PlatformDependent; +-import org.conscrypt.Conscrypt; +-import org.conscrypt.HandshakeListener; +- +-/** +- * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN. +- */ +-abstract class ConscryptAlpnSslEngine extends JdkSslEngine { +- private static final Class ENGINES_CLASS = getEnginesClass(); +- +- /** +- * Indicates whether or not conscrypt is available on the current system. +- */ +- static boolean isAvailable() { +- return ENGINES_CLASS != null && PlatformDependent.javaVersion() >= 8; +- } +- +- static boolean isEngineSupported(SSLEngine engine) { +- return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS); +- } +- +- static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- return new ClientEngine(engine, applicationNegotiator); +- } +- +- static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- return new ServerEngine(engine, applicationNegotiator); +- } +- +- private ConscryptAlpnSslEngine(SSLEngine engine, List protocols) { +- super(engine); +- +- // Set the list of supported ALPN protocols on the engine. +- Conscrypt.Engines.setAlpnProtocols(engine, protocols.toArray(new String[protocols.size()])); +- } +- +- /** +- * Calculates the maximum size of the encrypted output buffer required to wrap the given plaintext bytes. Assumes +- * as a worst case that there is one TLS record per buffer. +- * +- * @param plaintextBytes the number of plaintext bytes to be wrapped. +- * @param numBuffers the number of buffers that the plaintext bytes are spread across. +- * @return the maximum size of the encrypted output buffer required for the wrap operation. +- */ +- final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) { +- // Assuming a max of one frame per component in a composite buffer. +- long maxOverhead = (long) Conscrypt.Engines.maxSealOverhead(getWrappedEngine()) * numBuffers; +- // TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of Integer.MAX_VALUE +- return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead); +- } +- +- final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws SSLException { +- return Conscrypt.Engines.unwrap(getWrappedEngine(), srcs, dests); +- } +- +- private static final class ClientEngine extends ConscryptAlpnSslEngine { +- private final ProtocolSelectionListener protocolListener; +- +- ClientEngine(SSLEngine engine, +- JdkApplicationProtocolNegotiator applicationNegotiator) { +- super(engine, applicationNegotiator.protocols()); +- // Register for completion of the handshake. +- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() { +- @Override +- public void onHandshakeFinished() throws SSLException { +- selectProtocol(); +- } +- }); +- +- protocolListener = checkNotNull(applicationNegotiator +- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()), +- "protocolListener"); +- } +- +- private void selectProtocol() throws SSLException { +- String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine()); +- try { +- protocolListener.selected(protocol); +- } catch (Throwable e) { +- throw toSSLHandshakeException(e); +- } +- } +- } +- +- private static final class ServerEngine extends ConscryptAlpnSslEngine { +- private final ProtocolSelector protocolSelector; +- +- ServerEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator) { +- super(engine, applicationNegotiator.protocols()); +- +- // Register for completion of the handshake. +- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() { +- @Override +- public void onHandshakeFinished() throws SSLException { +- selectProtocol(); +- } +- }); +- +- protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory() +- .newSelector(this, +- new LinkedHashSet(applicationNegotiator.protocols())), +- "protocolSelector"); +- } +- +- private void selectProtocol() throws SSLException { +- try { +- String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine()); +- protocolSelector.select(protocol != null ? Collections.singletonList(protocol) +- : Collections.emptyList()); +- } catch (Throwable e) { +- throw toSSLHandshakeException(e); +- } +- } +- } +- +- private static Class getEnginesClass() { +- try { +- // Always use bootstrap class loader. +- Class engineClass = Class.forName("org.conscrypt.Conscrypt$Engines", true, +- ConscryptAlpnSslEngine.class.getClassLoader()); +- // Ensure that it also has the isConscrypt method. +- getIsConscryptMethod(engineClass); +- return engineClass; +- } catch (Throwable ignore) { +- // Conscrypt was not loaded. +- return null; +- } +- } +- +- private static boolean isConscryptEngine(SSLEngine engine, Class enginesClass) { +- try { +- Method method = getIsConscryptMethod(enginesClass); +- return (Boolean) method.invoke(null, engine); +- } catch (Throwable ignore) { +- return false; +- } +- } +- +- private static Method getIsConscryptMethod(Class enginesClass) throws NoSuchMethodException { +- return enginesClass.getMethod("isConscrypt", SSLEngine.class); +- } +-} +diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +index f82c7da..9c4ab9e 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java ++++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java +@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine; + * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}. + */ + public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator { +- private static final boolean AVAILABLE = ConscryptAlpnSslEngine.isAvailable() || JettyAlpnSslEngine.isAvailable(); ++ private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable(); + private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper(); + + /** +@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati + @Override + public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, + boolean isServer) { +- if (ConscryptAlpnSslEngine.isEngineSupported(engine)) { +- return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, applicationNegotiator) +- : ConscryptAlpnSslEngine.newClientEngine(engine, applicationNegotiator); +- } + if (JettyAlpnSslEngine.isAvailable()) { + return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator) + : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator); +diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +index 05c451a..8693011 100644 +--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java ++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +@@ -187,38 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + new ClosedChannelException(), SslHandler.class, "channelInactive(...)"); + + private enum SslEngineType { +- CONSCRYPT(true, COMPOSITE_CUMULATOR) { +- @Override +- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) +- throws SSLException { +- int nioBufferCount = in.nioBufferCount(); +- int writerIndex = out.writerIndex(); +- final SSLEngineResult result; +- if (nioBufferCount > 1) { +- /* +- * Use a special unwrap method without additional memory copies. +- */ +- try { +- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes()); +- result = ((ConscryptAlpnSslEngine) handler.engine).unwrap( +- in.nioBuffers(readerIndex, len), +- handler.singleBuffer); +- } finally { +- handler.singleBuffer[0] = null; +- } +- } else { +- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len), +- toByteBuffer(out, writerIndex, out.writableBytes())); +- } +- out.writerIndex(writerIndex + result.bytesProduced()); +- return result; +- } +- +- @Override +- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) { +- return ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents); +- } +- }, + JDK(false, MERGE_CUMULATOR) { + @Override + SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out) +@@ -237,9 +205,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH + }; + + static SslEngineType forEngine(SSLEngine engine) { +- if (engine instanceof ConscryptAlpnSslEngine) { +- return CONSCRYPT; +- } + return JDK; + } + +diff --git a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java +deleted file mode 100644 +index e217136..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* +- * Copyright 2016 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import java.security.Provider; +-import org.junit.BeforeClass; +-import org.junit.Ignore; +- +-import org.junit.runner.RunWith; +-import org.junit.runners.Parameterized; +- +-import java.util.ArrayList; +-import java.util.Collection; +-import java.util.List; +- +-import static org.junit.Assume.assumeTrue; +- +-@RunWith(Parameterized.class) +-public class ConscryptJdkSslEngineInteropTest extends SSLEngineTest { +- +- @Parameterized.Parameters(name = "{index}: bufferType = {0}") +- public static Collection data() { +- List params = new ArrayList(); +- for (BufferType type: BufferType.values()) { +- params.add(type); +- } +- return params; +- } +- +- public ConscryptJdkSslEngineInteropTest(BufferType type) { +- super(type); +- } +- +- @BeforeClass +- public static void checkConscrypt() { +- assumeTrue(ConscryptAlpnSslEngine.isAvailable()); +- } +- +- @Override +- protected SslProvider sslClientProvider() { +- return SslProvider.JDK; +- } +- +- @Override +- protected SslProvider sslServerProvider() { +- return SslProvider.JDK; +- } +- +- @Override +- protected Provider clientSslContextProvider() { +- return Java8SslTestUtils.conscryptProvider(); +- } +- +- @Ignore /* Does the JDK support a "max certificate chain length"? */ +- @Override +- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { +- } +- +- @Ignore /* Does the JDK support a "max certificate chain length"? */ +- @Override +- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java +index cc2e6c6..f9cf771 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java ++++ b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java +@@ -16,12 +16,9 @@ + + package io.netty.handler.ssl; + +-import org.conscrypt.OpenSSLProvider; +- + import javax.net.ssl.SNIMatcher; + import javax.net.ssl.SNIServerName; + import javax.net.ssl.SSLParameters; +-import java.security.Provider; + import java.util.Collections; + + final class Java8SslTestUtils { +@@ -37,8 +34,4 @@ final class Java8SslTestUtils { + }; + parameters.setSNIMatchers(Collections.singleton(matcher)); + } +- +- static Provider conscryptProvider() { +- return new OpenSSLProvider(); +- } + } +diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java +deleted file mode 100644 +index 0625f7a..0000000 +--- a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java ++++ /dev/null +@@ -1,86 +0,0 @@ +-/* +- * Copyright 2017 The Netty Project +- * +- * The Netty Project licenses this file to you under the Apache License, +- * version 2.0 (the "License"); you may not use this file except in compliance +- * with the License. You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +-package io.netty.handler.ssl; +- +-import java.security.Provider; +-import org.junit.BeforeClass; +-import org.junit.Ignore; +-import org.junit.Test; +-import org.junit.runner.RunWith; +-import org.junit.runners.Parameterized; +- +-import java.util.ArrayList; +-import java.util.Collection; +-import java.util.List; +- +-import static org.junit.Assume.assumeTrue; +- +-@RunWith(Parameterized.class) +-public class JdkConscryptSslEngineInteropTest extends SSLEngineTest { +- +- @Parameterized.Parameters(name = "{index}: bufferType = {0}") +- public static Collection data() { +- List params = new ArrayList(); +- for (BufferType type: BufferType.values()) { +- params.add(type); +- } +- return params; +- } +- +- public JdkConscryptSslEngineInteropTest(BufferType type) { +- super(type); +- } +- +- @BeforeClass +- public static void checkConscrypt() { +- assumeTrue(ConscryptAlpnSslEngine.isAvailable()); +- } +- +- @Override +- protected SslProvider sslClientProvider() { +- return SslProvider.JDK; +- } +- +- @Override +- protected SslProvider sslServerProvider() { +- return SslProvider.JDK; +- } +- +- @Override +- protected Provider serverSslContextProvider() { +- return Java8SslTestUtils.conscryptProvider(); +- } +- +- @Override +- @Test +- @Ignore("TODO: Make this work with Conscrypt") +- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception { +- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth(); +- } +- +- @Override +- @Test +- @Ignore("TODO: Make this work with Conscrypt") +- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { +- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth(); +- } +- +- @Override +- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) { +- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. +- return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause); +- } +-} +diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +index 4489b16..e32fa0d 100644 +--- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java ++++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java +@@ -81,7 +81,7 @@ public class JdkSslEngineTest extends SSLEngineTest { + + @Override + boolean isAvailable() { +- return ConscryptAlpnSslEngine.isAvailable(); ++ return false; + } + + @Override +-- +2.9.4 + diff --git a/codegen.bash b/codegen.bash new file mode 100755 index 0000000..f9837e4 --- /dev/null +++ b/codegen.bash @@ -0,0 +1,22 @@ +#!/bin/bash +for type in byte char short int long; do + case $type in + int) object=Integer ;; + char) object=Character ;; + *) object=${type^} ;; + esac + hash='(int) key' + if [ $type = long ]; then + hash='(int) (key ^ (key >>> 32))' + fi + mkdir -p target/generated-sources/collections/java + for file in `find src/main/templates -name '*.template'`; do + filename=$(basename $file | sed "s/K/${type^}/;s/\.template/.java/") + sed -e "s/@k@/${type}/g" \ + -e "s/@K@/${type^}/g" \ + -e "s/@O@/${object}/g" \ + -e "s/@KEY_NUMBER_METHOD@/${type}Value/g" \ + -e "s/@HASH_CODE@/${hash}/g" \ + $file > target/generated-sources/collections/java/$filename + done +done diff --git a/netty.spec b/netty.spec index 1bbf6b3..8717b1c 100644 --- a/netty.spec +++ b/netty.spec @@ -6,14 +6,19 @@ %bcond_with jp_minimal Name: netty -Version: 4.0.42 -Release: 7%{?dist} +Version: 4.1.13 +Release: 1%{?dist} Summary: An asynchronous event-driven network application framework and tools for Java License: ASL 2.0 URL: https://netty.io/ Source0: https://github.com/netty/netty/archive/netty-%{namedversion}.tar.gz +# Upsteam uses a simple template generator script written in groovy and run with gmaven +# We don't have the plugin and want to avoid groovy dependency +# This script is written in bash+sed and performs the same task +Source1: codegen.bash Patch0: 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch -Patch1: 0002-Remove-NPN-ALPN.patch +Patch1: 0002-Remove-NPN.patch +Patch2: 0003-Remove-conscrypt-ALPN.patch BuildRequires: maven-local BuildRequires: mvn(ant-contrib:ant-contrib) @@ -25,14 +30,22 @@ BuildRequires: mvn(org.apache.felix:maven-bundle-plugin) BuildRequires: mvn(org.apache.logging.log4j:log4j-api) BuildRequires: mvn(org.apache.maven.plugins:maven-antrun-plugin) BuildRequires: mvn(org.apache.maven.plugins:maven-dependency-plugin) +BuildRequires: mvn(org.apache.maven.plugins:maven-remote-resources-plugin) BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin) +BuildRequires: mvn(org.codehaus.mojo:exec-maven-plugin) +BuildRequires: mvn(org.eclipse.jetty.alpn:alpn-api) BuildRequires: mvn(org.fusesource.hawtjni:maven-hawtjni-plugin) BuildRequires: mvn(org.javassist:javassist) BuildRequires: mvn(org.jctools:jctools-core) BuildRequires: mvn(org.slf4j:slf4j-api) BuildRequires: mvn(org.sonatype.oss:oss-parent:pom:) %if %{without jp_minimal} +BuildRequires: mvn(com.fasterxml:aalto-xml) +BuildRequires: mvn(com.github.jponge:lzma-java) +BuildRequires: mvn(com.google.protobuf.nano:protobuf-javanano) BuildRequires: mvn(com.google.protobuf:protobuf-java) +BuildRequires: mvn(com.ning:compress-lzf) +BuildRequires: mvn(net.jpountz.lz4:lz4) BuildRequires: mvn(org.bouncycastle:bcpkix-jdk15on) BuildRequires: mvn(org.jboss.marshalling:jboss-marshalling) %endif @@ -62,6 +75,7 @@ Summary: API documentation for %{name} %patch0 -p1 %patch1 -p1 +%patch2 -p1 # Missing Mavenized rxtx %pom_disable_module "transport-rxtx" @@ -74,41 +88,76 @@ Summary: API documentation for %{name} %pom_disable_module "example" %pom_remove_dep ":netty-example" all %pom_disable_module "testsuite" +%pom_disable_module "testsuite-autobahn" %pom_disable_module "testsuite-osgi" %pom_disable_module "tarball" %pom_disable_module "microbench" -%pom_remove_plugin :maven-checkstyle-plugin -%pom_remove_plugin :animal-sniffer-maven-plugin -%pom_remove_plugin :maven-enforcer-plugin + +%pom_xpath_inject 'pom:plugin[pom:artifactId="maven-remote-resources-plugin"]' ' + + +io.netty +netty-dev-tools +${project.version} + +' + %pom_remove_plugin :maven-antrun-plugin +# get-jetty-alpn-agent %pom_remove_plugin :maven-dependency-plugin -%pom_remove_plugin :maven-shade-plugin -%pom_remove_plugin :maven-shade-plugin common +# style checker %pom_remove_plugin :xml-maven-plugin +%pom_remove_plugin -r :maven-checkstyle-plugin +%pom_remove_plugin -r :animal-sniffer-maven-plugin +%pom_remove_plugin -r :maven-enforcer-plugin +%pom_remove_plugin -r :maven-shade-plugin %pom_remove_plugin -r :maven-release-plugin %pom_remove_plugin -r :maven-clean-plugin %pom_remove_plugin -r :maven-source-plugin %pom_remove_plugin -r :maven-deploy-plugin %pom_remove_plugin -r :maven-jxr-plugin %pom_remove_plugin -r :maven-javadoc-plugin -# Optional things we don't ship -%pom_remove_dep ":\${tcnative.artifactId}" -%pom_remove_dep ":\${tcnative.artifactId}" handler -%pom_remove_dep "org.eclipse.jetty.npn:npn-api" -%pom_remove_dep "org.eclipse.jetty.npn:npn-api" handler -%pom_remove_dep "org.eclipse.jetty.alpn:alpn-api" -%pom_remove_dep "org.eclipse.jetty.alpn:alpn-api" handler +%pom_remove_plugin -r :forbiddenapis + +cp %{SOURCE1} common/codegen.bash +%pom_add_plugin org.codehaus.mojo:exec-maven-plugin common ' + + + generate-collections + generate-sources + + exec + + + common/codegen.bash + + + +' +%pom_remove_plugin :groovy-maven-plugin common %if %{with jp_minimal} %pom_remove_dep -r "com.google.protobuf:protobuf-java" +%pom_remove_dep -r "com.google.protobuf.nano:protobuf-javanano" rm codec/src/main/java/io/netty/handler/codec/protobuf/* +sed -i '/import.*protobuf/d' codec/src/main/java/io/netty/handler/codec/DatagramPacket*.java %pom_remove_dep -r "org.jboss.marshalling:jboss-marshalling" rm codec/src/main/java/io/netty/handler/codec/marshalling/* %pom_remove_dep -r org.bouncycastle rm handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java sed -i '/BouncyCastleSelfSignedCertGenerator/s/.*/throw new UnsupportedOperationException();/' \ handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java -%endif +%pom_remove_dep -r com.fasterxml:aalto-xml +%pom_disable_module codec-xml +%pom_remove_dep :netty-codec-xml all +%pom_remove_dep -r com.github.jponge:lzma-java +rm codec/src/*/java/io/netty/handler/codec/compression/Lzma*.java +%pom_remove_dep -r com.ning:compress-lzf +rm codec/src/*/java/io/netty/handler/codec/compression/Lzf*.java +%pom_remove_dep -r net.jpountz.lz4:lz4 +rm codec/src/*/java/io/netty/handler/codec/compression/Lz4*.java + +%endif # jp_minimal sed -i 's|taskdef|taskdef classpathref="maven.plugin.classpath"|' all/pom.xml @@ -137,6 +186,9 @@ export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS" %doc LICENSE.txt NOTICE.txt %changelog +* Mon Aug 14 2017 Michael Simacek - 4.1.13-1 +- Update to upstream version 4.1.13 + * Thu Aug 03 2017 Fedora Release Engineering - 4.0.42-7 - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild diff --git a/sources b/sources index dee10a7..39533ac 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -1259f8126350883c5770bd26a6896fc0 netty-4.0.42.Final.tar.gz +SHA512 (netty-4.1.13.Final.tar.gz) = f0a269adf5b6552eb2f0f12614c2093e0ccfd5a5bb38521dcf39c3827160c8983adcfe1bbcf93a24e71506e323ae723a837621046657fec0df50c59a07aee54c