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 e2547827..dc50897e 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java @@ -245,7 +245,11 @@ public class Registration extends AcmeResource { X509Certificate cert = null; if (rc == HttpURLConnection.HTTP_CREATED) { - cert = conn.readCertificate(); + try { + cert = conn.readCertificate(); + } catch (AcmeProtocolException ex) { + LOG.warn("Could not parse attached certificate", ex); + } } URI chainCertUri = conn.getLink("up"); 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 a0624eb0..b4508b74 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationTest.java @@ -39,6 +39,7 @@ import org.shredzone.acme4j.challenge.Dns01Challenge; import org.shredzone.acme4j.challenge.Http01Challenge; import org.shredzone.acme4j.connector.Resource; import org.shredzone.acme4j.exception.AcmeException; +import org.shredzone.acme4j.exception.AcmeProtocolException; import org.shredzone.acme4j.provider.AcmeProvider; import org.shredzone.acme4j.provider.TestableConnectionProvider; import org.shredzone.acme4j.util.JSON; @@ -397,6 +398,62 @@ public class RegistrationTest { provider.close(); } + /** + * Test that an unparseable certificate can be requested, and at least its location + * is made available. + */ + @Test + public void testRequestCertificateBrokenSync() throws AcmeException, IOException { + TestableConnectionProvider provider = new TestableConnectionProvider() { + @Override + public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { + assertThat(uri, is(resourceUri)); + assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequestWithDate"))); + assertThat(session, is(notNullValue())); + } + + @Override + public int accept(int... httpStatus) throws AcmeException { + assertThat(httpStatus, isIntArrayContainingInAnyOrder( + HttpURLConnection.HTTP_CREATED, HttpURLConnection.HTTP_ACCEPTED)); + return HttpURLConnection.HTTP_CREATED; + } + + @Override + public X509Certificate readCertificate() { + throw new AcmeProtocolException("Failed to read certificate"); + } + + @Override + public URI getLink(String relation) { + switch(relation) { + case "up": return chainUri; + default: return null; + } + } + + @Override + public URI getLocation() { + return locationUri; + } + }; + + provider.putTestResource(Resource.NEW_CERT, resourceUri); + + byte[] csr = TestUtils.getResourceAsByteArray("/csr.der"); + ZoneId utc = ZoneId.of("UTC"); + Instant notBefore = LocalDate.of(2016, 1, 1).atStartOfDay(utc).toInstant(); + Instant notAfter = LocalDate.of(2016, 1, 8).atStartOfDay(utc).toInstant(); + + Registration registration = new Registration(provider.createSession(), locationUri); + Certificate cert = registration.requestCertificate(csr, notBefore, notAfter); + + assertThat(cert.getLocation(), is(locationUri)); + assertThat(cert.getChainLocation(), is(chainUri)); + + provider.close(); + } + /** * Test that the account key can be changed. */ diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java index 2d42e9f0..a1ab6e94 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java @@ -630,4 +630,22 @@ public class DefaultConnectionTest { verifyNoMoreInteractions(mockUrlConnection); } + /** + * Test that a bad certificate throws an exception. + */ + @Test(expected = AcmeProtocolException.class) + public void testReadBadCertificate() throws Exception { + X509Certificate original = TestUtils.createCertificate(); + byte[] badCert = original.getEncoded(); + Arrays.sort(badCert); // break it + + when(mockUrlConnection.getHeaderField("Content-Type")).thenReturn("application/pkix-cert"); + when(mockUrlConnection.getInputStream()).thenReturn(new ByteArrayInputStream(badCert)); + + try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { + conn.conn = mockUrlConnection; + conn.readCertificate(); + } + } + }