mirror of
https://github.com/google/nomulus.git
synced 2025-04-29 19:47:51 +02:00
Reject handshakes with bad TLS protocols and ciphers (#970)
* Reject handshakes with bad TLS protocols and ciphers * Fix protocols * make cipher suite list static and fix tests * Delete unnecessary line * Add start time configuration for enforcement * small format fix * Add multiple ciphersuite test * fix gradle lint * fix indentation
This commit is contained in:
parent
7aa7bad986
commit
af50677612
13 changed files with 292 additions and 12 deletions
|
@ -28,6 +28,7 @@ dependencies {
|
||||||
compile deps['org.bouncycastle:bcpkix-jdk15on']
|
compile deps['org.bouncycastle:bcpkix-jdk15on']
|
||||||
compile deps['org.bouncycastle:bcprov-jdk15on']
|
compile deps['org.bouncycastle:bcprov-jdk15on']
|
||||||
compile project(':util')
|
compile project(':util')
|
||||||
|
compile project(':common')
|
||||||
|
|
||||||
runtime deps['com.google.flogger:flogger-system-backend']
|
runtime deps['com.google.flogger:flogger-system-backend']
|
||||||
runtime deps['io.netty:netty-tcnative-boringssl-static']
|
runtime deps['io.netty:netty-tcnative-boringssl-static']
|
||||||
|
@ -38,9 +39,11 @@ dependencies {
|
||||||
testCompile deps['org.junit.jupiter:junit-jupiter-params']
|
testCompile deps['org.junit.jupiter:junit-jupiter-params']
|
||||||
testCompile deps['org.bouncycastle:bcpkix-jdk15on']
|
testCompile deps['org.bouncycastle:bcpkix-jdk15on']
|
||||||
testCompile deps['org.bouncycastle:bcprov-jdk15on']
|
testCompile deps['org.bouncycastle:bcprov-jdk15on']
|
||||||
|
testCompile project(path: ':common', configuration: 'testing')
|
||||||
|
|
||||||
annotationProcessor deps['com.google.dagger:dagger-compiler']
|
annotationProcessor deps['com.google.dagger:dagger-compiler']
|
||||||
testAnnotationProcessor deps['com.google.dagger:dagger-compiler']
|
testAnnotationProcessor deps['com.google.dagger:dagger-compiler']
|
||||||
|
compile 'joda-time:joda-time:2.9.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make testing artifacts available to be depended up on by other projects.
|
// Make testing artifacts available to be depended up on by other projects.
|
||||||
|
|
|
@ -19,6 +19,7 @@ import static google.registry.util.X509Utils.getCertificateHash;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
|
import google.registry.util.Clock;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelHandler.Sharable;
|
import io.netty.channel.ChannelHandler.Sharable;
|
||||||
|
@ -29,6 +30,7 @@ import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SslContextBuilder;
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
import io.netty.handler.ssl.SslHandler;
|
import io.netty.handler.ssl.SslHandler;
|
||||||
import io.netty.handler.ssl.SslProvider;
|
import io.netty.handler.ssl.SslProvider;
|
||||||
|
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
|
||||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
|
@ -41,6 +43,7 @@ import java.security.cert.X509Certificate;
|
||||||
import java.security.interfaces.RSAPublicKey;
|
import java.security.interfaces.RSAPublicKey;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a server side SSL handler to the channel pipeline.
|
* Adds a server side SSL handler to the channel pipeline.
|
||||||
|
@ -66,6 +69,29 @@ public class SslServerInitializer<C extends Channel> extends ChannelInitializer<
|
||||||
public static final AttributeKey<Promise<X509Certificate>> CLIENT_CERTIFICATE_PROMISE_KEY =
|
public static final AttributeKey<Promise<X509Certificate>> CLIENT_CERTIFICATE_PROMISE_KEY =
|
||||||
AttributeKey.valueOf("CLIENT_CERTIFICATE_PROMISE_KEY");
|
AttributeKey.valueOf("CLIENT_CERTIFICATE_PROMISE_KEY");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of cipher suites that are currently acceptable to create a successful handshake.
|
||||||
|
*
|
||||||
|
* <p>This list includes all of the current TLS1.3 ciphers and a collection of TLS1.2 ciphers with
|
||||||
|
* no known security vulnerabilities. Note that OpenSSL uses a separate nomenclature for the
|
||||||
|
* ciphers internally but the IANA names listed here will be transparently translated by the
|
||||||
|
* OpenSSL provider (if used), so there is no need to include the OpenSSL name variants here. More
|
||||||
|
* information about these cipher suites and their OpenSSL names can be found at ciphersuite.info.
|
||||||
|
*/
|
||||||
|
private static final ImmutableList ALLOWED_TLS_CIPHERS =
|
||||||
|
ImmutableList.of(
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_AES_128_CCM_SHA256",
|
||||||
|
"TLS_AES_128_CCM_8_SHA256");
|
||||||
|
|
||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||||
private final boolean requireClientCert;
|
private final boolean requireClientCert;
|
||||||
// TODO(jianglai): Always validate client certs (if required).
|
// TODO(jianglai): Always validate client certs (if required).
|
||||||
|
@ -76,13 +102,19 @@ public class SslServerInitializer<C extends Channel> extends ChannelInitializer<
|
||||||
private final Supplier<PrivateKey> privateKeySupplier;
|
private final Supplier<PrivateKey> privateKeySupplier;
|
||||||
private final Supplier<ImmutableList<X509Certificate>> certificatesSupplier;
|
private final Supplier<ImmutableList<X509Certificate>> certificatesSupplier;
|
||||||
private final ImmutableList<String> supportedSslVersions;
|
private final ImmutableList<String> supportedSslVersions;
|
||||||
|
// TODO(sarahbot): Remove this variable and its check after enforcement start date has passed.
|
||||||
|
private final ImmutableList<String> oldSupportedSslVersions;
|
||||||
|
private final DateTime enforcementStartTime;
|
||||||
|
private final Clock clock;
|
||||||
|
|
||||||
public SslServerInitializer(
|
public SslServerInitializer(
|
||||||
boolean requireClientCert,
|
boolean requireClientCert,
|
||||||
boolean validateClientCert,
|
boolean validateClientCert,
|
||||||
SslProvider sslProvider,
|
SslProvider sslProvider,
|
||||||
Supplier<PrivateKey> privateKeySupplier,
|
Supplier<PrivateKey> privateKeySupplier,
|
||||||
Supplier<ImmutableList<X509Certificate>> certificatesSupplier) {
|
Supplier<ImmutableList<X509Certificate>> certificatesSupplier,
|
||||||
|
DateTime enforcementStartTime,
|
||||||
|
Clock clock) {
|
||||||
logger.atInfo().log("Server SSL Provider: %s", sslProvider);
|
logger.atInfo().log("Server SSL Provider: %s", sslProvider);
|
||||||
checkArgument(
|
checkArgument(
|
||||||
requireClientCert || !validateClientCert,
|
requireClientCert || !validateClientCert,
|
||||||
|
@ -94,10 +126,16 @@ public class SslServerInitializer<C extends Channel> extends ChannelInitializer<
|
||||||
this.certificatesSupplier = certificatesSupplier;
|
this.certificatesSupplier = certificatesSupplier;
|
||||||
this.supportedSslVersions =
|
this.supportedSslVersions =
|
||||||
sslProvider == SslProvider.OPENSSL
|
sslProvider == SslProvider.OPENSSL
|
||||||
? ImmutableList.of("TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1")
|
? ImmutableList.of("TLSv1.3", "TLSv1.2")
|
||||||
// JDK support for TLS 1.3 won't be available until 2020-07-14 at the earliest.
|
// JDK support for TLS 1.3 won't be available until 2021-04-20 at the earliest.
|
||||||
// See: https://java.com/en/jre-jdk-cryptoroadmap.html
|
// See: https://java.com/en/jre-jdk-cryptoroadmap.html
|
||||||
|
: ImmutableList.of("TLSv1.2");
|
||||||
|
this.oldSupportedSslVersions =
|
||||||
|
sslProvider == SslProvider.OPENSSL
|
||||||
|
? ImmutableList.of("TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1")
|
||||||
: ImmutableList.of("TLSv1.2", "TLSv1.1", "TLSv1");
|
: ImmutableList.of("TLSv1.2", "TLSv1.1", "TLSv1");
|
||||||
|
this.enforcementStartTime = enforcementStartTime;
|
||||||
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,8 +147,15 @@ public class SslServerInitializer<C extends Channel> extends ChannelInitializer<
|
||||||
.sslProvider(sslProvider)
|
.sslProvider(sslProvider)
|
||||||
.trustManager(InsecureTrustManagerFactory.INSTANCE)
|
.trustManager(InsecureTrustManagerFactory.INSTANCE)
|
||||||
.clientAuth(requireClientCert ? ClientAuth.REQUIRE : ClientAuth.NONE)
|
.clientAuth(requireClientCert ? ClientAuth.REQUIRE : ClientAuth.NONE)
|
||||||
.protocols(supportedSslVersions)
|
.protocols(
|
||||||
|
enforcementStartTime.isBefore(clock.nowUtc())
|
||||||
|
? supportedSslVersions
|
||||||
|
: oldSupportedSslVersions)
|
||||||
|
.ciphers(
|
||||||
|
enforcementStartTime.isBefore(clock.nowUtc()) ? ALLOWED_TLS_CIPHERS : null,
|
||||||
|
SupportedCipherSuiteFilter.INSTANCE)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
logger.atInfo().log("Available Cipher Suites: %s", sslContext.cipherSuites());
|
logger.atInfo().log("Available Cipher Suites: %s", sslContext.cipherSuites());
|
||||||
SslHandler sslHandler = sslContext.newHandler(channel.alloc());
|
SslHandler sslHandler = sslContext.newHandler(channel.alloc());
|
||||||
if (requireClientCert) {
|
if (requireClientCert) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import static google.registry.networking.handler.SslServerInitializer.CLIENT_CER
|
||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.util.SelfSignedCaCertificate;
|
import google.registry.util.SelfSignedCaCertificate;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
@ -42,13 +43,16 @@ import java.security.cert.CertificateNotYetValidException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
import javax.net.ssl.SSLHandshakeException;
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
import javax.net.ssl.SSLParameters;
|
import javax.net.ssl.SSLParameters;
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
@ -97,19 +101,29 @@ class SslServerInitializerTest {
|
||||||
validateClientCert,
|
validateClientCert,
|
||||||
sslProvider,
|
sslProvider,
|
||||||
Suppliers.ofInstance(privateKey),
|
Suppliers.ofInstance(privateKey),
|
||||||
Suppliers.ofInstance(ImmutableList.copyOf(certificates)));
|
Suppliers.ofInstance(ImmutableList.copyOf(certificates)),
|
||||||
|
DateTime.parse("2021-04-01T16:00:00Z"),
|
||||||
|
new FakeClock(DateTime.parse("2021-05-01T16:00:00Z")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChannelHandler getClientHandler(
|
private ChannelHandler getClientHandler(
|
||||||
SslProvider sslProvider,
|
SslProvider sslProvider,
|
||||||
X509Certificate trustedCertificate,
|
X509Certificate trustedCertificate,
|
||||||
PrivateKey privateKey,
|
PrivateKey privateKey,
|
||||||
X509Certificate certificate) {
|
X509Certificate certificate,
|
||||||
|
String protocol,
|
||||||
|
List<String> cipher) {
|
||||||
return new ChannelInitializer<LocalChannel>() {
|
return new ChannelInitializer<LocalChannel>() {
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(LocalChannel ch) throws Exception {
|
protected void initChannel(LocalChannel ch) throws Exception {
|
||||||
SslContextBuilder sslContextBuilder =
|
SslContextBuilder sslContextBuilder =
|
||||||
SslContextBuilder.forClient().trustManager(trustedCertificate).sslProvider(sslProvider);
|
SslContextBuilder.forClient()
|
||||||
|
.trustManager(trustedCertificate)
|
||||||
|
.sslProvider(sslProvider)
|
||||||
|
.ciphers(cipher);
|
||||||
|
if (protocol != null) {
|
||||||
|
sslContextBuilder.protocols(protocol);
|
||||||
|
}
|
||||||
if (privateKey != null && certificate != null) {
|
if (privateKey != null && certificate != null) {
|
||||||
sslContextBuilder.keyManager(privateKey, certificate);
|
sslContextBuilder.keyManager(privateKey, certificate);
|
||||||
}
|
}
|
||||||
|
@ -127,6 +141,14 @@ class SslServerInitializerTest {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ChannelHandler getClientHandler(
|
||||||
|
SslProvider sslProvider,
|
||||||
|
X509Certificate trustedCertificate,
|
||||||
|
PrivateKey privateKey,
|
||||||
|
X509Certificate certificate) {
|
||||||
|
return getClientHandler(sslProvider, trustedCertificate, privateKey, certificate, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("provideTestCombinations")
|
@MethodSource("provideTestCombinations")
|
||||||
void testSuccess_swappedInitializerWithSslHandler(SslProvider sslProvider) throws Exception {
|
void testSuccess_swappedInitializerWithSslHandler(SslProvider sslProvider) throws Exception {
|
||||||
|
@ -137,7 +159,9 @@ class SslServerInitializerTest {
|
||||||
false,
|
false,
|
||||||
sslProvider,
|
sslProvider,
|
||||||
Suppliers.ofInstance(ssc.key()),
|
Suppliers.ofInstance(ssc.key()),
|
||||||
Suppliers.ofInstance(ImmutableList.of(ssc.cert())));
|
Suppliers.ofInstance(ImmutableList.of(ssc.cert())),
|
||||||
|
DateTime.parse("2021-04-01T16:00:00Z"),
|
||||||
|
new FakeClock(DateTime.parse("2021-05-01T16:00:00Z")));
|
||||||
EmbeddedChannel channel = new EmbeddedChannel();
|
EmbeddedChannel channel = new EmbeddedChannel();
|
||||||
ChannelPipeline pipeline = channel.pipeline();
|
ChannelPipeline pipeline = channel.pipeline();
|
||||||
pipeline.addLast(sslServerInitializer);
|
pipeline.addLast(sslServerInitializer);
|
||||||
|
@ -172,6 +196,174 @@ class SslServerInitializerTest {
|
||||||
assertThat(sslSession.getPeerCertificates()).asList().containsExactly(serverSsc.cert());
|
assertThat(sslSession.getPeerCertificates()).asList().containsExactly(serverSsc.cert());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideTestCombinations")
|
||||||
|
void testFailure_cipherNotAccepted(SslProvider sslProvider) throws Exception {
|
||||||
|
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
|
||||||
|
LocalAddress localAddress = new LocalAddress("CIPHER_NOT_ACCEPTED_" + sslProvider);
|
||||||
|
|
||||||
|
nettyExtension.setUpServer(
|
||||||
|
localAddress, getServerHandler(true, true, sslProvider, serverSsc.key(), serverSsc.cert()));
|
||||||
|
SelfSignedCaCertificate clientSsc =
|
||||||
|
SelfSignedCaCertificate.create(
|
||||||
|
"CLIENT",
|
||||||
|
Date.from(Instant.now().minus(Duration.ofDays(2))),
|
||||||
|
Date.from(Instant.now().plus(Duration.ofDays(1))));
|
||||||
|
nettyExtension.setUpClient(
|
||||||
|
localAddress,
|
||||||
|
getClientHandler(
|
||||||
|
sslProvider,
|
||||||
|
serverSsc.cert(),
|
||||||
|
clientSsc.key(),
|
||||||
|
clientSsc.cert(),
|
||||||
|
"TLSv1.2",
|
||||||
|
Collections.singletonList("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")));
|
||||||
|
|
||||||
|
verifySslException(
|
||||||
|
nettyExtension.getServerChannel(),
|
||||||
|
channel -> channel.attr(CLIENT_CERTIFICATE_PROMISE_KEY).get().get(),
|
||||||
|
SSLHandshakeException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideTestCombinations")
|
||||||
|
void testSuccess_someCiphersNotAccepted(SslProvider sslProvider) throws Exception {
|
||||||
|
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
|
||||||
|
LocalAddress localAddress = new LocalAddress("SOME_CIPHERS_NOT_ACCEPTED_" + sslProvider);
|
||||||
|
|
||||||
|
nettyExtension.setUpServer(
|
||||||
|
localAddress,
|
||||||
|
new SslServerInitializer<LocalChannel>(
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
sslProvider,
|
||||||
|
Suppliers.ofInstance(serverSsc.key()),
|
||||||
|
Suppliers.ofInstance(ImmutableList.of(serverSsc.cert())),
|
||||||
|
DateTime.parse("2021-04-01T16:00:00Z"),
|
||||||
|
new FakeClock(DateTime.parse("2021-05-01T16:00:00Z"))));
|
||||||
|
SelfSignedCaCertificate clientSsc =
|
||||||
|
SelfSignedCaCertificate.create(
|
||||||
|
"CLIENT",
|
||||||
|
Date.from(Instant.now().minus(Duration.ofDays(2))),
|
||||||
|
Date.from(Instant.now().plus(Duration.ofDays(1))));
|
||||||
|
nettyExtension.setUpClient(
|
||||||
|
localAddress,
|
||||||
|
getClientHandler(
|
||||||
|
sslProvider,
|
||||||
|
serverSsc.cert(),
|
||||||
|
clientSsc.key(),
|
||||||
|
clientSsc.cert(),
|
||||||
|
"TLSv1.2",
|
||||||
|
ImmutableList.of(
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // Only accepted cipher
|
||||||
|
"TLS_RSA_WITH_AES_256_CBC_SHA")));
|
||||||
|
|
||||||
|
SSLSession sslSession = setUpSslChannel(nettyExtension.getClientChannel(), serverSsc.cert());
|
||||||
|
nettyExtension.assertThatMessagesWork();
|
||||||
|
|
||||||
|
assertThat(sslSession.getLocalCertificates()).asList().containsExactly(clientSsc.cert());
|
||||||
|
assertThat(sslSession.getPeerCertificates()).asList().containsExactly(serverSsc.cert());
|
||||||
|
assertThat(sslSession.getCipherSuite()).isEqualTo("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideTestCombinations")
|
||||||
|
void testSuccess_cipherNotAccepted_beforeEnforcementDate(SslProvider sslProvider)
|
||||||
|
throws Exception {
|
||||||
|
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
|
||||||
|
LocalAddress localAddress = new LocalAddress("CIPHER_ACCEPTED_BEFORE_DATE_" + sslProvider);
|
||||||
|
|
||||||
|
nettyExtension.setUpServer(
|
||||||
|
localAddress,
|
||||||
|
new SslServerInitializer<LocalChannel>(
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
sslProvider,
|
||||||
|
Suppliers.ofInstance(serverSsc.key()),
|
||||||
|
Suppliers.ofInstance(ImmutableList.of(serverSsc.cert())),
|
||||||
|
DateTime.parse("2021-04-01T16:00:00Z"),
|
||||||
|
new FakeClock(DateTime.parse("2021-03-01T16:00:00Z"))));
|
||||||
|
SelfSignedCaCertificate clientSsc =
|
||||||
|
SelfSignedCaCertificate.create(
|
||||||
|
"CLIENT",
|
||||||
|
Date.from(Instant.now().minus(Duration.ofDays(2))),
|
||||||
|
Date.from(Instant.now().plus(Duration.ofDays(1))));
|
||||||
|
nettyExtension.setUpClient(
|
||||||
|
localAddress,
|
||||||
|
getClientHandler(
|
||||||
|
sslProvider,
|
||||||
|
serverSsc.cert(),
|
||||||
|
clientSsc.key(),
|
||||||
|
clientSsc.cert(),
|
||||||
|
"TLSv1.2",
|
||||||
|
Collections.singletonList("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")));
|
||||||
|
|
||||||
|
SSLSession sslSession = setUpSslChannel(nettyExtension.getClientChannel(), serverSsc.cert());
|
||||||
|
nettyExtension.assertThatMessagesWork();
|
||||||
|
|
||||||
|
assertThat(sslSession.getLocalCertificates()).asList().containsExactly(clientSsc.cert());
|
||||||
|
assertThat(sslSession.getPeerCertificates()).asList().containsExactly(serverSsc.cert());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideTestCombinations")
|
||||||
|
void testFailure_protocolNotAccepted(SslProvider sslProvider) throws Exception {
|
||||||
|
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
|
||||||
|
LocalAddress localAddress = new LocalAddress("PROTOCOL_NOT_ACCEPTED_" + sslProvider);
|
||||||
|
|
||||||
|
nettyExtension.setUpServer(
|
||||||
|
localAddress, getServerHandler(true, true, sslProvider, serverSsc.key(), serverSsc.cert()));
|
||||||
|
SelfSignedCaCertificate clientSsc =
|
||||||
|
SelfSignedCaCertificate.create(
|
||||||
|
"CLIENT",
|
||||||
|
Date.from(Instant.now().minus(Duration.ofDays(2))),
|
||||||
|
Date.from(Instant.now().plus(Duration.ofDays(1))));
|
||||||
|
nettyExtension.setUpClient(
|
||||||
|
localAddress,
|
||||||
|
getClientHandler(
|
||||||
|
sslProvider, serverSsc.cert(), clientSsc.key(), clientSsc.cert(), "TLSv1.1", null));
|
||||||
|
|
||||||
|
verifySslException(
|
||||||
|
nettyExtension.getServerChannel(),
|
||||||
|
channel -> channel.attr(CLIENT_CERTIFICATE_PROMISE_KEY).get().get(),
|
||||||
|
SSLHandshakeException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideTestCombinations")
|
||||||
|
void testSuccess_protocolNotAccepted_beforeEnforcementDate(SslProvider sslProvider)
|
||||||
|
throws Exception {
|
||||||
|
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
|
||||||
|
LocalAddress localAddress = new LocalAddress("PROTOCOL_ACCEPTED_BEFORE_DATE_" + sslProvider);
|
||||||
|
|
||||||
|
nettyExtension.setUpServer(
|
||||||
|
localAddress,
|
||||||
|
new SslServerInitializer<LocalChannel>(
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
sslProvider,
|
||||||
|
Suppliers.ofInstance(serverSsc.key()),
|
||||||
|
Suppliers.ofInstance(ImmutableList.of(serverSsc.cert())),
|
||||||
|
DateTime.parse("2021-04-01T16:00:00Z"),
|
||||||
|
new FakeClock(DateTime.parse("2021-03-01T16:00:00Z"))));
|
||||||
|
SelfSignedCaCertificate clientSsc =
|
||||||
|
SelfSignedCaCertificate.create(
|
||||||
|
"CLIENT",
|
||||||
|
Date.from(Instant.now().minus(Duration.ofDays(2))),
|
||||||
|
Date.from(Instant.now().plus(Duration.ofDays(1))));
|
||||||
|
nettyExtension.setUpClient(
|
||||||
|
localAddress,
|
||||||
|
getClientHandler(
|
||||||
|
sslProvider, serverSsc.cert(), clientSsc.key(), clientSsc.cert(), "TLSv1.1", null));
|
||||||
|
|
||||||
|
SSLSession sslSession = setUpSslChannel(nettyExtension.getClientChannel(), serverSsc.cert());
|
||||||
|
nettyExtension.assertThatMessagesWork();
|
||||||
|
|
||||||
|
assertThat(sslSession.getLocalCertificates()).asList().containsExactly(clientSsc.cert());
|
||||||
|
assertThat(sslSession.getPeerCertificates()).asList().containsExactly(serverSsc.cert());
|
||||||
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("provideTestCombinations")
|
@MethodSource("provideTestCombinations")
|
||||||
void testFailure_clientCertExpired(SslProvider sslProvider) throws Exception {
|
void testFailure_clientCertExpired(SslProvider sslProvider) throws Exception {
|
||||||
|
|
|
@ -50,6 +50,7 @@ import javax.inject.Named;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
import javax.inject.Qualifier;
|
import javax.inject.Qualifier;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
/** A module that provides the {@link FrontendProtocol} used for epp protocol. */
|
/** A module that provides the {@link FrontendProtocol} used for epp protocol. */
|
||||||
@Module
|
@Module
|
||||||
|
@ -159,11 +160,19 @@ public final class EppProtocolModule {
|
||||||
@Provides
|
@Provides
|
||||||
@EppProtocol
|
@EppProtocol
|
||||||
static SslServerInitializer<NioSocketChannel> provideSslServerInitializer(
|
static SslServerInitializer<NioSocketChannel> provideSslServerInitializer(
|
||||||
|
ProxyConfig config,
|
||||||
SslProvider sslProvider,
|
SslProvider sslProvider,
|
||||||
Supplier<PrivateKey> privateKeySupplier,
|
Supplier<PrivateKey> privateKeySupplier,
|
||||||
Supplier<ImmutableList<X509Certificate>> certificatesSupplier) {
|
Supplier<ImmutableList<X509Certificate>> certificatesSupplier,
|
||||||
|
Clock clock) {
|
||||||
return new SslServerInitializer<>(
|
return new SslServerInitializer<>(
|
||||||
true, false, sslProvider, privateKeySupplier, certificatesSupplier);
|
true,
|
||||||
|
false,
|
||||||
|
sslProvider,
|
||||||
|
privateKeySupplier,
|
||||||
|
certificatesSupplier,
|
||||||
|
DateTime.parse(config.tlsEnforcementStartTime),
|
||||||
|
clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
@ -48,6 +48,7 @@ public class ProxyConfig {
|
||||||
public WebWhois webWhois;
|
public WebWhois webWhois;
|
||||||
public HttpsRelay httpsRelay;
|
public HttpsRelay httpsRelay;
|
||||||
public Metrics metrics;
|
public Metrics metrics;
|
||||||
|
public String tlsEnforcementStartTime;
|
||||||
|
|
||||||
/** Configuration options that apply to GCS. */
|
/** Configuration options that apply to GCS. */
|
||||||
public static class Gcs {
|
public static class Gcs {
|
||||||
|
|
|
@ -21,6 +21,8 @@ import dagger.multibindings.IntoSet;
|
||||||
import google.registry.networking.handler.SslServerInitializer;
|
import google.registry.networking.handler.SslServerInitializer;
|
||||||
import google.registry.proxy.Protocol.FrontendProtocol;
|
import google.registry.proxy.Protocol.FrontendProtocol;
|
||||||
import google.registry.proxy.handler.WebWhoisRedirectHandler;
|
import google.registry.proxy.handler.WebWhoisRedirectHandler;
|
||||||
|
import google.registry.util.Clock;
|
||||||
|
import google.registry.util.DateTimeUtils;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
import io.netty.handler.codec.http.HttpServerCodec;
|
import io.netty.handler.codec.http.HttpServerCodec;
|
||||||
|
@ -133,8 +135,15 @@ public final class WebWhoisProtocolsModule {
|
||||||
static SslServerInitializer<NioSocketChannel> provideSslServerInitializer(
|
static SslServerInitializer<NioSocketChannel> provideSslServerInitializer(
|
||||||
SslProvider sslProvider,
|
SslProvider sslProvider,
|
||||||
Supplier<PrivateKey> privateKeySupplier,
|
Supplier<PrivateKey> privateKeySupplier,
|
||||||
Supplier<ImmutableList<X509Certificate>> certificatesSupplier) {
|
Supplier<ImmutableList<X509Certificate>> certificatesSupplier,
|
||||||
|
Clock clock) {
|
||||||
return new SslServerInitializer<>(
|
return new SslServerInitializer<>(
|
||||||
false, false, sslProvider, privateKeySupplier, certificatesSupplier);
|
false,
|
||||||
|
false,
|
||||||
|
sslProvider,
|
||||||
|
privateKeySupplier,
|
||||||
|
certificatesSupplier,
|
||||||
|
DateTimeUtils.END_OF_TIME,
|
||||||
|
clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
# GCP project ID
|
# GCP project ID
|
||||||
projectId: your-gcp-project-id
|
projectId: your-gcp-project-id
|
||||||
|
|
||||||
|
# Time to begin enforcement of TLS versions and cipher suites.
|
||||||
|
tlsEnforcementStartTime: "2021-04-01T16:00:00Z"
|
||||||
|
|
||||||
# OAuth scope that the GoogleCredential will be constructed with. This list
|
# OAuth scope that the GoogleCredential will be constructed with. This list
|
||||||
# should include all service scopes that the proxy depends on.
|
# should include all service scopes that the proxy depends on.
|
||||||
gcpScopes:
|
gcpScopes:
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
# Add environment-specific proxy configuration here.
|
# Add environment-specific proxy configuration here.
|
||||||
|
|
||||||
|
# Time to begin enforcement of TLS versions and cipher suites.
|
||||||
|
tlsEnforcementStartTime: "1970-01-01T00:00:00Z"
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
# Add environment-specific proxy configuration here.
|
# Add environment-specific proxy configuration here.
|
||||||
|
|
||||||
|
# Time to begin enforcement of TLS versions and cipher suites.
|
||||||
|
tlsEnforcementStartTime: "1970-01-01T00:00:00Z"
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
# Add environment-specific proxy configuration here.
|
# Add environment-specific proxy configuration here.
|
||||||
|
|
||||||
|
# Time to begin enforcement of TLS versions and cipher suites.
|
||||||
|
tlsEnforcementStartTime: "1970-01-01T00:00:00Z"
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
# Add environment-specific proxy configuration here.
|
# Add environment-specific proxy configuration here.
|
||||||
|
|
||||||
|
# Time to begin enforcement of TLS versions and cipher suites.
|
||||||
|
tlsEnforcementStartTime: "1970-01-01T00:00:00Z"
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
# Add environment-specific proxy configuration here.
|
# Add environment-specific proxy configuration here.
|
||||||
|
|
||||||
|
# Time to begin enforcement of TLS versions and cipher suites.
|
||||||
|
tlsEnforcementStartTime: "1970-01-01T00:00:00Z"
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
# Add environment-specific proxy configuration here.
|
# Add environment-specific proxy configuration here.
|
||||||
|
|
||||||
|
# Time to begin enforcement of TLS versions and cipher suites.
|
||||||
|
tlsEnforcementStartTime: "1970-01-01T00:00:00Z"
|
||||||
|
|
Loading…
Add table
Reference in a new issue