mirror of
https://github.com/google/nomulus.git
synced 2025-07-19 17:26:09 +02:00
Add certificate checks to RegistrarSettingsAction (#843)
* Add certificate checks to RegistrarSettingsAction * Add some comments * Add more functionality to CertificateChecker and update call sites * Small code cleanups * Small format fix
This commit is contained in:
parent
f52e887db5
commit
576c05ff5f
10 changed files with 441 additions and 105 deletions
|
@ -16,13 +16,18 @@ package google.registry.util;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Days;
|
||||
|
||||
|
@ -68,8 +73,23 @@ public class CertificateChecker {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks a certificate for violations and returns a list of all the violations the certificate
|
||||
* has.
|
||||
* Checks the given certificate string for violations and throws an exception if any violations
|
||||
* exist.
|
||||
*/
|
||||
public void validateCertificate(String certificateString) {
|
||||
ImmutableSet<CertificateViolation> violations = checkCertificate(certificateString);
|
||||
if (!violations.isEmpty()) {
|
||||
String displayMessages =
|
||||
violations.stream()
|
||||
.map(violation -> getViolationDisplayMessage(violation))
|
||||
.collect(Collectors.joining("\n"));
|
||||
throw new IllegalArgumentException(displayMessages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a given certificate for violations and returns a list of all the violations the
|
||||
* certificate has.
|
||||
*/
|
||||
public ImmutableSet<CertificateViolation> checkCertificate(X509Certificate certificate) {
|
||||
ImmutableSet.Builder<CertificateViolation> violations = new ImmutableSet.Builder<>();
|
||||
|
@ -104,6 +124,25 @@ public class CertificateChecker {
|
|||
return violations.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given string to a certificate and checks it for violations, returning a list of all
|
||||
* the violations the certificate has.
|
||||
*/
|
||||
public ImmutableSet<CertificateViolation> checkCertificate(String certificateString) {
|
||||
X509Certificate certificate;
|
||||
|
||||
try {
|
||||
certificate =
|
||||
(X509Certificate)
|
||||
CertificateFactory.getInstance("X509")
|
||||
.generateCertificate(new ByteArrayInputStream(certificateString.getBytes(UTF_8)));
|
||||
} catch (CertificateException e) {
|
||||
throw new IllegalArgumentException("Unable to read given certificate.");
|
||||
}
|
||||
|
||||
return checkCertificate(certificate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the certificate is nearing expiration.
|
||||
*
|
||||
|
|
|
@ -21,6 +21,7 @@ import static google.registry.util.CertificateChecker.CertificateViolation.NOT_Y
|
|||
import static google.registry.util.CertificateChecker.CertificateViolation.RSA_KEY_LENGTH_TOO_SHORT;
|
||||
import static google.registry.util.CertificateChecker.CertificateViolation.VALIDITY_LENGTH_TOO_LONG;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.testing.FakeClock;
|
||||
|
@ -35,6 +36,54 @@ import org.junit.jupiter.api.Test;
|
|||
class CertificateCheckerTest {
|
||||
|
||||
private static final String SSL_HOST = "www.example.tld";
|
||||
private static final String GOOD_CERTIFICATE =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIIDyzCCArOgAwIBAgIUJnhiVrxAxgwkLJzHPm1w/lBoNs4wDQYJKoZIhvcNAQEL\n"
|
||||
+ "BQAwdTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREwDwYDVQQHDAhO\n"
|
||||
+ "ZXcgWW9yazEPMA0GA1UECgwGR29vZ2xlMR0wGwYDVQQLDBRkb21haW4tcmVnaXN0\n"
|
||||
+ "cnktdGVzdDEQMA4GA1UEAwwHY2xpZW50MTAeFw0yMDEwMTIxNzU5NDFaFw0yMTA0\n"
|
||||
+ "MzAxNzU5NDFaMHUxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8G\n"
|
||||
+ "A1UEBwwITmV3IFlvcmsxDzANBgNVBAoMBkdvb2dsZTEdMBsGA1UECwwUZG9tYWlu\n"
|
||||
+ "LXJlZ2lzdHJ5LXRlc3QxEDAOBgNVBAMMB2NsaWVudDEwggEiMA0GCSqGSIb3DQEB\n"
|
||||
+ "AQUAA4IBDwAwggEKAoIBAQC0msirO7kXyGEC93stsNYGc02Z77Q2qfHFwaGYkUG8\n"
|
||||
+ "QvOF5SWN+jwTo5Td6Jj26A26a8MLCtK45TCBuMRNcUsHhajhT19ocphO20iY3zhi\n"
|
||||
+ "ycwV1id0iwME4kPd1m57BELRE9tUPOxF81/JQXdR1fwT5KRVHYRDWZhaZ5aBmlZY\n"
|
||||
+ "3t/H9Ly0RBYyApkMaGs3nlb94OOug6SouUfRt02S59ja3wsE2SVF/Eui647OXP7O\n"
|
||||
+ "QdYXofxuqLoNkE8EnAdl43/enGLiCIVd0G2lABibFF+gbxTtfgbg7YtfUZJdL+Mb\n"
|
||||
+ "RAcAtuLXEamNQ9H63JgVF16PlQVCDz2XyI3uCfPpDDiBAgMBAAGjUzBRMB0GA1Ud\n"
|
||||
+ "DgQWBBQ26bWk8qfEBjXs/xZ4m8JZyalnITAfBgNVHSMEGDAWgBQ26bWk8qfEBjXs\n"
|
||||
+ "/xZ4m8JZyalnITAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAZ\n"
|
||||
+ "VcsgslBKanKOieJ5ik2d9qzOMXKfBuWPRFWbkC3t9i5awhHqnGAaj6nICnnMZIyt\n"
|
||||
+ "rdx5lZW5aaQyf0EP/90JAA8Xmty4A6MXmEjQAMiCOpP3A7eeS6Xglgi8IOZl4/bg\n"
|
||||
+ "LonW62TUkilo5IiFt/QklFTeHIjXB+OvA8+2Quqyd+zp7v6KnhXjvaomim78DhwE\n"
|
||||
+ "0PIUnjmiRpGpHfTVioTdfhPHZ2Y93Y8K7juL93sQog9aBu5m9XRJCY6wGyWPE83i\n"
|
||||
+ "kmLfGzjcnaJ6kqCd9xQRFZ0JwHmGlkAQvFoeengbNUqSyjyVgsOoNkEsrWwe/JFO\n"
|
||||
+ "iqBvjEhJlvRoefvkdR98\n"
|
||||
+ "-----END CERTIFICATE-----\n";
|
||||
private static final String BAD_CERTIFICATE =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIIDvTCCAqWgAwIBAgIJANoEy6mYwalPMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNV\n"
|
||||
+ "BAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8GA1UEBwwITmV3IFlvcmsxDzAN\n"
|
||||
+ "BgNVBAoMBkdvb2dsZTEdMBsGA1UECwwUZG9tYWluLXJlZ2lzdHJ5LXRlc3QxEDAO\n"
|
||||
+ "BgNVBAMMB2NsaWVudDIwHhcNMTUwODI2MTkyODU3WhcNNDMwMTExMTkyODU3WjB1\n"
|
||||
+ "MQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxETAPBgNVBAcMCE5ldyBZ\n"
|
||||
+ "b3JrMQ8wDQYDVQQKDAZHb29nbGUxHTAbBgNVBAsMFGRvbWFpbi1yZWdpc3RyeS10\n"
|
||||
+ "ZXN0MRAwDgYDVQQDDAdjbGllbnQyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"
|
||||
+ "CgKCAQEAw2FtuDyoR+rUJHp6k7KwaoHGHPV1xnC8IpG9O0SZubOXrFrnBHggBsbu\n"
|
||||
+ "+DsknbHXjmoihSFFem0KQqJg5y34aDAHXQV3iqa7nDfb1x4oc5voVz9gqjdmGKNm\n"
|
||||
+ "WF4MTIPNMu8KY52M852mMCxODK+6MZYp7wCmVa63KdCm0bW/XsLgoA/+FVGwKLhf\n"
|
||||
+ "UqFzt10Cf+87zl4VHrSaJqcHBYM6yAO5lvkr5VC6g8rRQ+dJ+pBT2D99YpSF1aFc\n"
|
||||
+ "rWbBreIypixZAnXm/Xoogu6RnohS29VCJp2dXFAJmKXGwyKNQFXfEKxZBaBi8uKH\n"
|
||||
+ "XF459795eyF9xHgSckEgu7jZlxOk6wIDAQABo1AwTjAdBgNVHQ4EFgQUv26AsQyc\n"
|
||||
+ "kLOjkhqcFLOuueB33l4wHwYDVR0jBBgwFoAUv26AsQyckLOjkhqcFLOuueB33l4w\n"
|
||||
+ "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANBuV+QDISSnGAEHKbR40\n"
|
||||
+ "zUYdOjdZ399zcFNqTSPHwmE0Qu8pbmXhofpBfjzrcv0tkVbhSLYnT22qhx7aDmhb\n"
|
||||
+ "bOS8CeVYCwl5eiDTkJly3pRZLzJpy+UT5z8SPxO3MrTqn+wuj0lBpWRTBCWYAUpr\n"
|
||||
+ "IFRmgVB3IwVb60UIuxhmuk8TVss2SzNrdhdt36eAIPJ0RWEb0KHYHi35Y6lt4f+t\n"
|
||||
+ "iVk+ZR0cCbHUs7Q1RqREXHd/ICuMRLY/MsadVQ9WDqVOridh198X/OIqdx/p9kvJ\n"
|
||||
+ "1R80jDcVGNhYVXLmHu4ho4xrOaliSYvUJSCmaaSEGVZ/xE5PI7S6A8RMdj0iXLSt\n"
|
||||
+ "Bg==\n"
|
||||
+ "-----END CERTIFICATE-----\n";
|
||||
|
||||
private FakeClock fakeClock = new FakeClock();
|
||||
private CertificateChecker certificateChecker =
|
||||
|
@ -189,6 +238,24 @@ class CertificateCheckerTest {
|
|||
.containsExactly(ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_checkCertificate_validCertificateString() throws Exception {
|
||||
fakeClock.setTo(DateTime.parse("2020-11-01T00:00:00Z"));
|
||||
assertThat(certificateChecker.checkCertificate(GOOD_CERTIFICATE)).isEmpty();
|
||||
assertThat(certificateChecker.checkCertificate(BAD_CERTIFICATE))
|
||||
.containsExactly(VALIDITY_LENGTH_TOO_LONG);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_checkCertificate_invalidCertificateString() throws Exception {
|
||||
fakeClock.setTo(DateTime.parse("2020-11-01T00:00:00Z"));
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> certificateChecker.checkCertificate("bad certificate string"));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Unable to read given certificate.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_isNearingExpiration_yesItIs() throws Exception {
|
||||
fakeClock.setTo(DateTime.parse("2021-09-20T00:00:00Z"));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue