Add support for boringssl and TLSv1.3 (#8412)
Motivation:
0ddc62cec0
added support for TLSv1.3 when using openssl 1.1.1. Now that BoringSSL chromium-stable branch supports it as well we can also support it with netty-tcnative-boringssl-static.
During this some unit tests failed with BoringSSL which was caused by not correctly handling flush() while the handshake is still in progress.
Modification:
- Upgrade netty-tcnative version which also supports TLSv1.3 when using BoringSSL
- Correctly handle flush() when done while the handshake is still in progress in all cases.
Result:
Easier for people to enable TLSv1.3 when using native SSL impl.
Ensure flush() while handshake is in progress will always be honored.
This commit is contained in:
parent
1cc692dd7d
commit
ce39773e04
@ -66,7 +66,7 @@ public final class OpenSsl {
|
|||||||
"TLS_AES_128_CCM_8_SHA256" + ':' +
|
"TLS_AES_128_CCM_8_SHA256" + ':' +
|
||||||
"TLS_AES_128_CCM_SHA256";
|
"TLS_AES_128_CCM_SHA256";
|
||||||
private static final boolean TLSV13_SUPPORTED;
|
private static final boolean TLSV13_SUPPORTED;
|
||||||
|
private static final boolean IS_BORINGSSL;
|
||||||
static final Set<String> SUPPORTED_PROTOCOLS_SET;
|
static final Set<String> SUPPORTED_PROTOCOLS_SET;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -141,6 +141,8 @@ public final class OpenSsl {
|
|||||||
boolean supportsHostNameValidation = false;
|
boolean supportsHostNameValidation = false;
|
||||||
boolean tlsv13Supported = false;
|
boolean tlsv13Supported = false;
|
||||||
|
|
||||||
|
IS_BORINGSSL = "BoringSSL".equals(versionString());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
|
final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
|
||||||
long certBio = 0;
|
long certBio = 0;
|
||||||
@ -160,12 +162,19 @@ public final class OpenSsl {
|
|||||||
// Filter out bad input.
|
// Filter out bad input.
|
||||||
if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c) ||
|
if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c) ||
|
||||||
// Filter out TLSv1.3 ciphers if not supported.
|
// Filter out TLSv1.3 ciphers if not supported.
|
||||||
!tlsv13Supported && SslUtils.isTLSv13Cipher(c)) {
|
!tlsv13Supported && isTLSv13Cipher(c)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
availableOpenSslCipherSuites.add(c);
|
availableOpenSslCipherSuites.add(c);
|
||||||
}
|
}
|
||||||
|
if (IS_BORINGSSL) {
|
||||||
|
// Currently BoringSSL does not include these when calling SSL.getCiphers() even when these
|
||||||
|
// are supported.
|
||||||
|
Collections.addAll(availableOpenSslCipherSuites,
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384" ,
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
SSL.setHostNameValidation(ssl, 0, "netty.io");
|
SSL.setHostNameValidation(ssl, 0, "netty.io");
|
||||||
supportsHostNameValidation = true;
|
supportsHostNameValidation = true;
|
||||||
@ -240,7 +249,7 @@ public final class OpenSsl {
|
|||||||
AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
|
AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
|
||||||
for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
|
for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
|
||||||
// Included converted but also openssl cipher name
|
// Included converted but also openssl cipher name
|
||||||
if (!SslUtils.isTLSv13Cipher(cipher)) {
|
if (!isTLSv13Cipher(cipher)) {
|
||||||
availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS"));
|
availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS"));
|
||||||
availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL"));
|
availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL"));
|
||||||
} else {
|
} else {
|
||||||
@ -312,6 +321,7 @@ public final class OpenSsl {
|
|||||||
SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
|
SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
|
||||||
SUPPORTS_OCSP = false;
|
SUPPORTS_OCSP = false;
|
||||||
TLSV13_SUPPORTED = false;
|
TLSV13_SUPPORTED = false;
|
||||||
|
IS_BORINGSSL = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,4 +520,8 @@ public final class OpenSsl {
|
|||||||
static boolean isTlsv13Supported() {
|
static boolean isTlsv13Supported() {
|
||||||
return TLSV13_SUPPORTED;
|
return TLSV13_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isBoringSSL() {
|
||||||
|
return IS_BORINGSSL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1385,13 +1385,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
|||||||
wrapLater = true;
|
wrapLater = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (flushedBeforeHandshake) {
|
|
||||||
// We need to call wrap(...) in case there was a flush done before the handshake completed.
|
|
||||||
//
|
|
||||||
// See https://github.com/netty/netty/pull/2437
|
|
||||||
flushedBeforeHandshake = false;
|
|
||||||
wrapLater = true;
|
|
||||||
}
|
|
||||||
// If we are not handshaking and there is no more data to unwrap then the next call to unwrap
|
// If we are not handshaking and there is no more data to unwrap then the next call to unwrap
|
||||||
// will not produce any data. We can avoid the potentially costly unwrap operation and break
|
// will not produce any data. We can avoid the potentially costly unwrap operation and break
|
||||||
// out of the loop.
|
// out of the loop.
|
||||||
@ -1414,6 +1408,15 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flushedBeforeHandshake && handshakePromise.isDone()) {
|
||||||
|
// We need to call wrap(...) in case there was a flush done before the handshake completed to ensure
|
||||||
|
// we do not stale.
|
||||||
|
//
|
||||||
|
// See https://github.com/netty/netty/pull/2437
|
||||||
|
flushedBeforeHandshake = false;
|
||||||
|
wrapLater = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (wrapLater) {
|
if (wrapLater) {
|
||||||
wrap(ctx, true);
|
wrap(ctx, true);
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,4 @@ final class OpenSslTestUtils {
|
|||||||
static void checkShouldUseKeyManagerFactory() {
|
static void checkShouldUseKeyManagerFactory() {
|
||||||
assumeTrue(OpenSsl.supportsKeyManagerFactory() && OpenSsl.useKeyManagerFactory());
|
assumeTrue(OpenSsl.supportsKeyManagerFactory() && OpenSsl.useKeyManagerFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isBoringSSL() {
|
|
||||||
return "BoringSSL".equals(OpenSsl.versionString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1087,7 +1087,7 @@ public abstract class SSLEngineTest {
|
|||||||
MessageReceiver receiver) throws Exception {
|
MessageReceiver receiver) throws Exception {
|
||||||
List<ByteBuf> dataCapture = null;
|
List<ByteBuf> dataCapture = null;
|
||||||
try {
|
try {
|
||||||
sendChannel.writeAndFlush(message);
|
assertTrue(sendChannel.writeAndFlush(message).await(5, TimeUnit.SECONDS));
|
||||||
receiverLatch.await(5, TimeUnit.SECONDS);
|
receiverLatch.await(5, TimeUnit.SECONDS);
|
||||||
message.resetReaderIndex();
|
message.resetReaderIndex();
|
||||||
ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);
|
ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);
|
||||||
|
@ -182,7 +182,7 @@ final class SniClientJava8TestUtil {
|
|||||||
if (clientSide) {
|
if (clientSide) {
|
||||||
Assert.assertEquals(0, extendedSSLSession.getPeerSupportedSignatureAlgorithms().length);
|
Assert.assertEquals(0, extendedSSLSession.getPeerSupportedSignatureAlgorithms().length);
|
||||||
} else {
|
} else {
|
||||||
if (session instanceof OpenSslSession && OpenSslTestUtils.isBoringSSL()) {
|
if (session instanceof OpenSslSession && OpenSsl.isBoringSSL()) {
|
||||||
// BoringSSL does not support SSL_get_sigalgs(...)
|
// BoringSSL does not support SSL_get_sigalgs(...)
|
||||||
// https://boringssl.googlesource.com/boringssl/+/ba16a1e405c617f4179bd780ad15522fb25b0a65%5E%21/
|
// https://boringssl.googlesource.com/boringssl/+/ba16a1e405c617f4179bd780ad15522fb25b0a65%5E%21/
|
||||||
Assert.assertEquals(0, extendedSSLSession.getPeerSupportedSignatureAlgorithms().length);
|
Assert.assertEquals(0, extendedSSLSession.getPeerSupportedSignatureAlgorithms().length);
|
||||||
|
@ -205,7 +205,7 @@ public class SslErrorTest {
|
|||||||
verifyException(unwrappedCause, "expired", promise);
|
verifyException(unwrappedCause, "expired", promise);
|
||||||
} else if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
|
} else if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
|
||||||
// BoringSSL uses "expired" in this case while others use "bad"
|
// BoringSSL uses "expired" in this case while others use "bad"
|
||||||
if (OpenSslTestUtils.isBoringSSL()) {
|
if (OpenSsl.isBoringSSL()) {
|
||||||
verifyException(unwrappedCause, "expired", promise);
|
verifyException(unwrappedCause, "expired", promise);
|
||||||
} else {
|
} else {
|
||||||
verifyException(unwrappedCause, "bad", promise);
|
verifyException(unwrappedCause, "bad", promise);
|
||||||
@ -217,7 +217,7 @@ public class SslErrorTest {
|
|||||||
verifyException(unwrappedCause, "expired", promise);
|
verifyException(unwrappedCause, "expired", promise);
|
||||||
} else if (exception instanceof CertificateNotYetValidException) {
|
} else if (exception instanceof CertificateNotYetValidException) {
|
||||||
// BoringSSL uses "expired" in this case while others use "bad"
|
// BoringSSL uses "expired" in this case while others use "bad"
|
||||||
if (OpenSslTestUtils.isBoringSSL()) {
|
if (OpenSsl.isBoringSSL()) {
|
||||||
verifyException(unwrappedCause, "expired", promise);
|
verifyException(unwrappedCause, "expired", promise);
|
||||||
} else {
|
} else {
|
||||||
verifyException(unwrappedCause, "bad", promise);
|
verifyException(unwrappedCause, "bad", promise);
|
||||||
|
2
pom.xml
2
pom.xml
@ -241,7 +241,7 @@
|
|||||||
<!-- Fedora-"like" systems. This is currently only used for the netty-tcnative dependency -->
|
<!-- Fedora-"like" systems. This is currently only used for the netty-tcnative dependency -->
|
||||||
<os.detection.classifierWithLikes>fedora</os.detection.classifierWithLikes>
|
<os.detection.classifierWithLikes>fedora</os.detection.classifierWithLikes>
|
||||||
<tcnative.artifactId>netty-tcnative</tcnative.artifactId>
|
<tcnative.artifactId>netty-tcnative</tcnative.artifactId>
|
||||||
<tcnative.version>2.0.18.Final</tcnative.version>
|
<tcnative.version>2.0.19.Final</tcnative.version>
|
||||||
<tcnative.classifier>${os.detected.classifier}</tcnative.classifier>
|
<tcnative.classifier>${os.detected.classifier}</tcnative.classifier>
|
||||||
<conscrypt.groupId>org.conscrypt</conscrypt.groupId>
|
<conscrypt.groupId>org.conscrypt</conscrypt.groupId>
|
||||||
<conscrypt.artifactId>conscrypt-openjdk-uber</conscrypt.artifactId>
|
<conscrypt.artifactId>conscrypt-openjdk-uber</conscrypt.artifactId>
|
||||||
|
Loading…
Reference in New Issue
Block a user