Correctly include TLS1.3 ciphers in the enabled ciphersuites when using BoringSSL (#10388)
Motivation: BoringSSL behaves differently then OpenSSL and not include any TLS1.3 ciphers in the returned array when calling SSL_get_ciphers(...). This is due the fact that it also not allow to explicit configure which are supported and which not for TLS1.3. To mimic the behaviour expected by the SSLEngine API we should workaround this. Modifications: - Add a unit test that verifies enabled protocols / ciphers - Add special handling for BoringSSL and tls1.3 Result: Make behaviour consistent
This commit is contained in:
parent
523dc5c269
commit
cbe238a95b
@ -26,6 +26,7 @@ import io.netty.internal.tcnative.SSLContext;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import io.netty.util.ReferenceCounted;
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
import io.netty.util.internal.NativeLibraryLoader;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
@ -62,6 +63,7 @@ public final class OpenSsl {
|
||||
private static final boolean TLSV13_SUPPORTED;
|
||||
private static final boolean IS_BORINGSSL;
|
||||
static final Set<String> SUPPORTED_PROTOCOLS_SET;
|
||||
static final String[] EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
|
||||
|
||||
// self-signed certificate for netty.io and the matching private-key
|
||||
private static final String CERT = "-----BEGIN CERTIFICATE-----\n" +
|
||||
@ -177,6 +179,13 @@ public final class OpenSsl {
|
||||
boolean tlsv13Supported = false;
|
||||
|
||||
IS_BORINGSSL = "BoringSSL".equals(versionString());
|
||||
if (IS_BORINGSSL) {
|
||||
EXTRA_SUPPORTED_TLS_1_3_CIPHERS = new String [] { "TLS_AES_128_GCM_SHA256",
|
||||
"TLS_AES_256_GCM_SHA384" ,
|
||||
"TLS_CHACHA20_POLY1305_SHA256" };
|
||||
} else {
|
||||
EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
|
||||
}
|
||||
|
||||
try {
|
||||
final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
|
||||
@ -222,10 +231,8 @@ public final class OpenSsl {
|
||||
if (IS_BORINGSSL) {
|
||||
// Currently BoringSSL does not include these when calling SSL.getCiphers() even when these
|
||||
// are supported.
|
||||
Collections.addAll(availableOpenSslCipherSuites, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
|
||||
Collections.addAll(availableOpenSslCipherSuites,
|
||||
"TLS_AES_128_GCM_SHA256",
|
||||
"TLS_AES_256_GCM_SHA384" ,
|
||||
"TLS_CHACHA20_POLY1305_SHA256",
|
||||
"AEAD-AES128-GCM-SHA256",
|
||||
"AEAD-AES256-GCM-SHA384",
|
||||
"AEAD-CHACHA20-POLY1305-SHA256");
|
||||
@ -372,6 +379,7 @@ public final class OpenSsl {
|
||||
SUPPORTS_OCSP = false;
|
||||
TLSV13_SUPPORTED = false;
|
||||
IS_BORINGSSL = false;
|
||||
EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,8 +72,6 @@ import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_1;
|
||||
import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_2;
|
||||
import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_3;
|
||||
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.Integer.MAX_VALUE;
|
||||
import static java.lang.Math.min;
|
||||
@ -1490,10 +1488,17 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
|
||||
@Override
|
||||
public final String[] getEnabledCipherSuites() {
|
||||
final String[] extraCiphers;
|
||||
final String[] enabled;
|
||||
synchronized (this) {
|
||||
if (!isDestroyed()) {
|
||||
enabled = SSL.getCiphers(ssl);
|
||||
int opts = SSL.getOptions(ssl);
|
||||
if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, PROTOCOL_TLS_V1_3)) {
|
||||
extraCiphers = OpenSsl.EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
|
||||
} else {
|
||||
extraCiphers = EmptyArrays.EMPTY_STRINGS;
|
||||
}
|
||||
} else {
|
||||
return EmptyArrays.EMPTY_STRINGS;
|
||||
}
|
||||
@ -1501,7 +1506,7 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
if (enabled == null) {
|
||||
return EmptyArrays.EMPTY_STRINGS;
|
||||
} else {
|
||||
List<String> enabledList = new ArrayList<String>();
|
||||
Set<String> enabledSet = new LinkedHashSet<String>(enabled.length + extraCiphers.length);
|
||||
synchronized (this) {
|
||||
for (int i = 0; i < enabled.length; i++) {
|
||||
String mapped = toJavaCipherSuite(enabled[i]);
|
||||
@ -1509,10 +1514,11 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
if (!OpenSsl.isTlsv13Supported() && SslUtils.isTLSv13Cipher(cipher)) {
|
||||
continue;
|
||||
}
|
||||
enabledList.add(cipher);
|
||||
enabledSet.add(cipher);
|
||||
}
|
||||
Collections.addAll(enabledSet, extraCiphers);
|
||||
}
|
||||
return enabledList.toArray(new String[0]);
|
||||
return enabledSet.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2254,8 +2260,8 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
byte[][] chain = SSL.getPeerCertChain(ssl);
|
||||
if (clientMode) {
|
||||
if (isEmpty(chain)) {
|
||||
peerCerts = EMPTY_CERTIFICATES;
|
||||
x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES;
|
||||
peerCerts = EmptyArrays.EMPTY_CERTIFICATES;
|
||||
x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
|
||||
} else {
|
||||
peerCerts = new Certificate[chain.length];
|
||||
x509PeerCerts = new X509Certificate[chain.length];
|
||||
@ -2269,8 +2275,8 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
// See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
|
||||
byte[] clientCert = SSL.getPeerCertificate(ssl);
|
||||
if (isEmpty(clientCert)) {
|
||||
peerCerts = EMPTY_CERTIFICATES;
|
||||
x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES;
|
||||
peerCerts = EmptyArrays.EMPTY_CERTIFICATES;
|
||||
x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
|
||||
} else {
|
||||
if (isEmpty(chain)) {
|
||||
peerCerts = new Certificate[] {new OpenSslX509Certificate(clientCert)};
|
||||
|
@ -3427,6 +3427,54 @@ public abstract class SSLEngineTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnabledProtocolsAndCiphers() throws Exception {
|
||||
clientSslCtx = wrapContext(SslContextBuilder.forClient()
|
||||
.trustManager(InsecureTrustManagerFactory.INSTANCE)
|
||||
.sslProvider(sslClientProvider())
|
||||
.sslContextProvider(clientSslContextProvider())
|
||||
.protocols(protocols())
|
||||
.ciphers(ciphers())
|
||||
.build());
|
||||
SelfSignedCertificate ssc = new SelfSignedCertificate();
|
||||
serverSslCtx = wrapContext(SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
|
||||
.sslProvider(sslServerProvider())
|
||||
.sslContextProvider(serverSslContextProvider())
|
||||
.protocols(protocols())
|
||||
.ciphers(ciphers())
|
||||
.build());
|
||||
SSLEngine clientEngine = null;
|
||||
SSLEngine serverEngine = null;
|
||||
try {
|
||||
clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
|
||||
serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
|
||||
handshake(clientEngine, serverEngine);
|
||||
assertEnabledProtocolsAndCipherSuites(clientEngine);
|
||||
assertEnabledProtocolsAndCipherSuites(serverEngine);
|
||||
} finally {
|
||||
cleanupClientSslEngine(clientEngine);
|
||||
cleanupServerSslEngine(serverEngine);
|
||||
ssc.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertEnabledProtocolsAndCipherSuites(SSLEngine engine) {
|
||||
String protocol = engine.getSession().getProtocol();
|
||||
String cipherSuite = engine.getSession().getCipherSuite();
|
||||
|
||||
assertArrayContains(protocol, engine.getEnabledProtocols());
|
||||
assertArrayContains(cipherSuite, engine.getEnabledCipherSuites());
|
||||
}
|
||||
|
||||
private static void assertArrayContains(String expected, String[] array) {
|
||||
for (String value: array) {
|
||||
if (expected.equals(value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
fail("Array did not contain '" + expected + "':" + Arrays.toString(array));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMasterKeyLogging() throws Exception {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user