Make the TLSv1.3 check more robust and not depend on the Java version… (#10409)
Motivation: TLSv1.3 is not strictly limited to Java11+ anymore as different vendors backported TLSv1.3 to Java8 as well. We should ensure we make the detection of if TLSv1.3 is supported not depend on the Java version that is used. Modifications: - Add SslProvider.isTlsv13Supported(...) and use it in tests to detect if we should run tests against TLSv1.3 as well - Adjust testcase to work on latest JDK 8 release as well Result: Correct detection of TLSv1.3 support even if Java version < 11.
This commit is contained in:
parent
4e86f768b9
commit
28e1fbd366
@ -46,7 +46,7 @@ final class OpenSslTlsv13X509ExtendedTrustManager extends X509ExtendedTrustManag
|
||||
}
|
||||
|
||||
static X509ExtendedTrustManager wrap(X509ExtendedTrustManager tm) {
|
||||
if (PlatformDependent.javaVersion() < 11 && OpenSsl.isTlsv13Supported()) {
|
||||
if (!SslProvider.isTlsv13Supported(SslProvider.JDK) && SslProvider.isTlsv13Supported(SslProvider.OPENSSL)) {
|
||||
return new OpenSslTlsv13X509ExtendedTrustManager(tm);
|
||||
}
|
||||
return tm;
|
||||
|
@ -215,10 +215,12 @@ public abstract class ReferenceCountedOpenSslContext extends SslContext implemen
|
||||
// Create a new SSL_CTX and configure it.
|
||||
boolean success = false;
|
||||
try {
|
||||
boolean tlsv13Supported = OpenSsl.isTlsv13Supported();
|
||||
|
||||
try {
|
||||
int protocolOpts = SSL.SSL_PROTOCOL_SSLV3 | SSL.SSL_PROTOCOL_TLSV1 |
|
||||
SSL.SSL_PROTOCOL_TLSV1_1 | SSL.SSL_PROTOCOL_TLSV1_2;
|
||||
if (OpenSsl.isTlsv13Supported()) {
|
||||
if (tlsv13Supported) {
|
||||
protocolOpts |= SSL.SSL_PROTOCOL_TLSV1_3;
|
||||
}
|
||||
ctx = SSLContext.make(protocolOpts, mode);
|
||||
@ -226,7 +228,6 @@ public abstract class ReferenceCountedOpenSslContext extends SslContext implemen
|
||||
throw new SSLException("failed to create an SSL_CTX", e);
|
||||
}
|
||||
|
||||
boolean tlsv13Supported = OpenSsl.isTlsv13Supported();
|
||||
StringBuilder cipherBuilder = new StringBuilder();
|
||||
StringBuilder cipherTLSv13Builder = new StringBuilder();
|
||||
|
||||
|
@ -52,4 +52,20 @@ public enum SslProvider {
|
||||
throw new Error("Unknown SslProvider: " + provider);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified {@link SslProvider} supports
|
||||
* <a href="https://tools.ietf.org/html/rfc8446">TLS 1.3</a>, {@code false} otherwise.
|
||||
*/
|
||||
public static boolean isTlsv13Supported(final SslProvider provider) {
|
||||
switch (provider) {
|
||||
case JDK:
|
||||
return SslUtils.isTLSv13SupportedByJDK();
|
||||
case OPENSSL:
|
||||
case OPENSSL_REFCNT:
|
||||
return OpenSsl.isTlsv13Supported();
|
||||
default:
|
||||
throw new Error("Unknown SslProvider: " + provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ import io.netty.handler.codec.base64.Base64;
|
||||
import io.netty.handler.codec.base64.Base64Dialect;
|
||||
import io.netty.util.NetUtil;
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
@ -33,7 +34,9 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.TrustManager;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
@ -41,6 +44,8 @@ import static java.util.Arrays.asList;
|
||||
* Constants for SSL packets.
|
||||
*/
|
||||
final class SslUtils {
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(SslUtils.class);
|
||||
|
||||
// See https://tools.ietf.org/html/rfc8446#appendix-B.4
|
||||
static final Set<String> TLSV13_CIPHERS = Collections.unmodifiableSet(new LinkedHashSet<String>(
|
||||
asList("TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256",
|
||||
@ -101,8 +106,31 @@ final class SslUtils {
|
||||
static final String[] DEFAULT_TLSV13_CIPHER_SUITES;
|
||||
static final String[] TLSV13_CIPHER_SUITES = { "TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384" };
|
||||
|
||||
private static final boolean TLSV1_3_SUPPORTED;
|
||||
|
||||
static {
|
||||
if (PlatformDependent.javaVersion() >= 11) {
|
||||
boolean tlsv13Supported = false;
|
||||
Throwable cause = null;
|
||||
try {
|
||||
SSLContext context = SSLContext.getInstance("TLS");
|
||||
context.init(null, new TrustManager[0], null);
|
||||
for (String supported: context.getSupportedSSLParameters().getProtocols()) {
|
||||
if (PROTOCOL_TLS_V1_3.equals(supported)) {
|
||||
tlsv13Supported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
cause = error;
|
||||
}
|
||||
if (cause == null) {
|
||||
logger.debug("JDK SSLEngine supports TLSv1.3: {}", tlsv13Supported);
|
||||
} else {
|
||||
logger.debug("Unable to detect if JDK SSLEngine supports TLSv1.3, assuming no", cause);
|
||||
}
|
||||
TLSV1_3_SUPPORTED = tlsv13Supported;
|
||||
|
||||
if (TLSV1_3_SUPPORTED) {
|
||||
DEFAULT_TLSV13_CIPHER_SUITES = TLSV13_CIPHER_SUITES;
|
||||
} else {
|
||||
DEFAULT_TLSV13_CIPHER_SUITES = EmptyArrays.EMPTY_STRINGS;
|
||||
@ -128,6 +156,13 @@ final class SslUtils {
|
||||
DEFAULT_CIPHER_SUITES = defaultCiphers.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the JDK itself supports TLSv1.3, {@code false} otherwise.
|
||||
*/
|
||||
static boolean isTLSv13SupportedByJDK() {
|
||||
return TLSV1_3_SUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add elements from {@code names} into {@code enabled} if they are in {@code supported}.
|
||||
*/
|
||||
|
@ -17,7 +17,6 @@ package io.netty.handler.ssl;
|
||||
|
||||
import com.amazon.corretto.crypto.provider.AmazonCorrettoCryptoProvider;
|
||||
import com.amazon.corretto.crypto.provider.SelfTestStatus;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
@ -44,7 +43,7 @@ public class AmazonCorrettoSslEngineTest extends SSLEngineTest {
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv12(), false });
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv12(), true });
|
||||
|
||||
if (PlatformDependent.javaVersion() >= 11) {
|
||||
if (SslProvider.isTlsv13Supported(SslProvider.JDK)) {
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv13(), true });
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv13(), false });
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package io.netty.handler.ssl;
|
||||
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -43,7 +42,7 @@ public class JdkOpenSslEngineInteroptTest extends SSLEngineTest {
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv12(), true, false });
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv12(), true, true });
|
||||
|
||||
if (PlatformDependent.javaVersion() >= 11 && OpenSsl.isTlsv13Supported()) {
|
||||
if (SslProvider.isTlsv13Supported(SslProvider.JDK) && SslProvider.isTlsv13Supported(SslProvider.OPENSSL)) {
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv13(), false, false });
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv13(), false, true });
|
||||
|
||||
|
@ -27,7 +27,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -150,7 +149,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
||||
params.add(new Object[]{ providerType, bufferType, ProtocolCipherCombo.tlsv12(), true });
|
||||
params.add(new Object[]{ providerType, bufferType, ProtocolCipherCombo.tlsv12(), false });
|
||||
|
||||
if (PlatformDependent.javaVersion() >= 11) {
|
||||
if (SslProvider.isTlsv13Supported(SslProvider.JDK)) {
|
||||
params.add(new Object[] { providerType, bufferType, ProtocolCipherCombo.tlsv13(), true });
|
||||
params.add(new Object[] { providerType, bufferType, ProtocolCipherCombo.tlsv13(), false });
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public class OpenSslEngineTest extends SSLEngineTest {
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv12(), true, false });
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv12(), true, true });
|
||||
|
||||
if (OpenSsl.isTlsv13Supported()) {
|
||||
if (SslProvider.isTlsv13Supported(SslProvider.OPENSSL)) {
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv13(), false, false });
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv13(), false, true });
|
||||
|
||||
|
@ -45,7 +45,7 @@ public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest {
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv12(), true, false});
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv12(), true, true });
|
||||
|
||||
if (PlatformDependent.javaVersion() >= 11 && OpenSsl.isTlsv13Supported()) {
|
||||
if (SslProvider.isTlsv13Supported(SslProvider.JDK) && SslProvider.isTlsv13Supported(SslProvider.OPENSSL)) {
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv13(), false, false });
|
||||
params.add(new Object[] { type, ProtocolCipherCombo.tlsv13(), false, true });
|
||||
|
||||
|
@ -2332,15 +2332,13 @@ public abstract class SSLEngineTest {
|
||||
encryptedClientToServer.flip();
|
||||
|
||||
assertEquals(SSLEngineResult.Status.CLOSED, result.getStatus());
|
||||
SSLEngineResult.HandshakeStatus hs = result.getHandshakeStatus();
|
||||
// Need an UNWRAP to read the response of the close_notify
|
||||
if ((PlatformDependent.javaVersion() >= 12 && sslClientProvider() == SslProvider.JDK)
|
||||
|| Conscrypt.isEngineSupported(client)) {
|
||||
// This is a workaround for a possible JDK12+ bug.
|
||||
//
|
||||
// See http://mail.openjdk.java.net/pipermail/security-dev/2019-February/019406.html.
|
||||
assertEquals(SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus());
|
||||
if (sslClientProvider() == SslProvider.JDK || Conscrypt.isEngineSupported(client)) {
|
||||
assertTrue(hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING
|
||||
|| hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP);
|
||||
} else {
|
||||
assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus());
|
||||
assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, hs);
|
||||
}
|
||||
|
||||
int produced = result.bytesProduced();
|
||||
|
@ -1116,37 +1116,37 @@ public class SslHandlerTest {
|
||||
|
||||
@Test(timeout = 5000L)
|
||||
public void testSessionTicketsWithTLSv12() throws Throwable {
|
||||
testSessionTickets(SslUtils.PROTOCOL_TLS_V1_2, true);
|
||||
testSessionTickets(SslProvider.OPENSSL, SslUtils.PROTOCOL_TLS_V1_2, true);
|
||||
}
|
||||
|
||||
@Test(timeout = 5000L)
|
||||
public void testSessionTicketsWithTLSv13() throws Throwable {
|
||||
assumeTrue(OpenSsl.isTlsv13Supported());
|
||||
testSessionTickets(SslUtils.PROTOCOL_TLS_V1_3, true);
|
||||
assumeTrue(SslProvider.isTlsv13Supported(SslProvider.OPENSSL));
|
||||
testSessionTickets(SslProvider.OPENSSL, SslUtils.PROTOCOL_TLS_V1_3, true);
|
||||
}
|
||||
|
||||
@Test(timeout = 5000L)
|
||||
public void testSessionTicketsWithTLSv12AndNoKey() throws Throwable {
|
||||
testSessionTickets(SslUtils.PROTOCOL_TLS_V1_2, false);
|
||||
testSessionTickets(SslProvider.OPENSSL, SslUtils.PROTOCOL_TLS_V1_2, false);
|
||||
}
|
||||
|
||||
@Test(timeout = 5000L)
|
||||
public void testSessionTicketsWithTLSv13AndNoKey() throws Throwable {
|
||||
assumeTrue(OpenSsl.isTlsv13Supported());
|
||||
testSessionTickets(SslUtils.PROTOCOL_TLS_V1_3, false);
|
||||
testSessionTickets(SslProvider.OPENSSL, SslUtils.PROTOCOL_TLS_V1_3, false);
|
||||
}
|
||||
|
||||
private static void testSessionTickets(String protocol, boolean withKey) throws Throwable {
|
||||
private static void testSessionTickets(SslProvider provider, String protocol, boolean withKey) throws Throwable {
|
||||
assumeTrue(OpenSsl.isAvailable());
|
||||
final SslContext sslClientCtx = SslContextBuilder.forClient()
|
||||
.trustManager(InsecureTrustManagerFactory.INSTANCE)
|
||||
.sslProvider(SslProvider.OPENSSL)
|
||||
.sslProvider(provider)
|
||||
.protocols(protocol)
|
||||
.build();
|
||||
|
||||
final SelfSignedCertificate cert = new SelfSignedCertificate();
|
||||
final SslContext sslServerCtx = SslContextBuilder.forServer(cert.key(), cert.cert())
|
||||
.sslProvider(SslProvider.OPENSSL)
|
||||
.sslProvider(provider)
|
||||
.protocols(protocol)
|
||||
.build();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user