Merge acme4j-utils into acme4j-client

The separation of acme4j-client and acme4j-utils was a design decision
that should avoid BouncyCastle to be a hard dependency of acme4j-client.
Anyhow acme4j is not really usable without BouncyCastle, so acme4j-utils
is used in almost all projects anyway.

This merge allows to extend the client API with some nice methods that
will make it easier to use.
pull/140/head
Richard Körber 2023-05-19 09:58:08 +02:00
parent c1ea9200ec
commit 16b02efe23
No known key found for this signature in database
GPG Key ID: AAB9FD19C78AA3E0
31 changed files with 28 additions and 134 deletions

View File

@ -26,9 +26,9 @@ If you require Java 8 or Android compatibility, you can use [acme4j v2](https://
## Dependencies ## Dependencies
* [Bouncy Castle](https://www.bouncycastle.org/)
* [jose4j](https://bitbucket.org/b_c/jose4j/wiki/Home) * [jose4j](https://bitbucket.org/b_c/jose4j/wiki/Home)
* [slf4j](http://www.slf4j.org/) * [slf4j](http://www.slf4j.org/)
* For `acme4j-utils`: [Bouncy Castle](https://www.bouncycastle.org/)
* For `acme4j-smime`: [Jakarta Mail](https://eclipse-ee4j.github.io/mail/), [Bouncy Castle](https://www.bouncycastle.org/) * For `acme4j-smime`: [Jakarta Mail](https://eclipse-ee4j.github.io/mail/), [Bouncy Castle](https://www.bouncycastle.org/)
## Usage ## Usage

View File

@ -57,6 +57,16 @@
<artifactId>jose4j</artifactId> <artifactId>jose4j</artifactId>
<version>${jose4j.version}</version> <version>${jose4j.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>

View File

@ -18,6 +18,8 @@
module org.shredzone.acme4j { module org.shredzone.acme4j {
requires static com.github.spotbugs.annotations; requires static com.github.spotbugs.annotations;
requires java.net.http; requires java.net.http;
requires org.bouncycastle.pkix;
requires org.bouncycastle.provider;
requires org.jose4j; requires org.jose4j;
requires org.slf4j; requires org.slf4j;
@ -27,6 +29,7 @@ module org.shredzone.acme4j {
exports org.shredzone.acme4j.exception; exports org.shredzone.acme4j.exception;
exports org.shredzone.acme4j.provider; exports org.shredzone.acme4j.provider;
exports org.shredzone.acme4j.toolbox; exports org.shredzone.acme4j.toolbox;
exports org.shredzone.acme4j.util;
uses org.shredzone.acme4j.provider.AcmeProvider; uses org.shredzone.acme4j.provider.AcmeProvider;
uses org.shredzone.acme4j.provider.ChallengeProvider; uses org.shredzone.acme4j.provider.ChallengeProvider;

View File

@ -59,11 +59,6 @@
<artifactId>acme4j-client</artifactId> <artifactId>acme4j-client</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.shredzone.acme4j</groupId>
<artifactId>acme4j-utils</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId> <artifactId>slf4j-simple</artifactId>

View File

@ -14,7 +14,6 @@
module org.shredzone.acme4j.example { module org.shredzone.acme4j.example {
requires org.shredzone.acme4j; requires org.shredzone.acme4j;
requires org.shredzone.acme4j.utils;
requires java.desktop; requires java.desktop;

View File

@ -173,11 +173,6 @@
<artifactId>acme4j-client</artifactId> <artifactId>acme4j-client</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.shredzone.acme4j</groupId>
<artifactId>acme4j-utils</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>

View File

@ -14,7 +14,6 @@
module org.shredzone.acme4j.it { module org.shredzone.acme4j.it {
requires org.shredzone.acme4j; requires org.shredzone.acme4j;
requires org.shredzone.acme4j.utils;
requires com.github.spotbugs.annotations; requires com.github.spotbugs.annotations;
requires org.apache.httpcomponents.httpclient; requires org.apache.httpcomponents.httpclient;

View File

@ -34,11 +34,6 @@
<artifactId>acme4j-client</artifactId> <artifactId>acme4j-client</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.shredzone.acme4j</groupId>
<artifactId>acme4j-utils</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId> <artifactId>bcprov-jdk18on</artifactId>

View File

@ -17,7 +17,6 @@
*/ */
module org.shredzone.acme4j.smime { module org.shredzone.acme4j.smime {
requires org.shredzone.acme4j; requires org.shredzone.acme4j;
requires org.shredzone.acme4j.utils;
requires transitive jakarta.mail; requires transitive jakarta.mail;
requires static com.github.spotbugs.annotations; requires static com.github.spotbugs.annotations;

View File

@ -1,54 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
*
* acme4j - ACME Java client
*
* Copyright (C) 2015 Richard "Shred" Körber
* http://acme4j.shredzone.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.shredzone.acme4j</groupId>
<artifactId>acme4j</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>acme4j-utils</artifactId>
<name>acme4j Utils</name>
<description>acme4j utilities</description>
<dependencies>
<dependency>
<groupId>org.shredzone.acme4j</groupId>
<artifactId>acme4j-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,27 +0,0 @@
/*
* acme4j - Java ACME client
*
* Copyright (C) 2020 Richard "Shred" Körber
* http://acme4j.shredzone.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
/**
* This module contains a collection of utility classes. All of them require Bouncy Castle
* to be added as security provider.
*/
module org.shredzone.acme4j.utils {
requires org.shredzone.acme4j;
requires static com.github.spotbugs.annotations;
requires org.bouncycastle.pkix;
requires org.bouncycastle.provider;
exports org.shredzone.acme4j.util;
}

View File

@ -1,20 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDVzCCAj+gAwIBAgIJAM4KDTzb0Y7NMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNV
BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
Q29tcGFueSBMdGQwHhcNMTUxMjEwMDAxMTA4WhcNMjUxMjA3MDAxMTA4WjBCMQsw
CQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZh
dWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
r0g3w4C8xbj/5lzJiDxk0HkEJeZeyruq+0AzOPMigJZ7zxZtX/KUxOIHrQ4qjcFh
l0DmQImoM0wESU+kcsjAHCx8E1lgRVlVsMfLAQPHkg5UybqfadzKT3ALcSD+9F9m
VIP6liC/6KzLTASmx6zM7j92KTl1ArObZr5mh0jvSNORrMhEC4Byn3+NTxjuHON1
rWppCMwpeNNhFzaAig3O8PY8IyaLXNP2Ac5pXn0iW16S+Im9by7751UeW5a7Dznm
uMEM+WY640ffJDQ4+I64H403uAgvvSu+BGw8SEEZGuBCxoCnG1g6y6OvJyN5TgqF
dGosAfm1u+/MP1seoPdpBQIDAQABo1AwTjAdBgNVHQ4EFgQUrie5ZLOrA/HuhW1b
/CHjzEvj34swHwYDVR0jBBgwFoAUrie5ZLOrA/HuhW1b/CHjzEvj34swDAYDVR0T
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkSOP0FUgIIUeJTObgXrenHzZpLAk
qXi37dgdYuPhNveo3agueP51N7yIoh6YGShiJ73Rvr+lVYTwFXStrLih1Wh3tWvk
sMxnvocgd7l6USRb5/AgH7eHeFK4DoCAak2hUAcCLDRJN3XMhNLpyJhw7GJxowVI
GUlxcW5Asrmh9qflfyMyjripTP3CdHobmNcNHyScjNncKj37m8vomel9acekTtDl
2Ci7nLdE+3VqQCXMIfLiF3PO0gGpKei0RuVCSOG6W83zVInCPd/l3aluSR+f/VZl
k8KGQ4As4uTQi89j+J1YepzG0ASMZpjVbXeIg5QBAywVxBh5XVTz37KN8A==
-----END CERTIFICATE-----

View File

@ -62,7 +62,6 @@
<modules> <modules>
<module>acme4j-client</module> <module>acme4j-client</module>
<module>acme4j-utils</module>
<module>acme4j-smime</module> <module>acme4j-smime</module>
<module>acme4j-example</module> <module>acme4j-example</module>
<module>acme4j-it</module> <module>acme4j-it</module>

View File

@ -15,7 +15,7 @@ You need to create a self-signed certificate with the domain to be validated set
After that, configure your web server so it will use this certificate on an incoming TLS request having the SNI `identifier` and the ALPN protocol `acme-tls/1`. After that, configure your web server so it will use this certificate on an incoming TLS request having the SNI `identifier` and the ALPN protocol `acme-tls/1`.
The `TlsAlpn01Challenge` class does not generate a self-signed certificate for you, as it would require _Bouncy Castle_. However, there is a utility method in the _acme4j-utils_ module for this use case: The `TlsAlpn01Challenge` class does not generate a self-signed certificate for you, as it would require _Bouncy Castle_. However, there is a utility method for this use case:
```java ```java
KeyPair certKeyPair = KeyPairUtils.createKeyPair(2048); KeyPair certKeyPair = KeyPairUtils.createKeyPair(2048);

View File

@ -50,7 +50,7 @@ public static void main(String... args) {
``` ```
!!! note !!! note
As the example makes use of the `acme4j-utils` module for generating key pairs and the CSR, the `BouncyCastleProvider` needs to be added as security provider. The example requires the `BouncyCastleProvider` to be added as security provider.
## The Main Workflow ## The Main Workflow

View File

@ -30,9 +30,9 @@ If you require Java 8 or Android compatibility, you can use [acme4j v2](https://
## Dependencies ## Dependencies
* [Bouncy Castle](https://www.bouncycastle.org/)
* [jose4j](https://bitbucket.org/b_c/jose4j/wiki/Home) * [jose4j](https://bitbucket.org/b_c/jose4j/wiki/Home)
* [slf4j](http://www.slf4j.org/) * [slf4j](http://www.slf4j.org/)
* For `acme4j-utils`: [Bouncy Castle](https://www.bouncycastle.org/)
* For `acme4j-smime`: [Jakarta Mail](https://eclipse-ee4j.github.io/mail/), [Bouncy Castle](https://www.bouncycastle.org/) * For `acme4j-smime`: [Jakarta Mail](https://eclipse-ee4j.github.io/mail/), [Bouncy Castle](https://www.bouncycastle.org/)
## Quick Start ## Quick Start
@ -44,22 +44,17 @@ There is an [example source code](example.md) included in this project. It gives
_acme4j_ consists of five modules. All modules are [available at Maven Central](https://mvnrepository.com/artifact/org.shredzone.acme4j) and can easily be added to the dependency list of your project. You can also download the jar files [at GitHub](https://github.com/shred/acme4j/releases/latest). _acme4j_ consists of five modules. All modules are [available at Maven Central](https://mvnrepository.com/artifact/org.shredzone.acme4j) and can easily be added to the dependency list of your project. You can also download the jar files [at GitHub](https://github.com/shred/acme4j/releases/latest).
acme4j-client acme4j-client
: [`acme4j-client`](https://mvnrepository.com/artifact/org.shredzone.acme4j/acme4j-client/latest) is the main module. It contains everything that is required to get certificates for domains. It only requires [jose4j](https://bitbucket.org/b_c/jose4j) and [slf4j](https://www.slf4j.org/). : [`acme4j-client`](https://mvnrepository.com/artifact/org.shredzone.acme4j/acme4j-client/latest) is the main module. It contains everything that is required to get certificates for domains.
The Java module name is `org.shredzone.acme4j`. The Java module name is `org.shredzone.acme4j`.
acme4j-utils
: [`acme4j-utils`](https://mvnrepository.com/artifact/org.shredzone.acme4j/acme4j-utils/latest) contains utility classes for creating key pairs, CSRs, and certificates. It requires [Bouncy Castle](https://www.bouncycastle.org/java.html) though.
The Java module name is `org.shredzone.acme4j.utils`.
acme4j-smime acme4j-smime
: [`acme4j-smime`](https://mvnrepository.com/artifact/org.shredzone.acme4j/acme4j-smime/latest) contains the [RFC 8823](https://tools.ietf.org/html/rfc8823) implementation for ordering S/MIME certificates. It requires [Bouncy Castle](https://www.bouncycastle.org/java.html) and a `javax.mail` implementation. : [`acme4j-smime`](https://mvnrepository.com/artifact/org.shredzone.acme4j/acme4j-smime/latest) contains the [RFC 8823](https://tools.ietf.org/html/rfc8823) implementation for ordering S/MIME certificates. It requires [Bouncy Castle](https://www.bouncycastle.org/java.html) and a `javax.mail` implementation.
The Java module name is `org.shredzone.acme4j.smime`. The Java module name is `org.shredzone.acme4j.smime`.
acme4j-example acme4j-example
: This module only contains [an example code](example.md) that demonstrates how to get a certificate with _acme4j_. It depends on `acme4j-client` and `acme4j-utils`. It is not useful as a dependency in other projects. : This module only contains [an example code](example.md) that demonstrates how to get a certificate with _acme4j_. It is not useful as a dependency in other projects.
acme4j-it acme4j-it
: [`acme4j-it`](https://mvnrepository.com/artifact/org.shredzone.acme4j/acme4j-it/latest) mainly serves as integration test suite for _acme4j_ itself. It is not really useful as a dependency in other projects. However if you write own integration tests using [pebble](https://github.com/letsencrypt/pebble) and [pebble-challtestsrv](https://hub.docker.com/r/letsencrypt/pebble-challtestsrv), you may find the [`challtestsrv` configuration client](acme4j-it/apidocs/org.shredzone.acme4j.it/org/shredzone/acme4j/it/BammBammClient.html) useful in your project. : [`acme4j-it`](https://mvnrepository.com/artifact/org.shredzone.acme4j/acme4j-it/latest) mainly serves as integration test suite for _acme4j_ itself. It is not really useful as a dependency in other projects. However if you write own integration tests using [pebble](https://github.com/letsencrypt/pebble) and [pebble-challtestsrv](https://hub.docker.com/r/letsencrypt/pebble-challtestsrv), you may find the [`challtestsrv` configuration client](acme4j-it/apidocs/org.shredzone.acme4j.it/org/shredzone/acme4j/it/BammBammClient.html) useful in your project.

View File

@ -4,7 +4,14 @@ This document will help you migrate your code to the latest _acme4j_ version.
## Migration to Version 3.0.0 ## Migration to Version 3.0.0
- The `acme4j-utils` module has been removed, and its classes moved into `acme4j-client` module. If you have used it before, just remove the dependency. If your project has a `module-info.java` file, remember to remove the `requires org.shredzone.acme4j.utils` line there as well. If you haven't used the module before: `acme4j-client` now depends on Bouncy Castle, so you might need to register it as security provider at the start of your code:
```java
Security.addProvider(new BouncyCastleProvider());
```
- All `@Nullable` return values have been reviewed. Collections may now be empty, but never `null`. Most of the other return values are now either `Optional`, or throwing an exception if more reasonable. If your code fails to compile because the return type has changed to `Optional`, you can simply add `.orElse(null)` to restore the old behavior. But often your code will reveal a better way to handle the former `null` pointer instead. - All `@Nullable` return values have been reviewed. Collections may now be empty, but never `null`. Most of the other return values are now either `Optional`, or throwing an exception if more reasonable. If your code fails to compile because the return type has changed to `Optional`, you can simply add `.orElse(null)` to restore the old behavior. But often your code will reveal a better way to handle the former `null` pointer instead.
What you might also need to know:
- A new `AcmeNotSupportedException` is thrown if a feature is not supported by the server. It is a subclass of the `AcmeProtocolException` runtime exception. - A new `AcmeNotSupportedException` is thrown if a feature is not supported by the server. It is a subclass of the `AcmeProtocolException` runtime exception.
- Starting with _acme4j_ v3, we will require the smallest Java SE LTS version that is still receiving premier support according to the [Oracle Java SE Support Roadmap](https://www.oracle.com/java/technologies/java-se-support-roadmap.html). At the moment of writing, these are Java 11 and Java 17, so _acme4j_ requires Java 11 starting from now. With the prospected release of Java 21 (LTS) in September 2023, we will start to require Java 17, and so on. If you still need Java 8, you can use _acme4j_ v2, which will receive bugfixes until September 2023. - Starting with _acme4j_ v3, we will require the smallest Java SE LTS version that is still receiving premier support according to the [Oracle Java SE Support Roadmap](https://www.oracle.com/java/technologies/java-se-support-roadmap.html). At the moment of writing, these are Java 11 and Java 17, so _acme4j_ requires Java 11 starting from now. With the prospected release of Java 21 (LTS) in September 2023, we will start to require Java 17, and so on. If you still need Java 8, you can use _acme4j_ v2, which will receive bugfixes until September 2023.
- Changed to `java.net.http` client. Due to limitations of the API, HTTP errors are only thrown with the error code, but not with the error message. If you checked the message in unit tests, be prepared that the error message might have changed. - Changed to `java.net.http` client. Due to limitations of the API, HTTP errors are only thrown with the error code, but not with the error message. If you checked the message in unit tests, be prepared that the error message might have changed.

View File

@ -13,7 +13,7 @@ After the CA has created your account, it returns an account URL. You will need
You can use external tools like `openssl` or standard Java methods to create a key pair. You can use external tools like `openssl` or standard Java methods to create a key pair.
A more convenient way is to use the `KeyPairUtils` class in the `acme4j-utils` module. This call generates a RSA key pair with a 2048 bit key: A more convenient way is to use the `KeyPairUtils` class. This call generates a RSA key pair with a 2048 bit key:
```java ```java
KeyPair accountKeyPair = KeyPairUtils.createKeyPair(2048); KeyPair accountKeyPair = KeyPairUtils.createKeyPair(2048);

View File

@ -77,7 +77,7 @@ The response you have set up before is not needed any more. You can (and should)
After successfully completing all authorizations, the order needs to be finalized by providing PKCS#10 CSR file. A single domain may be set as _Common Name_. Multiple domains must be provided as _Subject Alternative Name_. You must provide exactly the domains that you had passed to the `order()` method above, otherwise the finalization will fail. It depends on the CA if other CSR properties (_Organization_, _Organization Unit_ etc.) are accepted. Some may require these properties to be set, while others may ignore them when generating the certificate. After successfully completing all authorizations, the order needs to be finalized by providing PKCS#10 CSR file. A single domain may be set as _Common Name_. Multiple domains must be provided as _Subject Alternative Name_. You must provide exactly the domains that you had passed to the `order()` method above, otherwise the finalization will fail. It depends on the CA if other CSR properties (_Organization_, _Organization Unit_ etc.) are accepted. Some may require these properties to be set, while others may ignore them when generating the certificate.
CSR files can be generated with command line tools like `openssl`. Unfortunately the standard Java does not offer classes for that, so you'd have to resort to [Bouncy Castle](http://www.bouncycastle.org/java.html) if you want to create a CSR programmatically. In the `acme4j-utils` module, there is a [`CSRBuilder`](../acme4j-utils/apidocs/org.shredzone.acme4j.utils/org/shredzone/acme4j/util/CSRBuilder.html) for your convenience. You can also use [`KeyPairUtils`](../acme4j-utils/apidocs/org.shredzone.acme4j.utils/org/shredzone/acme4j/util/KeyPairUtils.html) for generating a new key pair for your domain. CSR files can be generated with command line tools like `openssl`. Unfortunately the standard Java does not offer classes for that, so you'd have to resort to [Bouncy Castle](http://www.bouncycastle.org/java.html) if you want to create a CSR programmatically. There is a [`CSRBuilder`](../acme4j-client/apidocs/org.shredzone.acme4j.utils/org/shredzone/acme4j/util/CSRBuilder.html) for your convenience. You can also use [`KeyPairUtils`](../acme4j-client/apidocs/org.shredzone.acme4j.utils/org/shredzone/acme4j/util/KeyPairUtils.html) for generating a new key pair for your domain.
!!! tip !!! tip
Never use your account key pair as domain key pair, but always generate separate key pairs! Never use your account key pair as domain key pair, but always generate separate key pairs!

View File

@ -20,7 +20,6 @@ nav:
- 'example.md' - 'example.md'
- JavaDocs: - JavaDocs:
- 'acme4j-client': acme4j-client/apidocs/index.html - 'acme4j-client': acme4j-client/apidocs/index.html
- 'acme4j-utils': acme4j-utils/apidocs/index.html
- 'acme4j-smime': acme4j-smime/apidocs/index.html - 'acme4j-smime': acme4j-smime/apidocs/index.html
- 'acme4j-it': acme4j-it/apidocs/index.html - 'acme4j-it': acme4j-it/apidocs/index.html
- Usage: - Usage: