Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce the configured TLS version #34468

Merged
merged 1 commit into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Enforce the configured TLS version
  • Loading branch information
cescoffier committed Jul 3, 2023
commit cdd9ce5bcc0cbbc3cc23a34f3c980fb2dff17616
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,7 @@ static boolean applySslOptions(GrpcServerConfiguration config, HttpServerOptions
for (String cipher : sslConfig.cipherSuites.orElse(Collections.emptyList())) {
options.addEnabledCipherSuite(cipher);
}

for (String protocol : sslConfig.protocols) {
if (!protocol.isEmpty()) {
options.addEnabledSecureTransportProtocol(protocol);
}
}
options.setEnabledSecureTransportProtocols(sslConfig.protocols);
options.setClientAuth(sslConfig.clientAuth);
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.quarkus.grpc.runtime;

import java.util.List;
import java.util.Set;

import org.eclipse.microprofile.config.ConfigProvider;

Expand Down Expand Up @@ -36,7 +36,7 @@ private static boolean isHttpsConfigured(SslServerConfig ssl) {
|| !isDefaultProtocols(ssl.protocols);
}

private static boolean isDefaultProtocols(List<String> protocols) {
private static boolean isDefaultProtocols(Set<String> protocols) {
return protocols.size() == 2 && protocols.contains("TLSv1.3") && protocols.contains("TLSv1.2");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;
Expand Down Expand Up @@ -49,7 +50,7 @@ public class SslServerConfig {

/**
* An optional trust store which holds the certificate information of the certificates to trust
*
* <p>
* The trust store can be either on classpath or an external file.
*/
@ConfigItem
Expand All @@ -75,11 +76,18 @@ public class SslServerConfig {
public Optional<List<String>> cipherSuites;

/**
* The list of protocols to explicitly enable.
* Sets the ordered list of enabled SSL/TLS protocols.
* <p>
* If not set, it defaults to {@code "TLSv1.3, TLSv1.2"}.
* The following list of protocols are supported: {@code TLSv1, TLSv1.1, TLSv1.2, TLSv1.3}.
* To only enable {@code TLSv1.3}, set the value to {@code to "TLSv1.3"}.
* <p>
* Note that setting an empty list, and enabling SSL/TLS is invalid.
* You must at least have one protocol.
*/
@DefaultConverter
@ConfigItem(defaultValue = "TLSv1.3,TLSv1.2")
public List<String> protocols;
public Set<String> protocols;

/**
* Configures the engine to require/request client authentication.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;
import java.util.Optional;
import java.util.Set;

import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;
Expand All @@ -24,11 +25,18 @@ public class ServerSslConfig {
public Optional<List<String>> cipherSuites;

/**
* The list of protocols to explicitly enable.
* Sets the ordered list of enabled SSL/TLS protocols.
* <p>
* If not set, it defaults to {@code "TLSv1.3, TLSv1.2"}.
* The following list of protocols are supported: {@code TLSv1, TLSv1.1, TLSv1.2, TLSv1.3}.
* To only enable {@code TLSv1.3}, set the value to {@code to "TLSv1.3"}.
* <p>
* Note that setting an empty list, and enabling SSL/TLS is invalid.
* You must at least have one protocol.
*/
@DefaultConverter
@ConfigItem(defaultValue = "TLSv1.3,TLSv1.2")
public List<String> protocols;
public Set<String> protocols;

/**
* Enables Server Name Indication (SNI), an TLS extension allowing the server to use multiple certificates.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,7 @@ public static HttpServerOptions createSslOptions(HttpBuildTimeConfig buildTimeCo
serverOptions.addEnabledCipherSuite(cipher);
}

for (String protocol : sslConfig.protocols) {
if (!protocol.isEmpty()) {
serverOptions.addEnabledSecureTransportProtocol(protocol);
}
}
serverOptions.setEnabledSecureTransportProtocols(sslConfig.protocols);
serverOptions.setSsl(true);
serverOptions.setSni(sslConfig.sni);
int sslPort = httpConfiguration.determineSslPort(launchMode);
Expand Down Expand Up @@ -224,11 +220,8 @@ public static HttpServerOptions createSslOptionsForManagementInterface(Managemen
serverOptions.addEnabledCipherSuite(cipher);
}

for (String protocol : sslConfig.protocols) {
if (!protocol.isEmpty()) {
serverOptions.addEnabledSecureTransportProtocol(protocol);
}
}
serverOptions.setEnabledSecureTransportProtocols(sslConfig.protocols);

serverOptions.setSsl(true);
serverOptions.setSni(sslConfig.sni);
int sslPort = httpConfiguration.determinePort(launchMode);
Expand Down
5 changes: 5 additions & 0 deletions integration-tests/vertx-http/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-web-client</artifactId>
<scope>test</scope>
</dependency>

<!-- Minimal test dependencies to *-deployment artifacts for consistent build order -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.quarkus.it.vertx;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@Path("/hello")
public class HelloResource {

@GET
public String hello() {
return "hello";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.quarkus.it.vertx;

import java.util.Map;

import io.quarkus.test.junit.QuarkusTestProfile;

public class ServerWithTLS13Only implements QuarkusTestProfile {

@Override
public Map<String, String> getConfigOverrides() {
return Map.of(
"quarkus.http.ssl.protocols", "TLSv1.3");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package io.quarkus.it.vertx;

import java.util.Set;
import java.util.concurrent.CompletionException;

import javax.net.ssl.SSLHandshakeException;

import jakarta.inject.Inject;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import io.quarkus.test.common.http.TestHTTPResource;
import io.quarkus.test.junit.QuarkusTest;
import io.vertx.core.net.JksOptions;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.mutiny.core.Vertx;
import io.vertx.mutiny.ext.web.client.WebClient;

@QuarkusTest
public class TlsProtocolVersionDefaultTestCase {

@TestHTTPResource(value = "/hello", ssl = true)
String url;

@Inject
Vertx vertx;

@Test
void testWithWebClientRequestingMultipleTlsVersions() {
// The Web client is requesting TLS 1.2 or 1.3, the server is exposing 1.3 - all good
WebClient client = WebClient.create(vertx, new WebClientOptions().setSsl(true)
.setKeyStoreOptions(
new JksOptions().setPath("src/test/resources/client-keystore-1.jks").setPassword("password"))
.setTrustStoreOptions(
new JksOptions().setPath("src/test/resources/client-truststore.jks").setPassword("password"))
.setVerifyHost(false));
var resp = client.getAbs(url).sendAndAwait();
Assertions.assertEquals(200, resp.statusCode());
}

@Test
void testWithWebClientRequestingTls13() {
// The Web client is requesting TLS 1.3, the server is exposing 1.3 - all good
WebClient client = WebClient.create(vertx, new WebClientOptions().setSsl(true)
.setEnabledSecureTransportProtocols(Set.of("TLSv1.3"))
.setKeyStoreOptions(
new JksOptions().setPath("src/test/resources/client-keystore-1.jks").setPassword("password"))
.setTrustStoreOptions(
new JksOptions().setPath("src/test/resources/client-truststore.jks").setPassword("password"))
.setVerifyHost(false));
var resp = client.getAbs(url).sendAndAwait();
Assertions.assertEquals(200, resp.statusCode());
}

@Test
void testWithWebClientRequestingTls12() {
// The Web client is requesting TLS 1.2, the server is exposing 1.2 and 1.3 - all good
WebClient client = WebClient.create(vertx, new WebClientOptions().setSsl(true)
.setEnabledSecureTransportProtocols(Set.of("TLSv1.2"))
.setKeyStoreOptions(
new JksOptions().setPath("src/test/resources/client-keystore-1.jks").setPassword("password"))
.setTrustStoreOptions(
new JksOptions().setPath("src/test/resources/client-truststore.jks").setPassword("password"))
.setVerifyHost(false));
var resp = client.getAbs(url).sendAndAwait();
Assertions.assertEquals(200, resp.statusCode());
}

@Test
void testWithWebClientRequestingTls11() {
// The Web client is requesting TLS 1.1, the server is exposing 1.2 and 1.3 - KO
WebClient client = WebClient.create(vertx, new WebClientOptions().setSsl(true)
.setEnabledSecureTransportProtocols(Set.of("TLSv1.1"))
.setKeyStoreOptions(
new JksOptions().setPath("src/test/resources/client-keystore-1.jks").setPassword("password"))
.setTrustStoreOptions(
new JksOptions().setPath("src/test/resources/client-truststore.jks").setPassword("password"))
.setVerifyHost(false));
Throwable exception = Assertions.assertThrows(CompletionException.class, () -> client.getAbs(url).sendAndAwait());
Assertions.assertTrue(exception.getCause() instanceof SSLHandshakeException);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.quarkus.it.vertx;

import java.util.Set;
import java.util.concurrent.CompletionException;

import javax.net.ssl.SSLHandshakeException;

import jakarta.inject.Inject;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import io.quarkus.test.common.http.TestHTTPResource;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.TestProfile;
import io.vertx.core.net.JksOptions;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.mutiny.core.Vertx;
import io.vertx.mutiny.ext.web.client.WebClient;

@QuarkusTest
@TestProfile(ServerWithTLS13Only.class)
public class TlsProtocolVersionSelectionTestCase {

@TestHTTPResource(value = "/hello", ssl = true)
String url;

@Inject
Vertx vertx;

@Test
void testWithWebClientRequestingMultipleTlsVersions() {
// The Web client is requesting TLS 1.2 or 1.3, the server is exposing 1.3 - all good
WebClient client = WebClient.create(vertx, new WebClientOptions().setSsl(true)
.setKeyStoreOptions(
new JksOptions().setPath("src/test/resources/client-keystore-1.jks").setPassword("password"))
.setTrustStoreOptions(
new JksOptions().setPath("src/test/resources/client-truststore.jks").setPassword("password"))
.setVerifyHost(false));
var resp = client.getAbs(url).sendAndAwait();
Assertions.assertEquals(200, resp.statusCode());
}

@Test
void testWithWebClientRequestingTls13() {
// The Web client is requesting TLS 1.3, the server is exposing 1.3 - all good
WebClient client = WebClient.create(vertx, new WebClientOptions().setSsl(true)
.setEnabledSecureTransportProtocols(Set.of("TLSv1.3"))
.setKeyStoreOptions(
new JksOptions().setPath("src/test/resources/client-keystore-1.jks").setPassword("password"))
.setTrustStoreOptions(
new JksOptions().setPath("src/test/resources/client-truststore.jks").setPassword("password"))
.setVerifyHost(false));
var resp = client.getAbs(url).sendAndAwait();
Assertions.assertEquals(200, resp.statusCode());
}

@Test
void testWithWebClientRequestingTls12() {
// The Web client is requesting TLS 1.2, the server is exposing 1.3 - KO
WebClient client = WebClient.create(vertx, new WebClientOptions().setSsl(true)
.setEnabledSecureTransportProtocols(Set.of("TLSv1.2"))
.setKeyStoreOptions(
new JksOptions().setPath("src/test/resources/client-keystore-1.jks").setPassword("password"))
.setTrustStoreOptions(
new JksOptions().setPath("src/test/resources/client-truststore.jks").setPassword("password"))
.setVerifyHost(false));
Throwable exception = Assertions.assertThrows(CompletionException.class, () -> client.getAbs(url).sendAndAwait());
Assertions.assertTrue(exception.getCause() instanceof SSLHandshakeException);
}

@Test
void testWithWebClientRequestingTls11() {
// The Web client is requesting TLS 1.1, the server is exposing 1.3 - KO
WebClient client = WebClient.create(vertx, new WebClientOptions().setSsl(true)
.setEnabledSecureTransportProtocols(Set.of("TLSv1.1"))
.setKeyStoreOptions(
new JksOptions().setPath("src/test/resources/client-keystore-1.jks").setPassword("password"))
.setTrustStoreOptions(
new JksOptions().setPath("src/test/resources/client-truststore.jks").setPassword("password"))
.setVerifyHost(false));
Throwable exception = Assertions.assertThrows(CompletionException.class, () -> client.getAbs(url).sendAndAwait());
Assertions.assertTrue(exception.getCause() instanceof SSLHandshakeException);
}
}
Loading