diff --git a/README.md b/README.md index 22520135..c07230cf 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This Java client helps to connect to an ACME server, and performing all necessar * Supports [draft-ietf-acme-ari-07](https://www.ietf.org/archive/id/draft-ietf-acme-ari-07.html) for renewal information (experimental) * Supports [draft-aaron-acme-profiles-00](https://www.ietf.org/archive/id/draft-aaron-acme-profiles-00.html) for certificate profiles (experimental) * Easy to use Java API -* Requires JRE 11 or higher +* Requires JRE 17 or higher * Supports [Buypass](https://buypass.com/), [Google Trust Services](https://pki.goog/), [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. * Built with maven, packages available at [Maven Central](http://search.maven.org/#search|ga|1|g%3A%22org.shredzone.acme4j%22) * Extensive unit and integration tests diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java index d63b467e..7b02723c 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java @@ -13,8 +13,7 @@ */ package org.shredzone.acme4j; -import static java.util.stream.Collectors.toUnmodifiableList; - +import java.io.Serial; import java.net.URI; import java.security.KeyPair; import java.util.ArrayList; @@ -42,6 +41,7 @@ import org.slf4j.LoggerFactory; * A representation of an account at the ACME server. */ public class Account extends AcmeJsonResource { + @Serial private static final long serialVersionUID = 7042863483428051319L; private static final Logger LOG = LoggerFactory.getLogger(Account.class); @@ -76,7 +76,7 @@ public class Account extends AcmeJsonResource { .asArray() .stream() .map(Value::asURI) - .collect(toUnmodifiableList()); + .toList(); } /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Identifier.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Identifier.java index f973f0d6..fc62bd61 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Identifier.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Identifier.java @@ -243,11 +243,9 @@ public class Identifier implements Serializable { @Override public boolean equals(Object obj) { - if (!(obj instanceof Identifier)) { + if (!(obj instanceof Identifier i)) { return false; } - - var i = (Identifier) obj; return content.equals(i.content); } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java index 214411c9..347ee517 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java @@ -15,9 +15,9 @@ package org.shredzone.acme4j; import static java.util.Collections.unmodifiableList; import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toUnmodifiableList; import java.io.IOException; +import java.io.Serial; import java.net.URL; import java.security.KeyPair; import java.time.Duration; @@ -43,6 +43,7 @@ import org.slf4j.LoggerFactory; * A representation of a certificate order at the CA. */ public class Order extends AcmeJsonResource implements PollableResource { + @Serial private static final long serialVersionUID = 5435808648658292177L; private static final Logger LOG = LoggerFactory.getLogger(Order.class); @@ -90,7 +91,7 @@ public class Order extends AcmeJsonResource implements PollableResource { .asArray() .stream() .map(Value::asIdentifier) - .collect(toUnmodifiableList()); + .toList(); } /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Problem.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Problem.java index cf5f50f3..e20b252b 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Problem.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Problem.java @@ -13,8 +13,7 @@ */ package org.shredzone.acme4j; -import static java.util.stream.Collectors.toUnmodifiableList; - +import java.io.Serial; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; @@ -33,6 +32,7 @@ import org.shredzone.acme4j.toolbox.JSON.Value; * @see RFC 7807 */ public class Problem implements Serializable { + @Serial private static final long serialVersionUID = -8418248862966754214L; private final URL baseUrl; @@ -122,7 +122,7 @@ public class Problem implements Serializable { .asArray() .stream() .map(o -> o.asProblem(baseUrl)) - .collect(toUnmodifiableList()); + .toList(); } /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Status.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Status.java index 1af60e07..868f77d8 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Status.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Status.java @@ -33,7 +33,7 @@ public enum Status { /** * The server is processing the resource. The client should invoke - * {@link AcmeJsonResource#update()} and re-check the status. + * {@link AcmeJsonResource#fetch()} and re-check the status. */ PROCESSING, diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java index a05640ef..2b5511ed 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java @@ -13,6 +13,7 @@ */ package org.shredzone.acme4j.challenge; +import java.io.Serial; import java.time.Duration; import java.time.Instant; import java.util.EnumSet; @@ -41,6 +42,7 @@ import org.slf4j.LoggerFactory; * required data to the challenge response. */ public class Challenge extends AcmeJsonResource implements PollableResource { + @Serial private static final long serialVersionUID = 2338794776848388099L; private static final Logger LOG = LoggerFactory.getLogger(Challenge.class); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java index 06ef297c..e76faf08 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java @@ -16,6 +16,8 @@ package org.shredzone.acme4j.challenge; import static org.shredzone.acme4j.toolbox.AcmeUtils.base64UrlEncode; import static org.shredzone.acme4j.toolbox.AcmeUtils.sha256hash; +import java.io.Serial; + import org.shredzone.acme4j.Identifier; import org.shredzone.acme4j.Login; import org.shredzone.acme4j.toolbox.JSON; @@ -25,6 +27,7 @@ import org.shredzone.acme4j.toolbox.JSON; * validation. See the acme4j documentation for a detailed explanation. */ public class Dns01Challenge extends TokenChallenge { + @Serial private static final long serialVersionUID = 6964687027713533075L; /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java index b2d2faf6..b7ccb1ac 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java @@ -13,6 +13,8 @@ */ package org.shredzone.acme4j.challenge; +import java.io.Serial; + import org.shredzone.acme4j.Login; import org.shredzone.acme4j.toolbox.JSON; @@ -22,6 +24,7 @@ import org.shredzone.acme4j.toolbox.JSON; * detailed explanation. */ public class Http01Challenge extends TokenChallenge { + @Serial private static final long serialVersionUID = 3322211185872544605L; /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsAlpn01Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsAlpn01Challenge.java index 1b88f920..c964f087 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsAlpn01Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsAlpn01Challenge.java @@ -16,6 +16,7 @@ package org.shredzone.acme4j.challenge; import static org.shredzone.acme4j.toolbox.AcmeUtils.sha256hash; import java.io.IOException; +import java.io.Serial; import java.security.KeyPair; import java.security.cert.X509Certificate; @@ -32,6 +33,7 @@ import org.shredzone.acme4j.util.CertificateUtils; * @since 2.1 */ public class TlsAlpn01Challenge extends TokenChallenge { + @Serial private static final long serialVersionUID = -5590351078176091228L; /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java index 6e66f54b..61407f5f 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java @@ -15,6 +15,8 @@ package org.shredzone.acme4j.challenge; import static org.shredzone.acme4j.toolbox.AcmeUtils.base64UrlEncode; +import java.io.Serial; + import org.shredzone.acme4j.Login; import org.shredzone.acme4j.exception.AcmeProtocolException; import org.shredzone.acme4j.toolbox.AcmeUtils; @@ -26,6 +28,7 @@ import org.shredzone.acme4j.toolbox.JoseUtils; * and {@code keyAuthorization}. */ public class TokenChallenge extends Challenge { + @Serial private static final long serialVersionUID = 1634133407432681800L; protected static final String KEY_TOKEN = "token"; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java index aad0869b..87c410f4 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java @@ -15,7 +15,6 @@ package org.shredzone.acme4j.connector; import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; import static java.util.function.Predicate.not; -import static java.util.stream.Collectors.toUnmodifiableList; import java.io.IOException; import java.io.InputStream; @@ -137,7 +136,7 @@ public class DefaultConnection implements Connection { var retryAfterInstant = getRetryAfter(); if (retryAfterInstant.isPresent()) { throw new AcmeRetryAfterException(message, retryAfterInstant.get()); - }; + } throw new AcmeException(message); } @@ -228,7 +227,7 @@ public class DefaultConnection implements Connection { var cf = CertificateFactory.getInstance("X.509"); return cf.generateCertificates(in).stream() .map(X509Certificate.class::cast) - .collect(toUnmodifiableList()); + .toList(); } catch (IOException ex) { throw new AcmeNetworkException(ex); } catch (CertificateException ex) { @@ -311,7 +310,7 @@ public class DefaultConnection implements Connection { public Collection getLinks(String relation) { return collectLinks(relation).stream() .map(this::resolveRelative) - .collect(toUnmodifiableList()); + .toList(); } @Override @@ -620,7 +619,7 @@ public class DefaultConnection implements Connection { .filter(Matcher::matches) .map(m -> m.group(1)) .peek(location -> LOG.debug("Link: {} -> {}", relation, location)) - .collect(toUnmodifiableList()); + .toList(); } /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeException.java index a3334b06..bcc7dc55 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeException.java @@ -13,10 +13,13 @@ */ package org.shredzone.acme4j.exception; +import java.io.Serial; + /** * The root class of all checked acme4j exceptions. */ public class AcmeException extends Exception { + @Serial private static final long serialVersionUID = -2935088954705632025L; /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java index 71e7cb87..b7980654 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java @@ -15,6 +15,7 @@ package org.shredzone.acme4j.exception; import static java.util.Objects.requireNonNull; +import java.io.Serial; import java.net.URL; import org.shredzone.acme4j.AcmeResource; @@ -26,6 +27,7 @@ import org.shredzone.acme4j.AcmeResource; * thrown by getter methods, so the API is not polluted with checked exceptions. */ public class AcmeLazyLoadingException extends RuntimeException { + @Serial private static final long serialVersionUID = 1000353433913721901L; private final Class type; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNetworkException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNetworkException.java index bad5ffdc..1fe75856 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNetworkException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNetworkException.java @@ -14,12 +14,14 @@ package org.shredzone.acme4j.exception; import java.io.IOException; +import java.io.Serial; /** * A general network error has occured while communicating with the server (e.g. network * timeout). */ public class AcmeNetworkException extends AcmeException { + @Serial private static final long serialVersionUID = 2054398693543329179L; /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNotSupportedException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNotSupportedException.java index f8356cd4..043a8c90 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNotSupportedException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNotSupportedException.java @@ -13,12 +13,15 @@ */ package org.shredzone.acme4j.exception; +import java.io.Serial; + /** * A runtime exception that is thrown if the ACME server does not support a certain * feature. It might be either because that feature is optional, or because the server * is not fully RFC compliant. */ public class AcmeNotSupportedException extends AcmeProtocolException { + @Serial private static final long serialVersionUID = 3434074002226584731L; /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeProtocolException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeProtocolException.java index c507767d..7100ce7f 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeProtocolException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeProtocolException.java @@ -13,12 +13,15 @@ */ package org.shredzone.acme4j.exception; +import java.io.Serial; + /** * A runtime exception that is thrown when the response of the server is violating the * RFC, and could not be handled or parsed for that reason. It is an indicator that the CA * does not fully comply with the RFC, and is usually not expected to be thrown. */ public class AcmeProtocolException extends RuntimeException { + @Serial private static final long serialVersionUID = 2031203835755725193L; /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRateLimitedException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRateLimitedException.java index b1c279de..c9f59c11 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRateLimitedException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRateLimitedException.java @@ -13,6 +13,7 @@ */ package org.shredzone.acme4j.exception; +import java.io.Serial; import java.net.URL; import java.time.Instant; import java.util.Collection; @@ -28,6 +29,7 @@ import org.shredzone.acme4j.Problem; * further explains the rate limit that was exceeded. */ public class AcmeRateLimitedException extends AcmeServerException { + @Serial private static final long serialVersionUID = 4150484059796413069L; private final @Nullable Instant retryAfter; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeServerException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeServerException.java index b5589d66..344df941 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeServerException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeServerException.java @@ -13,6 +13,7 @@ */ package org.shredzone.acme4j.exception; +import java.io.Serial; import java.net.URI; import java.util.Objects; @@ -26,6 +27,7 @@ import org.shredzone.acme4j.Problem; * individually. */ public class AcmeServerException extends AcmeException { + @Serial private static final long serialVersionUID = 5971622508467042792L; private final Problem problem; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUnauthorizedException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUnauthorizedException.java index 9221d538..574670b0 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUnauthorizedException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUnauthorizedException.java @@ -13,6 +13,8 @@ */ package org.shredzone.acme4j.exception; +import java.io.Serial; + import org.shredzone.acme4j.Problem; /** @@ -20,6 +22,7 @@ import org.shredzone.acme4j.Problem; * will give further details (e.g. "client IP is blocked"). */ public class AcmeUnauthorizedException extends AcmeServerException { + @Serial private static final long serialVersionUID = 9064697508262919366L; /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUserActionRequiredException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUserActionRequiredException.java index 457e6efd..ed2403b1 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUserActionRequiredException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUserActionRequiredException.java @@ -13,6 +13,7 @@ */ package org.shredzone.acme4j.exception; +import java.io.Serial; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; @@ -28,6 +29,7 @@ import org.shredzone.acme4j.Problem; * requires an agreement to the new terms before proceeding. */ public class AcmeUserActionRequiredException extends AcmeServerException { + @Serial private static final long serialVersionUID = 7719055447283858352L; private final @Nullable URI tosUri; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JSON.java b/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JSON.java index f52abfbc..d35bf6bf 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JSON.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JSON.java @@ -21,6 +21,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.Serial; import java.io.Serializable; import java.net.MalformedURLException; import java.net.URI; @@ -54,6 +55,7 @@ import org.shredzone.acme4j.exception.AcmeProtocolException; * A model containing a JSON result. The content is immutable. */ public final class JSON implements Serializable { + @Serial private static final long serialVersionUID = 418332625174149030L; private static final JSON EMPTY_JSON = new JSON(new HashMap<>()); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JoseUtils.java b/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JoseUtils.java index 23056774..39952cfb 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JoseUtils.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JoseUtils.java @@ -203,23 +203,13 @@ public final class JoseUtils { * there is no corresponding algorithm identifier for the key */ public static String keyAlgorithm(JsonWebKey jwk) { - if (jwk instanceof EllipticCurveJsonWebKey) { - var ecjwk = (EllipticCurveJsonWebKey) jwk; - - switch (ecjwk.getCurveName()) { - case "P-256": - return AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256; - - case "P-384": - return AlgorithmIdentifiers.ECDSA_USING_P384_CURVE_AND_SHA384; - - case "P-521": - return AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512; - - default: - throw new IllegalArgumentException("Unknown EC name " - + ecjwk.getCurveName()); - } + if (jwk instanceof EllipticCurveJsonWebKey ecjwk) { + return switch (ecjwk.getCurveName()) { + case "P-256" -> AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256; + case "P-384" -> AlgorithmIdentifiers.ECDSA_USING_P384_CURVE_AND_SHA384; + case "P-521" -> AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512; + default -> throw new IllegalArgumentException("Unknown EC name " + ecjwk.getCurveName()); + }; } else if (jwk instanceof RsaJsonWebKey) { return AlgorithmIdentifiers.RSA_USING_SHA256; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/util/CertificateUtils.java b/acme4j-client/src/main/java/org/shredzone/acme4j/util/CertificateUtils.java index c269c01b..5d642c56 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/util/CertificateUtils.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/util/CertificateUtils.java @@ -126,18 +126,11 @@ public final class CertificateUtils { var gns = new GeneralName[1]; - switch (id.getType()) { - case Identifier.TYPE_DNS: - gns[0] = new GeneralName(GeneralName.dNSName, id.getDomain()); - break; - - case Identifier.TYPE_IP: - gns[0] = new GeneralName(GeneralName.iPAddress, id.getIP().getHostAddress()); - break; - - default: - throw new IllegalArgumentException("Unsupported Identifier type " + id.getType()); - } + gns[0] = switch (id.getType()) { + case Identifier.TYPE_DNS -> new GeneralName(GeneralName.dNSName, id.getDomain()); + case Identifier.TYPE_IP -> new GeneralName(GeneralName.iPAddress, id.getIP().getHostAddress()); + default -> throw new IllegalArgumentException("Unsupported Identifier type " + id.getType()); + }; certBuilder.addExtension(Extension.subjectAlternativeName, false, new GeneralNames(gns)); certBuilder.addExtension(ACME_VALIDATION, true, new DEROctetString(acmeValidation)); @@ -268,8 +261,8 @@ public final class CertificateUtils { var attr = csr.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest); if (attr.length > 0) { var extensions = attr[0].getAttrValues().toArray(); - if (extensions.length > 0 && extensions[0] instanceof Extensions) { - var san = GeneralNames.fromExtensions((Extensions) extensions[0], Extension.subjectAlternativeName); + if (extensions.length > 0 && extensions[0] instanceof Extensions extension0) { + var san = GeneralNames.fromExtensions(extension0, Extension.subjectAlternativeName); var critical = csr.getSubject().getRDNs().length == 0; certBuilder.addExtension(Extension.subjectAlternativeName, critical, san); } diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java index 9858967e..45dacdc4 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java @@ -146,10 +146,10 @@ public class AccountTest { @Override public Collection getLinks(String relation) { - switch(relation) { - case "termsOfService": return singletonList(agreementUrl); - default: return emptyList(); - } + return switch (relation) { + case "termsOfService" -> singletonList(agreementUrl); + default -> emptyList(); + }; } }; diff --git a/acme4j-example/src/main/java/org/shredzone/acme4j/example/ClientTest.java b/acme4j-example/src/main/java/org/shredzone/acme4j/example/ClientTest.java index 1168d1ee..c65d1a0d 100644 --- a/acme4j-example/src/main/java/org/shredzone/acme4j/example/ClientTest.java +++ b/acme4j-example/src/main/java/org/shredzone/acme4j/example/ClientTest.java @@ -81,10 +81,10 @@ public class ClientTest { private static final String EAB_HMAC = null; // A supplier for a new account KeyPair. The default creates a new EC key pair. - private static Supplier ACCOUNT_KEY_SUPPLIER = () -> KeyPairUtils.createKeyPair(); + private static final Supplier ACCOUNT_KEY_SUPPLIER = KeyPairUtils::createKeyPair; // A supplier for a new domain KeyPair. The default creates a RSA key pair. - private static Supplier DOMAIN_KEY_SUPPLIER = () -> KeyPairUtils.createKeyPair(4096); + private static final Supplier DOMAIN_KEY_SUPPLIER = () -> KeyPairUtils.createKeyPair(4096); // File name of the User Key Pair private static final File USER_KEY_FILE = new File("user.key"); @@ -267,16 +267,10 @@ public class ClientTest { } // Find the desired challenge and prepare it. - Challenge challenge = null; - switch (CHALLENGE_TYPE) { - case HTTP: - challenge = httpChallenge(auth); - break; - - case DNS: - challenge = dnsChallenge(auth); - break; - } + Challenge challenge = switch (CHALLENGE_TYPE) { + case HTTP -> httpChallenge(auth); + case DNS -> dnsChallenge(auth); + }; if (challenge == null) { throw new AcmeException("No challenge found"); diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/EmailIdentifier.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/EmailIdentifier.java index 170791a0..bba42747 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/EmailIdentifier.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/EmailIdentifier.java @@ -13,6 +13,8 @@ */ package org.shredzone.acme4j.smime; +import java.io.Serial; + import jakarta.mail.internet.AddressException; import jakarta.mail.internet.InternetAddress; import org.shredzone.acme4j.Identifier; @@ -24,6 +26,7 @@ import org.shredzone.acme4j.exception.AcmeProtocolException; * @since 2.12 */ public class EmailIdentifier extends Identifier { + @Serial private static final long serialVersionUID = -1473014167038845395L; /** diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/EmailReply00Challenge.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/EmailReply00Challenge.java index 3d58c644..b12e3d28 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/EmailReply00Challenge.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/EmailReply00Challenge.java @@ -16,6 +16,8 @@ package org.shredzone.acme4j.smime.challenge; import static org.shredzone.acme4j.toolbox.AcmeUtils.base64UrlEncode; import static org.shredzone.acme4j.toolbox.AcmeUtils.sha256hash; +import java.io.Serial; + import jakarta.mail.internet.AddressException; import jakarta.mail.internet.InternetAddress; import org.shredzone.acme4j.Login; @@ -30,6 +32,7 @@ import org.shredzone.acme4j.toolbox.JSON; * @since 2.12 */ public class EmailReply00Challenge extends TokenChallenge { + @Serial private static final long serialVersionUID = 2502329538019544794L; /** diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/exception/AcmeInvalidMessageException.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/exception/AcmeInvalidMessageException.java index a2aeddaf..bdcf28d4 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/exception/AcmeInvalidMessageException.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/exception/AcmeInvalidMessageException.java @@ -15,6 +15,7 @@ package org.shredzone.acme4j.smime.exception; import static java.util.Collections.unmodifiableList; +import java.io.Serial; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -40,6 +41,7 @@ import org.shredzone.acme4j.exception.AcmeException; * @since 2.15 */ public class AcmeInvalidMessageException extends AcmeException { + @Serial private static final long serialVersionUID = 5607857024718309330L; private final List errors; diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SignedMail.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SignedMail.java index d26beda6..17001dee 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SignedMail.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SignedMail.java @@ -149,24 +149,19 @@ public class SignedMail implements Mail { var relaxed = false; for (var element : (ASN1Set) attr.getAttributeValues()[0]) { - if (element instanceof ASN1Enumerated) { - var algorithm = ((ASN1Enumerated) element).intValueExact(); - switch (algorithm) { - case 0: - relaxed = false; - break; - case 1: - relaxed = true; - break; - default: - throw new AcmeInvalidMessageException("Unknown algorithm: " + algorithm); - } + if (element instanceof ASN1Enumerated asn1element) { + var algorithm = asn1element.intValueExact(); + relaxed = switch (algorithm) { + case 0 -> false; + case 1 -> true; + default -> throw new AcmeInvalidMessageException("Unknown algorithm: " + algorithm); + }; } } for (var element : (ASN1Set) attr.getAttributeValues()[0]) { - if (element instanceof ASN1Sequence) { - for (var sequenceElement : (ASN1Sequence) element) { + if (element instanceof ASN1Sequence asn1sequence) { + for (var sequenceElement : asn1sequence) { var headerField = (ASN1Sequence) sequenceElement; var fieldName = ((ASN1String) headerField.getObjectAt(0)).getString(); var fieldValue = ((ASN1String) headerField.getObjectAt(1)).getString(); diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SignedMailBuilder.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SignedMailBuilder.java index 6c379139..c1172ef0 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SignedMailBuilder.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SignedMailBuilder.java @@ -163,12 +163,11 @@ public class SignedMailBuilder { requireNonNull(message, "message"); try { // Check all parameters - if (!(message instanceof MimeMessage)) { + if (!(message instanceof MimeMessage mimeMessage)) { throw new IllegalArgumentException("Message must be a MimeMessage"); } - MimeMessage mimeMessage = (MimeMessage) message; - if (!(mimeMessage.getContent() instanceof MimeMultipart)) { + if (!(mimeMessage.getContent() instanceof MimeMultipart contentMultipart)) { throw new AcmeProtocolException("S/MIME signed message must contain MimeMultipart"); } @@ -177,7 +176,7 @@ public class SignedMailBuilder { } // Get the signed message - SMIMESigned signed = new SMIMESigned((MimeMultipart) mimeMessage.getContent()); + SMIMESigned signed = new SMIMESigned(contentMultipart); // Validate the signature SignerInformation si = validateSignature(mimeMessage, pkixParameters); diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SimpleMail.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SimpleMail.java index 7461c885..3142d846 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SimpleMail.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/wrapper/SimpleMail.java @@ -55,10 +55,10 @@ public class SimpleMail implements Mail { if (from.length != 1) { throw new AcmeInvalidMessageException("Message must have exactly one sender, but has " + from.length); } - if (!(from[0] instanceof InternetAddress)) { + if (!(from[0] instanceof InternetAddress from0)) { throw new AcmeInvalidMessageException("Invalid sender message type: " + from[0].getClass().getName()); } - return (InternetAddress) from[0]; + return from0; } catch (MessagingException ex) { throw new AcmeInvalidMessageException("Could not read 'From' header", ex); } @@ -74,10 +74,10 @@ public class SimpleMail implements Mail { if (to.length != 1) { throw new AcmeInvalidMessageException("Message must have exactly one recipient, but has " + to.length); } - if (!(to[0] instanceof InternetAddress)) { + if (!(to[0] instanceof InternetAddress to0)) { throw new AcmeInvalidMessageException("Invalid recipient message type: " + to[0].getClass().getName()); } - return (InternetAddress) to[0]; + return to0; } catch (MessagingException ex) { throw new AcmeInvalidMessageException("Could not read 'To' header", ex); } diff --git a/acme4j-smime/src/test/java/org/shredzone/acme4j/smime/EmailIdentifierTest.java b/acme4j-smime/src/test/java/org/shredzone/acme4j/smime/EmailIdentifierTest.java index 3e1514d7..4a282ce6 100644 --- a/acme4j-smime/src/test/java/org/shredzone/acme4j/smime/EmailIdentifierTest.java +++ b/acme4j-smime/src/test/java/org/shredzone/acme4j/smime/EmailIdentifierTest.java @@ -37,8 +37,8 @@ public class EmailIdentifierTest { @ParameterizedTest @MethodSource("provideTestEmails") public void testEmail(Object input, String expected) { - var id = input instanceof InternetAddress - ? EmailIdentifier.email((InternetAddress) input) + var id = input instanceof InternetAddress internetAddress + ? EmailIdentifier.email(internetAddress) : EmailIdentifier.email(input.toString()); assertThat(id.getType()).isEqualTo(EmailIdentifier.TYPE_EMAIL); diff --git a/pom.xml b/pom.xml index 237f1f87..5877748a 100644 --- a/pom.xml +++ b/pom.xml @@ -75,7 +75,7 @@ maven-compiler-plugin 3.8.1 - 11 + 17 diff --git a/src/doc/docs/index.md b/src/doc/docs/index.md index 78e2fa83..4ee0fca9 100644 --- a/src/doc/docs/index.md +++ b/src/doc/docs/index.md @@ -22,7 +22,7 @@ Latest version: ![maven central](https://shredzone.org/maven-central/org.shredzo * Supports [draft-ietf-acme-ari-07](https://www.ietf.org/archive/id/draft-ietf-acme-ari-07.html) for renewal information (experimental) * Supports [draft-aaron-acme-profiles-00](https://www.ietf.org/archive/id/draft-aaron-acme-profiles-00.html) for certificate profiles (experimental) * Easy to use Java API -* Requires JRE 11 or higher +* Requires JRE 17 or higher * Supports [Buypass](https://buypass.com/), [Google Trust Services](https://pki.goog/), [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. * Built with maven, packages available at [Maven Central](http://search.maven.org/#search|ga|1|g%3A%22org.shredzone.acme4j%22) * Extensive unit and integration tests diff --git a/src/doc/docs/migration.md b/src/doc/docs/migration.md index 7e031cac..2bbda282 100644 --- a/src/doc/docs/migration.md +++ b/src/doc/docs/migration.md @@ -2,6 +2,10 @@ This document will help you migrate your code to the latest _acme4j_ version. +## Migration to Version 3.6.0 + +- _acme4j_ requires JRE 17 or higher now. + ## Migration to Version 3.5.0 - If you use STAR auto-renewal certificates, you can now use `Order.getCertificate()` instead of `Order.getAutoRenewalCertificate()` to retrieve the STAR certificate. `Order.getAutoRenewalCertificate()` is marked as deprecated, but still functional. The new method `Order.isAutoRenewalCertificate()` can be used to check if the order resulted in a standard or auto-renewing certificate.