Remove enforcement date from the SslServerInitializer (#1117)

The enforcement data has passed and ICANN has confirmed that their web
WHOIS prober conforms to our requirements.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/1117)
<!-- Reviewable:end -->
This commit is contained in:
Lai Jiang 2021-04-30 15:44:03 -04:00 committed by GitHub
parent eb6a1fe1ed
commit 8d63cbfca0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 37 additions and 141 deletions

View file

@ -43,7 +43,6 @@ dependencies {
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.

View file

@ -19,7 +19,6 @@ 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;
@ -43,7 +42,6 @@ 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.
@ -102,19 +100,13 @@ 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,
@ -130,12 +122,6 @@ public class SslServerInitializer<C extends Channel> extends ChannelInitializer<
// JDK support for TLS 1.3 won't be available until 2021-04-20 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"); : 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");
this.enforcementStartTime = enforcementStartTime;
this.clock = clock;
} }
@Override @Override
@ -147,13 +133,8 @@ 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( .protocols(supportedSslVersions)
enforcementStartTime.isBefore(clock.nowUtc()) .ciphers(ALLOWED_TLS_CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
? 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());

View file

@ -23,7 +23,6 @@ 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;
@ -35,6 +34,7 @@ import io.netty.handler.ssl.OpenSsl;
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 java.nio.channels.ClosedChannelException;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
@ -43,6 +43,7 @@ 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.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -52,8 +53,6 @@ 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.Disabled;
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;
@ -102,9 +101,7 @@ 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(
@ -160,9 +157,7 @@ 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);
@ -239,9 +234,7 @@ class SslServerInitializerTest {
true, true,
sslProvider, sslProvider,
Suppliers.ofInstance(serverSsc.key()), Suppliers.ofInstance(serverSsc.key()),
Suppliers.ofInstance(ImmutableList.of(serverSsc.cert())), 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 clientSsc =
SelfSignedCaCertificate.create( SelfSignedCaCertificate.create(
"CLIENT", "CLIENT",
@ -268,50 +261,6 @@ class SslServerInitializerTest {
assertThat(sslSession.getCipherSuite()).isEqualTo("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"); 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());
}
// This test is a bit tricky to fix because apparently some new OpenJDK 11 version does no
// support TLS 1.1 anymore, and in that case it throws a ClosedChannelException instead of a
// SSLHandShakeException. It's going to be hard to accommodate both the OpenSSL and the JDK
// provider. Disable it for now to unblock people.
@Disabled
@ParameterizedTest @ParameterizedTest
@MethodSource("provideTestCombinations") @MethodSource("provideTestCombinations")
void testFailure_protocolNotAccepted(SslProvider sslProvider) throws Exception { void testFailure_protocolNotAccepted(SslProvider sslProvider) throws Exception {
@ -330,45 +279,24 @@ class SslServerInitializerTest {
getClientHandler( getClientHandler(
sslProvider, serverSsc.cert(), clientSsc.key(), clientSsc.cert(), "TLSv1.1", null)); sslProvider, serverSsc.cert(), clientSsc.key(), clientSsc.cert(), "TLSv1.1", null));
ImmutableList<Integer> jdkVersion =
Arrays.asList(System.getProperty("java.version").split("\\.")).stream()
.map(Integer::parseInt)
.collect(ImmutableList.toImmutableList());
// In JDK v11.0.11 and above TLS 1.1 is not supported any more, in which case attempting to
// connect with TLS 1.1 results in a ClosedChannelException instead of a SSLHandShakeException.
// See https://www.oracle.com/java/technologies/javase/11-0-11-relnotes.html#JDK-8202343
Class<? extends Exception> rootCause =
sslProvider == SslProvider.JDK
&& compareSemanticVersion(jdkVersion, ImmutableList.of(11, 0, 11))
? ClosedChannelException.class
: SSLHandshakeException.class;
verifySslException( verifySslException(
nettyExtension.getServerChannel(), nettyExtension.getServerChannel(),
channel -> channel.attr(CLIENT_CERTIFICATE_PROMISE_KEY).get().get(), channel -> channel.attr(CLIENT_CERTIFICATE_PROMISE_KEY).get().get(),
SSLHandshakeException.class); rootCause);
}
@Disabled
@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
@ -525,4 +453,14 @@ class SslServerInitializerTest {
nettyExtension.assertThatServerRootCause().isInstanceOf(SSLException.class); nettyExtension.assertThatServerRootCause().isInstanceOf(SSLException.class);
assertThat(nettyExtension.getClientChannel().isActive()).isFalse(); assertThat(nettyExtension.getClientChannel().isActive()).isFalse();
} }
/** Returns true if v1 is larger or equals to v2. */
private static boolean compareSemanticVersion(
ImmutableList<Integer> v1, ImmutableList<Integer> v2) {
for (int i : ImmutableList.of(0, 1, 2)) {
if (v1.get(i) > v2.get(i)) return true;
if (v1.get(i) < v2.get(i)) return false;
}
return true;
}
} }

View file

@ -50,7 +50,6 @@ 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
@ -160,19 +159,11 @@ 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, true, false, sslProvider, privateKeySupplier, certificatesSupplier);
false,
sslProvider,
privateKeySupplier,
certificatesSupplier,
DateTime.parse(config.tlsEnforcementStartTime),
clock);
} }
@Provides @Provides

View file

@ -48,7 +48,6 @@ 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 {

View file

@ -21,8 +21,6 @@ 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;
@ -135,15 +133,8 @@ 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, false, sslProvider, privateKeySupplier, certificatesSupplier);
false,
sslProvider,
privateKeySupplier,
certificatesSupplier,
DateTimeUtils.END_OF_TIME,
clock);
} }
} }

View file

@ -8,9 +8,6 @@
# 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: "1970-01-01T00: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: