Update to draft-ietf-acme-ari-05

pull/168/head
Richard Körber 2024-08-24 12:19:13 +02:00
parent afa60ae76f
commit 0ccd68c09a
No known key found for this signature in database
GPG Key ID: AAB9FD19C78AA3E0
8 changed files with 102 additions and 8 deletions

View File

@ -15,7 +15,7 @@ This Java client helps connecting to an ACME server, and performing all necessar
* Supports [RFC 8739](https://tools.ietf.org/html/rfc8739) short-term automatic certificate renewal (experimental) * Supports [RFC 8739](https://tools.ietf.org/html/rfc8739) short-term automatic certificate renewal (experimental)
* Supports [RFC 8823](https://tools.ietf.org/html/rfc8823) for S/MIME certificates (experimental) * Supports [RFC 8823](https://tools.ietf.org/html/rfc8823) for S/MIME certificates (experimental)
* Supports [RFC 9444](https://tools.ietf.org/html/rfc9444) for subdomain validation * Supports [RFC 9444](https://tools.ietf.org/html/rfc9444) for subdomain validation
* Supports [draft-ietf-acme-ari-04](https://www.ietf.org/archive/id/draft-ietf-acme-ari-04.html) for renewal information (experimental) * Supports [draft-ietf-acme-ari-05](https://www.ietf.org/archive/id/draft-ietf-acme-ari-05.html) for renewal information (experimental)
* Easy to use Java API * Easy to use Java API
* Requires JRE 11 or higher * Requires JRE 11 or higher
* Supports [Let's Encrypt](https://letsencrypt.org/), [SSL.com](https://www.ssl.com/), [ZeroSSL](https://zerossl.com), and all other CAs that comply with the ACME protocol (RFC 8555). Note that _acme4j_ is an independent project that is not supported or endorsed by any of the CAs. * Supports [Let's Encrypt](https://letsencrypt.org/), [SSL.com](https://www.ssl.com/), [ZeroSSL](https://zerossl.com), and all other CAs that comply with the ACME protocol (RFC 8555). Note that _acme4j_ is an independent project that is not supported or endorsed by any of the CAs.

View File

@ -343,6 +343,10 @@ public class OrderBuilder {
throw new AcmeNotSupportedException("auto-renewal"); throw new AcmeNotSupportedException("auto-renewal");
} }
if (replaces != null && session.resourceUrlOptional(Resource.RENEWAL_INFO).isEmpty()) {
throw new AcmeNotSupportedException("renewal-information");
}
var hasAncestorDomain = identifierSet.stream() var hasAncestorDomain = identifierSet.stream()
.filter(id -> Identifier.TYPE_DNS.equals(id.getType())) .filter(id -> Identifier.TYPE_DNS.equals(id.getType()))
.anyMatch(id -> id.toMap().containsKey(Identifier.KEY_ANCESTOR_DOMAIN)); .anyMatch(id -> id.toMap().containsKey(Identifier.KEY_ANCESTOR_DOMAIN));

View File

@ -14,8 +14,7 @@
package org.shredzone.acme4j; package org.shredzone.acme4j;
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.shredzone.acme4j.toolbox.AcmeUtils.parseTimestamp; import static org.shredzone.acme4j.toolbox.AcmeUtils.parseTimestamp;
import static org.shredzone.acme4j.toolbox.TestUtils.getJSON; import static org.shredzone.acme4j.toolbox.TestUtils.getJSON;
@ -169,7 +168,6 @@ public class OrderBuilderTest {
.autoRenewalLifetime(validity) .autoRenewalLifetime(validity)
.autoRenewalLifetimeAdjust(predate) .autoRenewalLifetimeAdjust(predate)
.autoRenewalEnableGet() .autoRenewalEnableGet()
.replaces("aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE")
.create(); .create();
try (var softly = new AutoCloseableSoftAssertions()) { try (var softly = new AutoCloseableSoftAssertions()) {
@ -335,4 +333,73 @@ public class OrderBuilderTest {
provider.close(); provider.close();
} }
/**
* Test that the ARI replaces field is set.
*/
@Test
public void testARIReplaces() throws Exception {
var provider = new TestableConnectionProvider() {
@Override
public int sendSignedRequest(URL url, JSONBuilder claims, Login login) {
assertThat(url).isEqualTo(resourceUrl);
assertThatJson(claims.toString()).isEqualTo(getJSON("requestReplacesRequest").toString());
assertThat(login).isNotNull();
return HttpURLConnection.HTTP_CREATED;
}
@Override
public JSON readJsonResponse() {
return getJSON("requestReplacesResponse");
}
@Override
public URL getLocation() {
return locationUrl;
}
};
var login = provider.createLogin();
provider.putTestResource(Resource.NEW_ORDER, resourceUrl);
provider.putTestResource(Resource.RENEWAL_INFO, resourceUrl);
var account = new Account(login);
account.newOrder()
.domain("example.org")
.replaces("aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE")
.create();
provider.close();
}
/**
* Test that exception is thrown if the ARI replaces field is set but ARI is not
* supported.
*/
@Test
public void testARIReplaceFails() throws Exception {
var provider = new TestableConnectionProvider() {
@Override
public int sendSignedRequest(URL url, JSONBuilder claims, Login login) {
fail("Request was sent");
return HttpURLConnection.HTTP_FORBIDDEN;
}
};
var login = provider.createLogin();
provider.putTestResource(Resource.NEW_ORDER, resourceUrl);
var account = new Account(login);
assertThatExceptionOfType(AcmeNotSupportedException.class).isThrownBy(() -> {
account.newOrder()
.domain("example.org")
.replaces("aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE")
.create();
})
.withMessage("Server does not support renewal-information");
provider.close();
}
} }

View File

@ -11,6 +11,5 @@
"lifetime": 604800, "lifetime": 604800,
"lifetime-adjust": 518400, "lifetime-adjust": 518400,
"allow-certificate-get": true "allow-certificate-get": true
}, }
"replaces": "aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE"
} }

