From 627e2c228e0723574ff75e8709ad784f38cda492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20K=C3=B6rber?= Date: Thu, 21 Jul 2016 00:58:11 +0200 Subject: [PATCH] Accept optional notBefore and notAfter with CSR --- .../org/shredzone/acme4j/Registration.java | 27 +++++++++++++++++++ .../shredzone/acme4j/util/ClaimBuilder.java | 26 ++++++++++++++++++ .../shredzone/acme4j/RegistrationTest.java | 12 +++++++-- .../acme4j/util/ClaimBuilderTest.java | 17 ++++++++++++ .../src/test/resources/json.properties | 8 ++++++ 5 files changed, 88 insertions(+), 2 deletions(-) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java index cd45ee2d..8276a97b 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -217,6 +218,26 @@ public class Registration extends AcmeResource { * @return The {@link Certificate} */ public Certificate requestCertificate(byte[] csr) throws AcmeException { + return requestCertificate(csr, null, null); + } + + /** + * Requests a certificate for the given CSR. + *

+ * All domains given in the CSR must be authorized before. + * + * @param csr + * PKCS#10 Certificate Signing Request to be sent to the server + * @param notBefore + * requested value of the notBefore field in the certificate, {@code null} + * for default. May be ignored by the server. + * @param notAfter + * requested value of the notAfter field in the certificate, {@code null} + * for default. May be ignored by the server. + * @return The {@link Certificate} + */ + public Certificate requestCertificate(byte[] csr, Date notBefore, Date notAfter) + throws AcmeException { if (csr == null) { throw new NullPointerException("csr must not be null"); } @@ -226,6 +247,12 @@ public class Registration extends AcmeResource { ClaimBuilder claims = new ClaimBuilder(); claims.putResource(Resource.NEW_CERT); claims.putBase64("csr", csr); + if (notBefore != null) { + claims.put("notBefore", notBefore); + } + if (notAfter != null) { + claims.put("notAfter", notAfter); + } int rc = conn.sendSignedRequest(getSession().resourceUri(Resource.NEW_CERT), claims, getSession()); if (rc != HttpURLConnection.HTTP_CREATED && rc != HttpURLConnection.HTTP_ACCEPTED) { diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/util/ClaimBuilder.java b/acme4j-client/src/main/java/org/shredzone/acme4j/util/ClaimBuilder.java index 65398dfe..9298f62b 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/util/ClaimBuilder.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/util/ClaimBuilder.java @@ -15,8 +15,11 @@ package org.shredzone.acme4j.util; import java.security.Key; import java.security.PublicKey; +import java.text.SimpleDateFormat; import java.util.Collections; +import java.util.Date; import java.util.Map; +import java.util.TimeZone; import java.util.TreeMap; import org.jose4j.base64url.Base64Url; @@ -62,6 +65,29 @@ public class ClaimBuilder { return this; } + /** + * Puts a {@link Date} to the claim. If a claim with the key exists, it will be + * replaced. + * + * @param key + * Claim key + * @param value + * Claim {@link Date} value + * @return {@code this} + */ + public ClaimBuilder put(String key, Date value) { + if (value == null) { + put(key, null); + return this; + } + + SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + fmt.setTimeZone(TimeZone.getTimeZone("UTC")); + String date = fmt.format(value); + put(key, date); + return this; + } + /** * Puts a resource claim. * diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationTest.java index 65c3137b..7505a9dd 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationTest.java @@ -24,9 +24,11 @@ import java.net.URI; import java.security.KeyPair; import java.security.cert.X509Certificate; import java.util.Arrays; +import java.util.Calendar; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.TimeZone; import java.util.concurrent.atomic.AtomicBoolean; import org.jose4j.jws.JsonWebSignature; @@ -258,7 +260,7 @@ public class RegistrationTest { @Override public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session) { assertThat(uri, is(resourceUri)); - assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequest"))); + assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequestWithDate"))); assertThat(session, is(notNullValue())); return HttpURLConnection.HTTP_CREATED; } @@ -285,9 +287,15 @@ public class RegistrationTest { provider.putTestResource(Resource.NEW_CERT, resourceUri); byte[] csr = TestUtils.getResourceAsByteArray("/csr.der"); + Calendar notBefore = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + notBefore.clear(); + notBefore.set(2016, Calendar.JANUARY, 1); + Calendar notAfter = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + notAfter.clear(); + notAfter.set(2016, Calendar.JANUARY, 8); Registration registration = new Registration(provider.createSession(), locationUri); - Certificate cert = registration.requestCertificate(csr); + Certificate cert = registration.requestCertificate(csr, notBefore.getTime(), notAfter.getTime()); assertThat(cert.download(), is(originalCert)); assertThat(cert.getLocation(), is(locationUri)); diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/util/ClaimBuilderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/util/ClaimBuilderTest.java index b6c8c725..3b1729de 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/util/ClaimBuilderTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/util/ClaimBuilderTest.java @@ -19,8 +19,10 @@ import static org.junit.Assert.assertThat; import java.io.IOException; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; +import java.util.Calendar; import java.util.HashMap; import java.util.Map; +import java.util.TimeZone; import org.jose4j.json.JsonUtil; import org.jose4j.lang.JoseException; @@ -71,6 +73,21 @@ public class ClaimBuilderTest { )); } + /** + * Test date type. + */ + @Test + public void testDate() { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+2")); + cal.clear(); + cal.set(2016, Calendar.JUNE, 1, 5, 13, 46); + + ClaimBuilder cb = new ClaimBuilder(); + cb.put("fooDate", cal.getTime()); + + assertThat(cb.toString(), is("{\"fooDate\":\"2016-06-01T03:13:46Z\"}")); + } + /** * Test resources. */ diff --git a/acme4j-client/src/test/resources/json.properties b/acme4j-client/src/test/resources/json.properties index 6ccc72d2..908e1445 100644 --- a/acme4j-client/src/test/resources/json.properties +++ b/acme4j-client/src/test/resources/json.properties @@ -151,6 +151,14 @@ requestCertificateRequest = \ "resource":"new-cert"\ } +requestCertificateRequestWithDate = \ + {\ + "csr":"MIIChDCCAWwCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCPemmumcNGR0hsPo-2N6nkJ0FcEMdb0_MlucHR0dNeHEvn8vmcQHlYRjkDVX0aypnfKQI3tvhTBKLdlNvbVIW1TQ_Wbqh9TQlC8G3Hog8nRQ2vAzO4sH6nhvdrAFUmq6hkATpU3iQuDvtYu03ExaYHKsItLocl1OndaQizBn5udBv1baOW3Kd790k6lEWGrD-TXo6uwuMha2k_YBGNKd4S4UuPmbPV9SUVW8JSylBSgDhvY3BHv-dfdIMhVwRMZDFaa0mHDIYUiwcEaU5x4P6Q5bGP2wxcUPCLwFsbAK5K6B2T2P3A2fNjGBAlHwEkg6VMvi7jax8MD-oRnku2M2JLAgMBAAGgKTAnBgkqhkiG9w0BCQ4xGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQACnMZdjE1jVqnkHkEeGrMXujWuwuiKLZVa4YZ9fL0UIGOqqf4b9-3JmtEiLB9ycQO5N9rW4V-6_DBMeoeRBLu-wranHnxU4ds6GzNzBxKfI86_8t5pdQK4Cglv7yfseseZRdQtvcR2ejkW0F3SL1DF5Sk3T46aRYiUXxeoNC4Uh3zoIHOv8YGUa-DuZQ6OnHMhPrdsfU09L7KVAMTq1bodjGWmgoIJm4x5JSm19GbhYAm9Q9XWnN56YHqgS3FtS9n3wDxz7Dvo24whto1tUU5hnjrp31rTvyxG3kydoEZf2Ciq_82bQDb40kwnoO6RytPYJVMRIBsP2mCfaFtIt9Eb",\ + "notBefore": "2016-01-01T00:00:00Z",\ + "notAfter": "2016-01-08T00:00:00Z",\ + "resource":"new-cert"\ + } + revokeCertificateRequest = \ {\ "certificate": "MIIDVzCCAj-gAwIBAgIJAM4KDTzb0Y7NMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQwHhcNMTUxMjEwMDAxMTA4WhcNMjUxMjA3MDAxMTA4WjBCMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr0g3w4C8xbj_5lzJiDxk0HkEJeZeyruq-0AzOPMigJZ7zxZtX_KUxOIHrQ4qjcFhl0DmQImoM0wESU-kcsjAHCx8E1lgRVlVsMfLAQPHkg5UybqfadzKT3ALcSD-9F9mVIP6liC_6KzLTASmx6zM7j92KTl1ArObZr5mh0jvSNORrMhEC4Byn3-NTxjuHON1rWppCMwpeNNhFzaAig3O8PY8IyaLXNP2Ac5pXn0iW16S-Im9by7751UeW5a7DznmuMEM-WY640ffJDQ4-I64H403uAgvvSu-BGw8SEEZGuBCxoCnG1g6y6OvJyN5TgqFdGosAfm1u-_MP1seoPdpBQIDAQABo1AwTjAdBgNVHQ4EFgQUrie5ZLOrA_HuhW1b_CHjzEvj34swHwYDVR0jBBgwFoAUrie5ZLOrA_HuhW1b_CHjzEvj34swDAYDVR0TBAUwAwEB_zANBgkqhkiG9w0BAQsFAAOCAQEAkSOP0FUgIIUeJTObgXrenHzZpLAkqXi37dgdYuPhNveo3agueP51N7yIoh6YGShiJ73Rvr-lVYTwFXStrLih1Wh3tWvksMxnvocgd7l6USRb5_AgH7eHeFK4DoCAak2hUAcCLDRJN3XMhNLpyJhw7GJxowVIGUlxcW5Asrmh9qflfyMyjripTP3CdHobmNcNHyScjNncKj37m8vomel9acekTtDl2Ci7nLdE-3VqQCXMIfLiF3PO0gGpKei0RuVCSOG6W83zVInCPd_l3aluSR-f_VZlk8KGQ4As4uTQi89j-J1YepzG0ASMZpjVbXeIg5QBAywVxBh5XVTz37KN8A",\