Remove java.util.Date (#2373)

There is one remaining instance in JpaTransactionManagerImpl that cannot
be removed because DetachingTypedQuery is implementing TypedQuery, which has
a method that expectred java.util.Date.
This commit is contained in:
Lai Jiang 2024-03-15 19:06:00 -04:00 committed by GitHub
parent 6d2eb2e140
commit c68583f666
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 108 additions and 147 deletions

View file

@ -173,17 +173,24 @@ PRESUBMITS = {
):
"JavaScript files should not include console logging.",
PresubmitCheck(
r"org\.testcontainers\.shaded\.",
r".*org\.testcontainers\.shaded.*",
"java",
{"/node_modules/"},
):
"Do not use shaded dependencies from testcontainers.",
PresubmitCheck(
r"com\.google\.common\.truth\.Truth8",
r".*com\.google\.common\.truth\.Truth8.*",
"java",
{"/node_modules/"},
):
"Truth8 is deprecated. Use Truth instead.",
PresubmitCheck(
r".*java\.util\.Date.*",
"java",
{"/node_modules/", "JpaTransactionManagerImpl.java"},
):
"Do not use java.util.Date. Use classes in java.time package instead.",
}
# Note that this regex only works for one kind of Flyway file. If we want to

View file

@ -45,7 +45,6 @@ import java.io.IOException;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.ServiceLoader;
import org.apache.commons.codec.binary.Base64;
@ -195,10 +194,7 @@ public class DelegatedCredentials extends GoogleCredentials {
GenericData responseData = response.parseAs(GenericData.class);
String accessToken = validateString(responseData, "access_token", PARSE_ERROR_PREFIX);
int expiresInSeconds = validateInt32(responseData, "expires_in", PARSE_ERROR_PREFIX);
long expiresAtMilliseconds = clock.nowUtc().getMillis() + expiresInSeconds * 1000L;
@SuppressWarnings("JavaUtilDate")
AccessToken token = new AccessToken(accessToken, new Date(expiresAtMilliseconds));
return token;
return new AccessToken(accessToken, clock.nowUtc().plusSeconds(expiresInSeconds).toDate());
}
String createAssertion(JsonFactory jsonFactory, long currentTime) throws IOException {
@ -257,8 +253,7 @@ public class DelegatedCredentials extends GoogleCredentials {
if (value == null) {
throw new IOException(String.format(VALUE_NOT_FOUND_MESSAGE, errorPrefix, key));
}
if (value instanceof BigDecimal) {
BigDecimal bigDecimalValue = (BigDecimal) value;
if (value instanceof BigDecimal bigDecimalValue) {
return bigDecimalValue.intValueExact();
}
if (!(value instanceof Integer)) {

View file

@ -31,7 +31,6 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
@ -106,12 +105,9 @@ public class CertificateChecker {
// These 2 different instances of PublicKey need to be handled separately since their OIDs are
// encoded differently. More details on this can be found at
// https://stackoverflow.com/questions/49895713/how-to-find-the-matching-curve-name-from-an-ecpublickey.
if (key instanceof ECPublicKey) {
ECPublicKey ecKey = (ECPublicKey) key;
if (key instanceof ECPublicKey ecKey) {
params = EC5Util.convertSpec(ecKey.getParams());
} else if (key instanceof org.bouncycastle.jce.interfaces.ECPublicKey) {
org.bouncycastle.jce.interfaces.ECPublicKey ecKey =
(org.bouncycastle.jce.interfaces.ECPublicKey) key;
} else if (key instanceof org.bouncycastle.jce.interfaces.ECPublicKey ecKey) {
params = ecKey.getParameters();
} else {
throw new IllegalArgumentException("Unrecognized instance of PublicKey.");
@ -148,7 +144,7 @@ public class CertificateChecker {
if (!violations.isEmpty()) {
String displayMessages =
violations.stream()
.map(violation -> getViolationDisplayMessage(violation))
.map(this::getViolationDisplayMessage)
.collect(Collectors.joining("\n"));
throw new InsecureCertificateException(violations, displayMessages);
}
@ -162,7 +158,7 @@ public class CertificateChecker {
ImmutableSet.Builder<CertificateViolation> violations = new ImmutableSet.Builder<>();
// Check if currently in validity period
Date now = clock.nowUtc().toDate();
DateTime now = clock.nowUtc();
if (DateTimeComparator.getInstance().compare(certificate.getNotAfter(), now) < 0) {
violations.add(CertificateViolation.EXPIRED);
} else if (DateTimeComparator.getInstance().compare(certificate.getNotBefore(), now) > 0) {
@ -231,13 +227,13 @@ public class CertificateChecker {
DateTime lastExpiringNotificationSentDate, String certificateStr) {
X509Certificate certificate = getCertificate(certificateStr);
DateTime now = clock.nowUtc();
// expiration date is one day after lastValidDate
// the expiration date is one day after lastValidDate
DateTime lastValidDate = new DateTime(certificate.getNotAfter());
if (lastValidDate.isBefore(now)) {
return false;
}
/*
* Client should receive a notification if :
* Client should receive a notification if:
* 1) client has never received notification (lastExpiringNotificationSentDate is initially
* set to START_OF_TIME) and the certificate has entered the expiring period, OR
* 2) client has received notification but the interval between now and
@ -254,29 +250,21 @@ public class CertificateChecker {
// Yes, we'd rather do this as an instance method on the CertificateViolation enum itself, but
// we can't because we need access to configuration (injected as instance variables) which you
// can't get in a static enum context.
switch (certificateViolation) {
case EXPIRED:
return "Certificate is expired.";
case NOT_YET_VALID:
return "Certificate start date is in the future.";
case ALGORITHM_CONSTRAINED:
return "Certificate key algorithm must be RSA or ECDSA.";
case RSA_KEY_LENGTH_TOO_SHORT:
return String.format(
"RSA key length is too short; the minimum allowed length is %d bits.",
this.minimumRsaKeyLength);
case VALIDITY_LENGTH_TOO_LONG:
return String.format(
"Certificate validity period is too long; it must be less than or equal to %d days.",
this.maxValidityLengthSchedule.lastEntry().getValue());
case INVALID_ECDSA_CURVE:
return String.format(
"The ECDSA key must use one of these algorithms: %s", allowedEcdsaCurves);
default:
throw new IllegalArgumentException(
String.format(
"Unknown CertificateViolation enum value: %s", certificateViolation.name()));
}
return switch (certificateViolation) {
case EXPIRED -> "Certificate is expired.";
case NOT_YET_VALID -> "Certificate start date is in the future.";
case ALGORITHM_CONSTRAINED -> "Certificate key algorithm must be RSA or ECDSA.";
case RSA_KEY_LENGTH_TOO_SHORT ->
String.format(
"RSA key length is too short; the minimum allowed length is %d bits.",
this.minimumRsaKeyLength);
case VALIDITY_LENGTH_TOO_LONG ->
String.format(
"Certificate validity period is too long; it must be less than or equal to %d days.",
this.maxValidityLengthSchedule.lastEntry().getValue());
case INVALID_ECDSA_CURVE ->
String.format("The ECDSA key must use one of these algorithms: %s", allowedEcdsaCurves);
};
}
/**
@ -295,7 +283,7 @@ public class CertificateChecker {
* Gets a suitable end-user-facing display message for this particular certificate violation.
*
* <p>Note that the {@link CertificateChecker} instance must be passed in because it contains
* configuration values (e.g. minimum RSA key length) that go into the error message text.
* configuration values (e.g., minimum RSA key length) that go into the error message text.
*/
public String getDisplayMessage(CertificateChecker certificateChecker) {
return certificateChecker.getViolationDisplayMessage(this);

View file

@ -127,7 +127,7 @@ public final class TmchCertificateAuthority {
*/
public void verify(X509Certificate cert) throws GeneralSecurityException {
synchronized (TmchCertificateAuthority.class) {
X509Utils.verifyCertificate(getAndValidateRoot(), getCrl(), cert, clock.nowUtc().toDate());
X509Utils.verifyCertificate(getAndValidateRoot(), getCrl(), cert, clock.nowUtc());
}
}
@ -151,7 +151,7 @@ public final class TmchCertificateAuthority {
} catch (Exception e) {
logger.atWarning().withCause(e).log("Old CRL is invalid, ignored during CRL update.");
}
X509Utils.verifyCrl(getAndValidateRoot(), oldCrl, newCrl, clock.nowUtc().toDate());
X509Utils.verifyCrl(getAndValidateRoot(), oldCrl, newCrl, clock.nowUtc());
TmchCrl.set(asciiCrl, url);
}

View file

@ -22,7 +22,7 @@ import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.TokenType;
import google.registry.model.domain.token.BulkPricingPackage;
import google.registry.persistence.VKey;
import java.util.Date;
import google.registry.tools.params.DateTimeParameter;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
@ -56,9 +56,11 @@ abstract class CreateOrUpdateBulkPricingPackageCommand extends MutatingCommand {
@Nullable
@Parameter(
names = "--next_billing_date",
converter = DateTimeParameter.class,
validateWith = DateTimeParameter.class,
description =
"The next date that the bulk pricing package should be billed for its annual fee")
Date nextBillingDate;
DateTime nextBillingDate;
/** Returns the existing BulkPricingPackage or null if it does not exist. */
@Nullable
@ -105,9 +107,7 @@ abstract class CreateOrUpdateBulkPricingPackageCommand extends MutatingCommand {
Optional.ofNullable(maxCreates).ifPresent(builder::setMaxCreates);
Optional.ofNullable(price).ifPresent(builder::setBulkPrice);
Optional.ofNullable(nextBillingDate)
.ifPresent(
nextBillingDate ->
builder.setNextBillingDate(new DateTime(nextBillingDate)));
.ifPresent(nextBillingDate -> builder.setNextBillingDate(nextBillingDate));
if (clearLastNotificationSent()) {
builder.setLastNotificationSent(null);
}

View file

@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import google.registry.module.backend.BackendRequestComponent;
import google.registry.module.bsa.BsaRequestComponent;
import google.registry.module.frontend.FrontendRequestComponent;
@ -28,7 +29,6 @@ import google.registry.testing.TestDataHelper;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
/** Unit tests for {@link RequestComponent}. */
public class RequestComponentTest {

View file

@ -40,7 +40,6 @@ import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.net.HttpHeaders;
import com.google.common.net.MediaType;
import com.google.common.truth.Truth8;
import com.google.protobuf.Timestamp;
import com.google.protobuf.util.Timestamps;
import dagger.Module;
@ -133,7 +132,7 @@ public class CloudTasksHelper implements Serializable {
public void assertTasksEnqueuedWithProperty(
String queueName, Function<Task, String> propertyGetter, String... expectedTaskProperties) {
// Ordering is irrelevant but duplicates should be considered independently.
Truth8.assertThat(getTestTasksFor(queueName).stream().map(propertyGetter))
assertThat(getTestTasksFor(queueName).stream().map(propertyGetter))
.containsExactly((Object[]) expectedTaskProperties);
}

View file

@ -53,7 +53,7 @@ public class CreateBulkPricingPackageCommandTest
"--max_domains=100",
"--max_creates=500",
"--price=USD 1000.00",
"--next_billing_date=2012-03-17",
"--next_billing_date=2012-03-17T00:00:00Z",
"abc123");
Optional<BulkPricingPackage> bulkPricingPackageOptional =
@ -161,7 +161,7 @@ public class CreateBulkPricingPackageCommandTest
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setDiscountFraction(1)
.build());
runCommandForced("--price=USD 1000.00", "--next_billing_date=2012-03-17", "abc123");
runCommandForced("--price=USD 1000.00", "--next_billing_date=2012-03-17T00:00:00Z", "abc123");
Optional<BulkPricingPackage> bulkPricingPackageOptional =
tm().transact(() -> BulkPricingPackage.loadByTokenString("abc123"));
assertThat(bulkPricingPackageOptional).isPresent();

View file

@ -69,7 +69,7 @@ public class UpdateBulkPricingPackageCommandTest
"--max_domains=200",
"--max_creates=1000",
"--price=USD 2000.00",
"--next_billing_date=2013-03-17",
"--next_billing_date=2013-03-17T00:00:00Z",
"--clear_last_notification_sent",
"abc123");
@ -106,7 +106,7 @@ public class UpdateBulkPricingPackageCommandTest
"--max_domains=100",
"--max_creates=500",
"--price=USD 1000.00",
"--next_billing_date=2012-03-17",
"--next_billing_date=2012-03-17T00:00:00Z",
"nullPackage"));
Truth.assertThat(thrown.getMessage())
.isEqualTo("BulkPricingPackage with token nullPackage does not exist");
@ -117,7 +117,7 @@ public class UpdateBulkPricingPackageCommandTest
runCommandForced(
"--max_creates=1000",
"--price=USD 2000.00",
"--next_billing_date=2013-03-17",
"--next_billing_date=2013-03-17T00:00:00Z",
"--clear_last_notification_sent",
"abc123");
@ -159,7 +159,7 @@ public class UpdateBulkPricingPackageCommandTest
runCommandForced(
"--max_domains=200",
"--max_creates=1000",
"--next_billing_date=2013-03-17",
"--next_billing_date=2013-03-17T00:00:00Z",
"--clear_last_notification_sent",
"abc123");

View file

@ -19,6 +19,7 @@ import static google.registry.networking.handler.SslInitializerTestUtils.getKeyP
import static google.registry.networking.handler.SslInitializerTestUtils.setUpSslChannel;
import static google.registry.networking.handler.SslInitializerTestUtils.signKeyPair;
import static google.registry.networking.handler.SslInitializerTestUtils.verifySslException;
import static org.joda.time.DateTimeZone.UTC;
import com.google.common.collect.ImmutableList;
import google.registry.util.SelfSignedCaCertificate;
@ -43,12 +44,10 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.stream.Stream;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import org.joda.time.DateTime;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@ -62,7 +61,7 @@ import org.junit.jupiter.params.provider.MethodSource;
* the overhead of routing traffic through the network layer, even if it were to go through
* loopback. It also alleviates the need to pick a free port to use.
*
* <p>The local addresses used in each test method must to be different, otherwise tests run in
* <p>The local addresses used in each test method must be different, otherwise tests run in
* parallel may interfere with each other.
*/
class SslClientInitializerTest {
@ -204,7 +203,7 @@ class SslClientInitializerTest {
// Generate a new key pair.
KeyPair keyPair = getKeyPair();
// Generate a self signed certificate, and use it to sign the key pair.
// Generate a self-signed certificate, and use it to sign the key pair.
SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create();
X509Certificate cert = signKeyPair(ssc, keyPair, SSL_HOST);
@ -212,7 +211,7 @@ class SslClientInitializerTest {
PrivateKey privateKey = keyPair.getPrivate();
nettyExtension.setUpServer(localAddress, getServerHandler(false, privateKey, cert));
// Set up the client to trust the self signed cert used to sign the cert that server provides.
// Set up the client to trust the self-signed cert used to sign the cert that server provides.
SslClientInitializer<LocalChannel> sslClientInitializer =
new SslClientInitializer<>(
sslProvider,
@ -239,21 +238,17 @@ class SslClientInitializerTest {
// Generate a new key pair.
KeyPair keyPair = getKeyPair();
// Generate a self signed certificate, and use it to sign the key pair.
// Generate a self-signed certificate, and use it to sign the key pair.
SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create();
X509Certificate cert =
signKeyPair(
ssc,
keyPair,
SSL_HOST,
Date.from(Instant.now().minus(Duration.ofDays(2))),
Date.from(Instant.now().minus(Duration.ofDays(1))));
ssc, keyPair, SSL_HOST, DateTime.now(UTC).minusDays(2), DateTime.now(UTC).minusDays(1));
// Set up the server to use the signed cert and private key to perform handshake;
PrivateKey privateKey = keyPair.getPrivate();
nettyExtension.setUpServer(localAddress, getServerHandler(false, privateKey, cert));
// Set up the client to trust the self signed cert used to sign the cert that server provides.
// Set up the client to trust the self-signed cert used to sign the cert that server provides.
SslClientInitializer<LocalChannel> sslClientInitializer =
new SslClientInitializer<>(
sslProvider,
@ -280,21 +275,17 @@ class SslClientInitializerTest {
// Generate a new key pair.
KeyPair keyPair = getKeyPair();
// Generate a self signed certificate, and use it to sign the key pair.
// Generate a self-signed certificate, and use it to sign the key pair.
SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create();
X509Certificate cert =
signKeyPair(
ssc,
keyPair,
SSL_HOST,
Date.from(Instant.now().plus(Duration.ofDays(1))),
Date.from(Instant.now().plus(Duration.ofDays(2))));
ssc, keyPair, SSL_HOST, DateTime.now(UTC).plusDays(1), DateTime.now(UTC).plusDays(2));
// Set up the server to use the signed cert and private key to perform handshake;
PrivateKey privateKey = keyPair.getPrivate();
nettyExtension.setUpServer(localAddress, getServerHandler(false, privateKey, cert));
// Set up the client to trust the self signed cert used to sign the cert that server provides.
// Set up the client to trust the self-signed cert used to sign the cert that server provides.
SslClientInitializer<LocalChannel> sslClientInitializer =
new SslClientInitializer<>(
sslProvider,
@ -333,7 +324,7 @@ class SslClientInitializerTest {
SslClientInitializerTest::hostProvider,
SslClientInitializerTest::portProvider,
ImmutableList.of(serverSsc.cert()),
() -> clientSsc.key(),
clientSsc::key,
() -> ImmutableList.of(clientSsc.cert()));
nettyExtension.setUpClient(localAddress, sslClientInitializer);
@ -360,7 +351,7 @@ class SslClientInitializerTest {
// Generate a new key pair.
KeyPair keyPair = getKeyPair();
// Generate a self signed certificate, and use it to sign the key pair.
// Generate a self-signed certificate, and use it to sign the key pair.
SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create();
X509Certificate cert = signKeyPair(ssc, keyPair, "wrong.com");
@ -368,7 +359,7 @@ class SslClientInitializerTest {
PrivateKey privateKey = keyPair.getPrivate();
nettyExtension.setUpServer(localAddress, getServerHandler(false, privateKey, cert));
// Set up the client to trust the self signed cert used to sign the cert that server provides.
// Set up the client to trust the self-signed cert used to sign the cert that server provides.
SslClientInitializer<LocalChannel> sslClientInitializer =
new SslClientInitializer<>(
sslProvider,
@ -379,7 +370,7 @@ class SslClientInitializerTest {
null);
nettyExtension.setUpClient(localAddress, sslClientInitializer);
// When the client rejects the server cert due to wrong hostname, both the client and server
// When the client rejects the server cert due to the wrong hostname, both the client and server
// should throw exceptions.
nettyExtension.assertThatClientRootCause().isInstanceOf(CertificateException.class);
nettyExtension.assertThatClientRootCause().hasMessageThat().contains(SSL_HOST);

View file

@ -15,6 +15,7 @@
package google.registry.networking.handler;
import static com.google.common.truth.Truth.assertThat;
import static org.joda.time.DateTimeZone.UTC;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.base.Throwables;
@ -27,9 +28,6 @@ import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import javax.net.ssl.SSLSession;
import org.bouncycastle.asn1.x500.X500Name;
@ -40,6 +38,7 @@ import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.joda.time.DateTime;
/**
* Utility class that provides methods used by {@link SslClientInitializerTest} and {@link
@ -67,13 +66,13 @@ public final class SslInitializerTestUtils {
}
/**
* Signs the given key pair with the given self signed certificate to generate a certificate with
* Signs the given key pair with the given self-signed certificate to generate a certificate with
* the given validity range.
*
* @return signed public key (of the key pair) certificate
*/
public static X509Certificate signKeyPair(
SelfSignedCaCertificate ssc, KeyPair keyPair, String hostname, Date from, Date to)
SelfSignedCaCertificate ssc, KeyPair keyPair, String hostname, DateTime from, DateTime to)
throws Exception {
X500Name subjectDnName = new X500Name("CN=" + hostname);
BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis());
@ -81,7 +80,12 @@ public final class SslInitializerTestUtils {
ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(ssc.key());
X509v3CertificateBuilder v3CertGen =
new JcaX509v3CertificateBuilder(
issuerDnName, serialNumber, from, to, subjectDnName, keyPair.getPublic());
issuerDnName,
serialNumber,
from.toDate(),
to.toDate(),
subjectDnName,
keyPair.getPublic());
X509CertificateHolder certificateHolder = v3CertGen.build(sigGen);
return new JcaX509CertificateConverter()
@ -90,7 +94,7 @@ public final class SslInitializerTestUtils {
}
/**
* Signs the given key pair with the given self signed certificate to generate a certificate that
* Signs the given key pair with the given self-signed certificate to generate a certificate that
* is valid from yesterday to tomorrow.
*
* @return signed public key (of the key pair) certificate
@ -98,11 +102,7 @@ public final class SslInitializerTestUtils {
public static X509Certificate signKeyPair(
SelfSignedCaCertificate ssc, KeyPair keyPair, String hostname) throws Exception {
return signKeyPair(
ssc,
keyPair,
hostname,
Date.from(Instant.now().minus(Duration.ofDays(1))),
Date.from(Instant.now().plus(Duration.ofDays(1))));
ssc, keyPair, hostname, DateTime.now(UTC).minusDays(1), DateTime.now(UTC).plusDays(1));
}
/**
@ -110,7 +110,7 @@ public final class SslInitializerTestUtils {
* and verifies if it is echoed back correctly.
*
* @param certs The certificate that the server should provide.
* @return The SSL session in current channel, can be used for further validation.
* @return The SSL session in the current channel, can be used for further validation.
*/
static SSLSession setUpSslChannel(Channel channel, X509Certificate... certs) throws Exception {
SslHandler sslHandler = channel.pipeline().get(SslHandler.class);

View file

@ -20,6 +20,7 @@ import static google.registry.networking.handler.SslInitializerTestUtils.setUpSs
import static google.registry.networking.handler.SslInitializerTestUtils.signKeyPair;
import static google.registry.networking.handler.SslInitializerTestUtils.verifySslException;
import static google.registry.networking.handler.SslServerInitializer.CLIENT_CERTIFICATE_PROMISE_KEY;
import static org.joda.time.DateTimeZone.UTC;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
@ -41,11 +42,8 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Stream;
import javax.net.ssl.SSLEngine;
@ -53,6 +51,7 @@ import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import org.joda.time.DateTime;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@ -66,7 +65,7 @@ import org.junit.jupiter.params.provider.MethodSource;
* the overhead of routing traffic through the network layer, even if it were to go through
* loopback. It also alleviates the need to pick a free port to use.
*
* <p>The local addresses used in each test method must to be different, otherwise tests run in
* <p>The local addresses used in each test method must be different, otherwise tests run in
* parallel may interfere with each other.
*/
class SslServerInitializerTest {
@ -202,9 +201,7 @@ class SslServerInitializerTest {
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))));
"CLIENT", DateTime.now(UTC).minusDays(2), DateTime.now(UTC).plusDays(1));
nettyExtension.setUpClient(
localAddress,
getClientHandler(
@ -237,9 +234,7 @@ class SslServerInitializerTest {
Suppliers.ofInstance(ImmutableList.of(serverSsc.cert()))));
SelfSignedCaCertificate clientSsc =
SelfSignedCaCertificate.create(
"CLIENT",
Date.from(Instant.now().minus(Duration.ofDays(2))),
Date.from(Instant.now().plus(Duration.ofDays(1))));
"CLIENT", DateTime.now(UTC).minusDays(2), DateTime.now(UTC).plusDays(1));
nettyExtension.setUpClient(
localAddress,
getClientHandler(
@ -271,20 +266,18 @@ class SslServerInitializerTest {
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))));
"CLIENT", DateTime.now(UTC).minusDays(2), DateTime.now(UTC).plusDays(1));
nettyExtension.setUpClient(
localAddress,
getClientHandler(
sslProvider, serverSsc.cert(), clientSsc.key(), clientSsc.cert(), "TLSv1.1", null));
ImmutableList<Integer> jdkVersion =
Arrays.asList(System.getProperty("java.version").split("\\.")).stream()
Arrays.stream(System.getProperty("java.version").split("\\."))
.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
// In JDK v11.0.11 and above, TLS 1.1 is not supported anymore, 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 =
@ -309,9 +302,7 @@ class SslServerInitializerTest {
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().minus(Duration.ofDays(1))));
"CLIENT", DateTime.now(UTC).minusDays(2), DateTime.now(UTC).minusDays(1));
nettyExtension.setUpClient(
localAddress,
getClientHandler(sslProvider, serverSsc.cert(), clientSsc.key(), clientSsc.cert()));
@ -332,9 +323,7 @@ class SslServerInitializerTest {
localAddress, getServerHandler(true, true, sslProvider, serverSsc.key(), serverSsc.cert()));
SelfSignedCaCertificate clientSsc =
SelfSignedCaCertificate.create(
"CLIENT",
Date.from(Instant.now().plus(Duration.ofDays(1))),
Date.from(Instant.now().plus(Duration.ofDays(2))));
"CLIENT", DateTime.now(UTC).plusDays(1), DateTime.now(UTC).plusDays(2));
nettyExtension.setUpClient(
localAddress,
getClientHandler(sslProvider, serverSsc.cert(), clientSsc.key(), clientSsc.cert()));
@ -446,8 +435,8 @@ class SslServerInitializerTest {
localAddress,
getClientHandler(sslProvider, serverSsc.cert(), clientSsc.key(), clientSsc.cert()));
// When the client rejects the server cert due to wrong hostname, both the server and the client
// throw exceptions.
// When the client rejects the server cert due to the wrong hostname, both the server and the
// client throw exceptions.
nettyExtension.assertThatClientRootCause().isInstanceOf(CertificateException.class);
nettyExtension.assertThatClientRootCause().hasMessageThat().contains(SSL_HOST);
nettyExtension.assertThatServerRootCause().isInstanceOf(SSLException.class);

View file

@ -15,6 +15,7 @@
package google.registry.util;
import static com.google.common.base.Preconditions.checkArgument;
import static org.joda.time.DateTimeZone.UTC;
import com.google.common.collect.ImmutableMap;
import java.math.BigInteger;
@ -23,9 +24,6 @@ import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.Random;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x500.X500Name;
@ -44,9 +42,8 @@ import org.joda.time.DateTime;
public class SelfSignedCaCertificate {
private static final String DEFAULT_ISSUER_FQDN = "registry-test";
private static final Date DEFAULT_NOT_BEFORE =
Date.from(Instant.now().minus(Duration.ofHours(1)));
private static final Date DEFAULT_NOT_AFTER = Date.from(Instant.now().plus(Duration.ofDays(1)));
private static final DateTime DEFAULT_NOT_BEFORE = DateTime.now(UTC).minusHours(1);
private static final DateTime DEFAULT_NOT_AFTER = DateTime.now(UTC).plusDays(1);
private static final Random RANDOM = new Random();
private static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();
@ -80,24 +77,14 @@ public class SelfSignedCaCertificate {
return create(fqdn, DEFAULT_NOT_BEFORE, DEFAULT_NOT_AFTER);
}
public static SelfSignedCaCertificate create(String fqdn, Date from, Date to) throws Exception {
return create(keyGen.generateKeyPair(), fqdn, from, to);
}
public static SelfSignedCaCertificate create(String fqdn, DateTime from, DateTime to)
throws Exception {
return create(keyGen.generateKeyPair(), fqdn, from.toDate(), to.toDate());
}
public static SelfSignedCaCertificate create(KeyPair keyPair, String fqdn, Date from, Date to)
throws Exception {
return new SelfSignedCaCertificate(keyPair.getPrivate(), createCaCert(keyPair, fqdn, from, to));
return create(keyGen.generateKeyPair(), fqdn, from, to);
}
public static SelfSignedCaCertificate create(
KeyPair keyPair, String fqdn, DateTime from, DateTime to) throws Exception {
return new SelfSignedCaCertificate(
keyPair.getPrivate(), createCaCert(keyPair, fqdn, from.toDate(), to.toDate()));
return new SelfSignedCaCertificate(keyPair.getPrivate(), createCaCert(keyPair, fqdn, from, to));
}
static KeyPairGenerator createKeyPairGenerator() {
@ -111,7 +98,7 @@ public class SelfSignedCaCertificate {
}
/** Returns a self-signed Certificate Authority (CA) certificate. */
static X509Certificate createCaCert(KeyPair keyPair, String fqdn, Date from, Date to)
static X509Certificate createCaCert(KeyPair keyPair, String fqdn, DateTime from, DateTime to)
throws Exception {
X500Name owner = new X500Name("CN=" + fqdn);
String publicKeyAlg = keyPair.getPublic().getAlgorithm();
@ -121,7 +108,12 @@ public class SelfSignedCaCertificate {
new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate());
X509v3CertificateBuilder builder =
new JcaX509v3CertificateBuilder(
owner, new BigInteger(64, RANDOM), from, to, owner, keyPair.getPublic());
owner,
new BigInteger(64, RANDOM),
from.toDate(),
to.toDate(),
owner,
keyPair.getPublic());
// Mark cert as CA by adding basicConstraint with cA=true to the builder
BasicConstraints basicConstraints = new BasicConstraints(true);

View file

@ -41,11 +41,11 @@ import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Date;
import java.util.NoSuchElementException;
import java.util.Optional;
import javax.annotation.Nullable;
import javax.annotation.Tainted;
import org.joda.time.DateTime;
import org.joda.time.DateTimeComparator;
/** X.509 Public Key Infrastructure (PKI) helper functions. */
@ -140,13 +140,13 @@ public final class X509Utils {
* <p>Support for certificate chains has not been implemented.
*
* @throws GeneralSecurityException for unsupported protocols, certs not signed by the TMCH,
* parsing errors, encoding errors, if the CRL is expired, or if the CRL is older than the
* one currently in memory.
* parsing errors, encoding errors, if the CRL is expired, or if the CRL is older than the one
* currently in memory.
*/
public static void verifyCertificate(
X509Certificate rootCert, X509CRL crl, @Tainted X509Certificate cert, Date now)
throws GeneralSecurityException {
cert.checkValidity(checkNotNull(now, "now"));
X509Certificate rootCert, X509CRL crl, @Tainted X509Certificate cert, DateTime now)
throws GeneralSecurityException {
cert.checkValidity(checkNotNull(now, "now").toDate());
cert.verify(rootCert.getPublicKey());
if (crl.isRevoked(cert)) {
X509CRLEntry entry = crl.getRevokedCertificate(cert);
@ -168,7 +168,7 @@ public final class X509Utils {
* incorrect keys, and for invalid, old, not-yet-valid or revoked certificates.
*/
public static void verifyCrl(
X509Certificate rootCert, @Nullable X509CRL oldCrl, @Tainted X509CRL newCrl, Date now)
X509Certificate rootCert, @Nullable X509CRL oldCrl, @Tainted X509CRL newCrl, DateTime now)
throws GeneralSecurityException {
if (oldCrl != null
&& DateTimeComparator.getInstance().compare(newCrl.getThisUpdate(), oldCrl.getThisUpdate())
@ -178,7 +178,7 @@ public final class X509Utils {
"New CRL is more out of date than our current CRL. %s < %s\n%s",
newCrl.getThisUpdate(), oldCrl.getThisUpdate(), newCrl));
}
if (DateTimeComparator.getInstance().compare(newCrl.getNextUpdate(), now) < 0) {
if (DateTimeComparator.getInstance().compare(new DateTime(newCrl.getNextUpdate()), now) < 0) {
throw new CRLException("CRL has expired.\n" + newCrl);
}
newCrl.verify(rootCert.getPublicKey());