View File

@ -0,0 +1,9 @@
{
"identifiers": [
{
"type": "dns",
"value": "example.org"
}
],
"replaces": "aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE"
}

View File

@ -0,0 +1,15 @@
{
"status": "pending",
"expires": "2016-01-10T00:00:00Z",
"identifiers": [
{
"type": "dns",
"value": "example.org"
}
],
"authorizations": [
"https://example.com/acme/authz/1234",
"https://example.com/acme/authz/2345"
],
"finalize": "https://example.com/acme/acct/1/order/1/finalize"
}

View File

@ -19,7 +19,7 @@ Latest version: ![maven central](https://shredzone.org/maven-central/org.shredzo
* Supports [RFC 8739](https://tools.ietf.org/html/rfc8739) short-term automatic certificate renewal (experimental) * Supports [RFC 8739](https://tools.ietf.org/html/rfc8739) short-term automatic certificate renewal (experimental)
* Supports [RFC 8823](https://tools.ietf.org/html/rfc8823) for S/MIME certificates (experimental) * Supports [RFC 8823](https://tools.ietf.org/html/rfc8823) for S/MIME certificates (experimental)
* Supports [RFC 9444](https://tools.ietf.org/html/rfc9444) for subdomain validation * Supports [RFC 9444](https://tools.ietf.org/html/rfc9444) for subdomain validation
* Supports [draft-ietf-acme-ari-04](https://www.ietf.org/archive/id/draft-ietf-acme-ari-04.html) for renewal information (experimental) * Supports [draft-ietf-acme-ari-05](https://www.ietf.org/archive/id/draft-ietf-acme-ari-05.html) for renewal information (experimental)
* Easy to use Java API * Easy to use Java API
* Requires JRE 11 or higher * Requires JRE 11 or higher
* Supports [Let's Encrypt](https://letsencrypt.org/), [SSL.com](https://www.ssl.com/), [ZeroSSL](https://zerossl.com), and all other CAs that comply with the ACME protocol (RFC 8555). Note that _acme4j_ is an independent project that is not supported or endorsed by any of the CAs. * Supports [Let's Encrypt](https://letsencrypt.org/), [SSL.com](https://www.ssl.com/), [ZeroSSL](https://zerossl.com), and all other CAs that comply with the ACME protocol (RFC 8555). Note that _acme4j_ is an independent project that is not supported or endorsed by any of the CAs.

View File

@ -13,7 +13,7 @@ There is no special path for renewing a certificate. To renew it, just [order](o
## Renewal Information ## Renewal Information
_acme4j_ supports the [draft-ietf-acme-ari-04](https://www.ietf.org/archive/id/draft-ietf-acme-ari-04.html) draft. _acme4j_ supports the [draft-ietf-acme-ari-05](https://www.ietf.org/archive/id/draft-ietf-acme-ari-05.html) draft.
You can check if the CA offers renewal information by invoking `Certificate.hasRenewalInfo()`. If it does, you can get a suggested time window for certificate nenewal by invoking `Certificate.getRenewalInfo()`. You can check if the CA offers renewal information by invoking `Certificate.hasRenewalInfo()`. If it does, you can get a suggested time window for certificate nenewal by invoking `Certificate.getRenewalInfo()`.