mirror of https://github.com/shred/acme4j
Add full documentation
parent
afaf286a49
commit
9bcd5a2dd4
33
README.md
33
README.md
|
@ -1,15 +1,14 @@
|
|||
# ACME Java Client 
|
||||
|
||||
This is a Java client for the [ACME](https://tools.ietf.org/html/draft-ietf-acme-acme-01) protocol.
|
||||
This is a Java client for the [Automatic Certificate Management Environment (ACME)](https://tools.ietf.org/html/draft-ietf-acme-acme-01) protocol.
|
||||
|
||||
ACME is a protocol that a certificate authority (CA) and an applicant can use to automate the process of verification and certificate issuance.
|
||||
|
||||
This Java client helps connecting to an ACME server, and performing all necessary steps to manage certificates.
|
||||
|
||||
It is an independent open source implementation that is not affiliated with or endorsed by _Let's Encrypt_. The source code can be found at [GitHub](https://github.com/shred/acme4j) and is distributed under the terms of [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
||||
It is an independent open source implementation that is not affiliated with or endorsed by _Let's Encrypt_.
|
||||
|
||||
Alpha Release!
|
||||
--------------
|
||||
## Alpha Release!
|
||||
|
||||
Please note that even though _acme4j_ is already usable, it is currently in an early alpha state. This means that:
|
||||
|
||||
|
@ -17,33 +16,29 @@ Please note that even though _acme4j_ is already usable, it is currently in an e
|
|||
* The API is not stable. It may change in a manner not compatible to previous versions and without prior notice.
|
||||
* _acme4j_ is not thoroughly tested yet, and may still have major bugs.
|
||||
|
||||
Features
|
||||
--------
|
||||
## Features
|
||||
|
||||
* Easy to use Java API
|
||||
* Requires JRE 7 or higher
|
||||
* Built with maven (package will be made available at Maven Central as soon as beta state is reached)
|
||||
* Small, only requires [jose4j](https://bitbucket.org/b_c/jose4j/wiki/Home) and [slf4j](http://www.slf4j.org/) as dependencies. [Bouncy Castle](https://www.bouncycastle.org/java.html) is recommended, but not required.
|
||||
* Small, only requires [jose4j](https://bitbucket.org/b_c/jose4j/wiki/Home) and [slf4j](http://www.slf4j.org/) as dependencies
|
||||
* Extensive unit tests
|
||||
|
||||
How to Use
|
||||
----------
|
||||
## Usage
|
||||
|
||||
_acme4j_ consists of a few modules:
|
||||
See the [online documentation](http://www.shredzone.org/maven/acme4j/) for how to use _acme4j_. Or just have a look at [the source code of an example](https://github.com/shred/acme4j/blob/master/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java).
|
||||
|
||||
* _acme4j-client_: This is the main module. It contains the ACME client and everything needed for communication with an ACME server.
|
||||
* _acme4j-utils_: Some utility classes that may be helpful for creating key pairs, certificates, and certificate signing requests. Requires [Bouncy Castle](https://www.bouncycastle.org/java.html).
|
||||
* _acme4j-example_: An example tool that performs all steps for registering a new account at _Let's Encrypt_ and getting a certificate for a set of domain names. This is a good starting point to find out how _acme4j_ is used.
|
||||
|
||||
Missing
|
||||
-------
|
||||
## Missing
|
||||
|
||||
The following features are planned to be completed for the first beta release, but are still missing:
|
||||
|
||||
* Support of account recovery and certificate revocation.
|
||||
* `proofOfPossession-01` and `tls-sni-01` challenge support.
|
||||
* Extensive unit tests.
|
||||
* Better error handling.
|
||||
* Some hardening (like plausibility checks).
|
||||
* Full documentation.
|
||||
|
||||
_acme4j_ is open source software. Feel free to send in pull requests!
|
||||
## License
|
||||
|
||||
_acme4j_ is open source software. The source code can be found at [GitHub](https://github.com/shred/acme4j) and is distributed under the terms of [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
||||
Feel free to send in pull requests!
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
<artifactId>acme4j-client</artifactId>
|
||||
|
||||
<name>acme4j client</name>
|
||||
<name>acme4j Client</name>
|
||||
<description>ACME client for Java</description>
|
||||
|
||||
<dependencies>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
This is the client part of the Java ACME client.
|
|
@ -0,0 +1,17 @@
|
|||
acme4j Client
|
||||
=============
|
||||
|
||||
This is the main part of _acme4j_.
|
||||
|
||||
How to Use
|
||||
----------
|
||||
|
||||
_acme4j_ is availabe at Maven Central. Just add this snippet to your `pom.xml`:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>${project.artifactId}</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
```
|
|
@ -1,6 +0,0 @@
|
|||
a.externalLink, a.externalLink:link, a.externalLink:visited, a.externalLink:active, a.externalLink:hover {
|
||||
background: none;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
<version position="right"/>
|
||||
<body>
|
||||
<links>
|
||||
<item name="Home" href="index.html"/>
|
||||
<item name="Project Management" href="http://acme4j.shredzone.org"/>
|
||||
<item name="API javadoc" href="./apidocs/index.html"/>
|
||||
<item name="GitHub" href="https://github.com/shred/acme4j"/>
|
||||
</links>
|
||||
<breadcrumbs>
|
||||
<item name="shredzone.org" href="http://www.shredzone.org"/>
|
||||
|
@ -29,10 +29,15 @@
|
|||
<item name="acme4j-client" href="index.html"/>
|
||||
</breadcrumbs>
|
||||
<menu name="Main">
|
||||
<item name="Introduction" href="index.html"/>
|
||||
<item name="Project Management" href="http://acme4j.shredzone.org"/>
|
||||
<item name="Description" href="index.html"/>
|
||||
</menu>
|
||||
<menu ref="modules"/>
|
||||
<menu ref="reports"/>
|
||||
</body>
|
||||
|
||||
<skin>
|
||||
<groupId>org.apache.maven.skins</groupId>
|
||||
<artifactId>maven-fluido-skin</artifactId>
|
||||
<version>1.4</version>
|
||||
</skin>
|
||||
</project>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
<artifactId>acme4j-example</artifactId>
|
||||
|
||||
<name>acme4j example</name>
|
||||
<name>acme4j Example</name>
|
||||
<description>Example for using acme4j</description>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
An example about how to use the Java ACME client.
|
|
@ -0,0 +1,19 @@
|
|||
acme4j Example
|
||||
==============
|
||||
|
||||
An example tool that uses _acme4j_, and a good starting point to find out how _acme4j_ is used.
|
||||
|
||||
This tool registers a new account with the _Let's Encrypt_ staging server, and fetches a certificate for a set of domains.
|
||||
|
||||
How to Use
|
||||
----------
|
||||
|
||||
Run the `org.shredzone.acme4j.ClientTest` class with the domains to be registered as parameters.
|
||||
|
||||
You can also invoke the example tool via maven:
|
||||
|
||||
```
|
||||
mvn exec:java -Dexec.args="example.com example.org"
|
||||
```
|
||||
|
||||
Or just have a look at [the source code](https://github.com/shred/acme4j/blob/master/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java).
|
|
@ -1,6 +0,0 @@
|
|||
a.externalLink, a.externalLink:link, a.externalLink:visited, a.externalLink:active, a.externalLink:hover {
|
||||
background: none;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
|
|
@ -20,8 +20,7 @@
|
|||
<version position="right"/>
|
||||
<body>
|
||||
<links>
|
||||
<item name="Home" href="index.html"/>
|
||||
<item name="Project Management" href="http://acme4j.shredzone.org"/>
|
||||
<item name="GitHub" href="https://github.com/shred/acme4j"/>
|
||||
</links>
|
||||
<breadcrumbs>
|
||||
<item name="shredzone.org" href="http://www.shredzone.org"/>
|
||||
|
@ -29,10 +28,15 @@
|
|||
<item name="acme4j-example" href="index.html"/>
|
||||
</breadcrumbs>
|
||||
<menu name="Main">
|
||||
<item name="Introduction" href="index.html"/>
|
||||
<item name="Project Management" href="http://acme4j.shredzone.org"/>
|
||||
<item name="Description" href="index.html"/>
|
||||
</menu>
|
||||
<menu ref="modules"/>
|
||||
<menu ref="reports"/>
|
||||
</body>
|
||||
|
||||
<skin>
|
||||
<groupId>org.apache.maven.skins</groupId>
|
||||
<artifactId>maven-fluido-skin</artifactId>
|
||||
<version>1.4</version>
|
||||
</skin>
|
||||
</project>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
<artifactId>acme4j-utils</artifactId>
|
||||
|
||||
<name>acme4j utils</name>
|
||||
<name>acme4j Utils</name>
|
||||
<description>acme4j utilities</description>
|
||||
|
||||
<dependencies>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Some utility classes for using the Java ACME client.
|
|
@ -0,0 +1,19 @@
|
|||
acme4j Utils
|
||||
============
|
||||
|
||||
Some utility classes to be used with _acme4j_. They will help generating and processing keys and signatures.
|
||||
|
||||
Note that (unlike `acme4j-client`) this module requires [Bouncy Castle](https://www.bouncycastle.org/java.html).
|
||||
|
||||
How to Use
|
||||
----------
|
||||
|
||||
Just add this snippet to your `pom.xml`:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>${project.artifactId}</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
```
|
|
@ -1,6 +0,0 @@
|
|||
a.externalLink, a.externalLink:link, a.externalLink:visited, a.externalLink:active, a.externalLink:hover {
|
||||
background: none;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
<version position="right"/>
|
||||
<body>
|
||||
<links>
|
||||
<item name="Home" href="index.html"/>
|
||||
<item name="Project Management" href="http://acme4j.shredzone.org"/>
|
||||
<item name="API javadoc" href="./apidocs/index.html"/>
|
||||
<item name="GitHub" href="https://github.com/shred/acme4j"/>
|
||||
</links>
|
||||
<breadcrumbs>
|
||||
<item name="shredzone.org" href="http://www.shredzone.org"/>
|
||||
|
@ -29,10 +29,15 @@
|
|||
<item name="acme4j-utils" href="index.html"/>
|
||||
</breadcrumbs>
|
||||
<menu name="Main">
|
||||
<item name="Introduction" href="index.html"/>
|
||||
<item name="Project Management" href="http://acme4j.shredzone.org"/>
|
||||
<item name="Description" href="index.html"/>
|
||||
</menu>
|
||||
<menu ref="modules"/>
|
||||
<menu ref="reports"/>
|
||||
</body>
|
||||
|
||||
<skin>
|
||||
<groupId>org.apache.maven.skins</groupId>
|
||||
<artifactId>maven-fluido-skin</artifactId>
|
||||
<version>1.4</version>
|
||||
</skin>
|
||||
</project>
|
||||
|
|
9
pom.xml
9
pom.xml
|
@ -97,10 +97,17 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.3</version>
|
||||
<version>3.4</version>
|
||||
<configuration>
|
||||
<outputEncoding>UTF-8</outputEncoding>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.doxia</groupId>
|
||||
<artifactId>doxia-module-markdown</artifactId>
|
||||
<version>1.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
This is a Java ACME client.
|
|
@ -0,0 +1,25 @@
|
|||
# Certificate Authorities
|
||||
|
||||
_acme4j_ should support any CA providing an ACME server.
|
||||
|
||||
It is always possible to connect to an ACME server by passing in the CA's resource directory URI:
|
||||
|
||||
```java
|
||||
AcmeClient client =
|
||||
AcmeClientFactory.connect("https://acme-staging.api.letsencrypt.org/directory");
|
||||
```
|
||||
|
||||
For some CAs there are also more specific ACME providers available via `acme` schemed URIs:
|
||||
|
||||
```java
|
||||
AcmeClient client =
|
||||
AcmeClientFactory.connect("acme://letsencrypt.org/staging");
|
||||
```
|
||||
|
||||
Connecting via `acme` URI should always be preferred over using the directory URL.
|
||||
|
||||
## Available Providers
|
||||
|
||||
In _acme4j_ these providers are available:
|
||||
|
||||
* [Let's Encrypt](./letsencrypt.html)
|
|
@ -0,0 +1,21 @@
|
|||
# Let's Encrypt
|
||||
|
||||
Web site: [Let's Encrypt](https://letsencrypt.org)
|
||||
|
||||
## Connection URIs
|
||||
|
||||
* `acme://letsencrypt.org` - Production server
|
||||
* `acme://letsencrypt.org/staging` - Testing server
|
||||
* `acme://letsencrypt.org/v01` - Production server, pinned to API v01
|
||||
|
||||
## Features
|
||||
|
||||
* Connection to the ACME server is pinned to the Let's Encrypt certificate
|
||||
|
||||
## Intermediate Certificates
|
||||
|
||||
The _Let's Encrypt_ intermediate certificates are available [here](https://letsencrypt.org/certificates/).
|
||||
|
||||
## Renewal
|
||||
|
||||
Just download the renewed certificate from the certificate URL that was provided by `requestCertificate()`.
|
|
@ -0,0 +1,14 @@
|
|||
# DNS Challenge
|
||||
|
||||
After authorizing the challenge, `DnsChallenge` provides a digest string:
|
||||
|
||||
```java
|
||||
DnsChallenge challenge = auth.findChallenge(DnsChallenge.TYPE);
|
||||
challenge.authorize(account);
|
||||
|
||||
String digest = challenge.getDigest();
|
||||
```
|
||||
|
||||
The CA expects a TXT record at `_acme-challenge.${domain}` with the `digest` string as value.
|
||||
|
||||
The challenge is completed when the CA was able to fetch the TXT record and got the correct `digest` returned.
|
|
@ -0,0 +1,21 @@
|
|||
# HTTP Challenge
|
||||
|
||||
After authorizing the challenge, `HttpChallenge` provides two strings:
|
||||
|
||||
```java
|
||||
HttpChallenge challenge = auth.findChallenge(HttpChallenge.TYPE);
|
||||
challenge.authorize(account);
|
||||
|
||||
String token = challenge.getToken();
|
||||
String content = challenge.getAuthorization();
|
||||
```
|
||||
|
||||
`token` is the name of the file that will be requested by the CA server. It must contain the `content` string, without any leading or trailing white spaces or line breaks. The `Content-Type` header must be either `text/plain` or absent.
|
||||
|
||||
The expected path is (assuming that `${domain}` is your domain and `${token}` is the token):
|
||||
|
||||
```
|
||||
http://${domain}/.well-known/acme-challenge/${token}
|
||||
```
|
||||
|
||||
The challenge is completed when the CA was able to download that file and found `content` in it.
|
|
@ -0,0 +1,14 @@
|
|||
# Challenges
|
||||
|
||||
Challenges are used to prove ownership of a domain.
|
||||
|
||||
There are different kind of challenges. The most simple is maybe the HTTP challenge, where a file must be made available at the domain that is to be validated. It is assumed that you control the domain if you are able to publish a given file under a given path.
|
||||
|
||||
The CA offers one or more sets of challenges. At least one set has to be completed in order to prove ownership.
|
||||
|
||||
The ACME specifications define four standard challenges:
|
||||
|
||||
* [HTTP](./http.html)
|
||||
* [DNS](./dns.html)
|
||||
* [TLS-SNI](./tls-sni.html)
|
||||
* [Proof of Possession](./proof-of-possession.html)
|
|
@ -0,0 +1,3 @@
|
|||
# Proof of Possession
|
||||
|
||||
This challenge is not yet implemented in _acme4j_.
|
|
@ -0,0 +1,3 @@
|
|||
# TLS-SNI
|
||||
|
||||
This challenge is not yet implemented in _acme4j_.
|
|
@ -0,0 +1,37 @@
|
|||
acme4j
|
||||
======
|
||||
|
||||
A Java client for the [Automatic Certificate Management Environment (ACME)](https://tools.ietf.org/html/draft-ietf-acme-acme-01) protocol.
|
||||
|
||||
ACME is a protocol that a certificate authority (CA) and an applicant can use to automate the process of verification and certificate issuance.
|
||||
|
||||
This Java client helps connecting to an ACME server, and performing all necessary steps to manage certificates.
|
||||
|
||||
It is an independent open source implementation that is not affiliated with or endorsed by _Let's Encrypt_.
|
||||
|
||||
The source code can be found at [GitHub](https://github.com/shred/acme4j) and is distributed under the terms of [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
||||
_acme4j_ is available at Maven Central. Just add this snippet to your `pom.xml`:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>${project.artifactId}-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
There is also an optional utility module that will help you handling key pairs and certificates (but requires [Bouncy Castle](https://www.bouncycastle.org/java.html)):
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>${project.artifactId}-utils</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Now just have a look at [this source code](https://github.com/shred/acme4j/blob/master/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java) to see an example usage.
|
|
@ -0,0 +1,54 @@
|
|||
# ACME Client Provider
|
||||
|
||||
Basically, it is possible to connect to any kind of ACME server just by connecting to the URI of its directory resource:
|
||||
|
||||
```java
|
||||
AcmeClient client =
|
||||
AcmeClientFactory.connect("https://acme-v01.api.letsencrypt.org/directory");
|
||||
```
|
||||
|
||||
ACME client providers are "plug-ins" to _acme4j_ that are specialized on a single CA. For example, the _Let's Encrypt_ client provider offers connection URIs that are much easier to remember. Opening a connection like in the example above looks like this:
|
||||
|
||||
```java
|
||||
AcmeClient client = AcmeClientFactory.connect("acme://letsencrypt.org");
|
||||
```
|
||||
|
||||
## Writing an own Client Provider
|
||||
|
||||
Every CA that provides an ACME server should also have an own Client Provider, and if it is just for the sake of a pretty `acme:` URI.
|
||||
|
||||
However, it is also possible to adapt the behavior of wide parts of _acme4j_ to special characteristics of the CA, just by overriding methods and extending classes.
|
||||
|
||||
A client provider implements the [`AcmeClientProvider`](./apidocs/org/shredzone/acme4j/provider/AcmeClientProvider.html) interface, but usually it is easier to extend [`AbstractAcmeClientProvider`](./apidocs/org/shredzone/acme4j/provider/AbstractAcmeClientProvider.html) and implement only these two methods:
|
||||
|
||||
* `accepts(URI)` checks if the client provider is accepting the provided URI. Usually it would be an URI like `acme://example.com`. Note that the `http` and `https` schemes are reserved for the generic provider and cannot be used by client providers.
|
||||
* `resolve(URI)` parses that URI and returns the corresponding URI of the directory service.
|
||||
|
||||
The `AcmeClientProvider` implementation needs to be registered with Java's `ServiceLoader`. In the `META-INF/services` path of your project, create a file `org.shredzone.acme4j.provider.AcmeClientProvider` and write the fully qualified class name of your implementation into that file.
|
||||
|
||||
When _acme4j_ tries to connect to an acme URI, it first invokes the `accepts(URI)` method of all registered `AcmeClientProvider`s. Only one of the providers must return `true` for a successful connection. _acme4j_ then invokes the `resolve(URI)` method of that provider, and connects to the directory URI that is returned.
|
||||
|
||||
The connection fails if none or more than one `AcmeClientProvider` implementations `accept` the acme URI.
|
||||
|
||||
## Certificate Pinning
|
||||
|
||||
Client providers may verify the HTTPS certificate provided by the ACME server.
|
||||
|
||||
To do so, override the `createHttpConnector()` method of `AbstractAcmeClientProvider` and return a subclassed `HttpConnector` class that modifies the `HttpURLConnection` as required.
|
||||
|
||||
The source code of the [_Let's Encrypt_ provider](./apidocs/org/shredzone/acme4j/provider/letsencrypt/package-summary.html) gives an example of how to do that.
|
||||
|
||||
## Individual Challenges
|
||||
|
||||
If your ACME server provides challenges that are not specified in the ACME protocol, there should be an own `Challenge` implementation for each of your challenge, by either implementing the [`Challenge`](./apidocs/org/shredzone/acme4j/challenge/Challenge.html)
|
||||
interface or (more conveniently) extending the [`GenericChallenge`](./apidocs/org/shredzone/acme4j/challenge/GenericChallenge.html) class.
|
||||
|
||||
In your `AcmeClientProvider` implementation, override the `createChallenge(String)` method so it returns a new instance of your `Challenge` implementation when your individual challenge type is requested. All other types should be delegated to the super method.
|
||||
|
||||
## No directory service
|
||||
|
||||
An ACME server may not provide a directory service, for example when fixed URIs are to be used.
|
||||
|
||||
In this case, extend `GenericAcmeClient` and override the `resourceUri(Resource)` method. It should return the URI of the given resource.
|
||||
|
||||
Your `AcmeClientProvider`'s `connect(URI)` method would then return a new instance of your `GenericAcmeClient` class. Just use `null` as your directory URI.
|
|
@ -0,0 +1,64 @@
|
|||
# Authorize your Domains
|
||||
|
||||
Once you have your account set up, you need to associate your domain with it. This is done by using an `Authorization` data transfer object:
|
||||
|
||||
```java
|
||||
Authorization auth = new Authorization();
|
||||
auth.setDomain("example.org");
|
||||
|
||||
client.newAuthorization(account, auth);
|
||||
```
|
||||
|
||||
When `newAuthorization()` returns successfully, the `Authorization` instance contains further details about how you can prove ownership of your domain. An ACME server offers combinations of different authorization methods, called `Challenge`s.
|
||||
|
||||
`Authorization` methods help you find the `Challenge` that fits best to your possibilities. Just pass all the challenge types that your software is able to accept to `findCombination()`, and it returns the shortest possible combination of `Challenge`s you have to perform.
|
||||
|
||||
In the following example, your software would be able to either perform a HTTP or DNS challenge, or both:
|
||||
|
||||
```java
|
||||
Collection<Challenge> combination = auth.findCombination(
|
||||
HttpChallenge.TYPE, DnsChallenge.TYPE);
|
||||
```
|
||||
|
||||
The returned `combination` contains a single combination of challenges you would have to perform. If the combination consists of more than one challenge, you would have to perform _all of them_ in order to successfully authorize your domain. If `null` is returned, it means that none of your offered challenge types are acceptable to the CA.
|
||||
|
||||
If your software only implements a single challenge type, `findChallenge()` may be a little easier to use:
|
||||
|
||||
```java
|
||||
HttpChallenge challenge = auth.findChallenge(HttpChallenge.TYPE);
|
||||
```
|
||||
|
||||
It returns a properly casted `Challenge` object, or `null` if your challenge type was not acceptable.
|
||||
|
||||
After you have found a challenge, you need to sign it first:
|
||||
|
||||
```java
|
||||
challenge.authorize(account);
|
||||
```
|
||||
|
||||
After signing the challenge, it provides the necessary data for a successful response to the challenge. The kind of response depends on the challenge type (see the [documentation of challenges](../challenge/index.html)). Some types may also require more data for authorizing the challenge.
|
||||
|
||||
After you have performed the necessary steps to set up the response to the challenge, the ACME server is told to test your response:
|
||||
|
||||
```java
|
||||
client.triggerChallenge(account, challenge);
|
||||
```
|
||||
|
||||
Again, the call completes the `Challenge` transfer object with server side data like the current challenge status and a challenge URI.
|
||||
|
||||
Now you have to wait for the server to test your response and set the challenge status to `VALID`. The easiest way is to poll the status:
|
||||
|
||||
```java
|
||||
while (challenge.getStatus() != Challenge.Status.VALID) {
|
||||
Thread.sleep(3000L);
|
||||
client.updateChallenge(account, challenge);
|
||||
}
|
||||
```
|
||||
|
||||
This is a very simple example. You should limit the number of loop iterations, and abort the loop when the status should turn to `INVALID`. If you know when the CA server actually requested your response (e.g. when you notice a HTTP request on the response file), you should start polling after that event.
|
||||
|
||||
As soon as the challenge is `VALID`, you have successfully associated the domain with your account.
|
||||
|
||||
If your final certificate contains further domains or subdomains, repeat the authorization run with each of them.
|
||||
|
||||
Note that wildcard certificates are not currently supported.
|
|
@ -0,0 +1,38 @@
|
|||
# Request a Certificate
|
||||
|
||||
Once you completed all the previous steps, it's time to request the signed certificate.
|
||||
|
||||
To do so, prepare a PKCS#10 CSR file. A single domain may be set as _Common Name_. Multiple domains must be provided as _Subject Alternative Name_. Other properties (_Organization_, _Organization Unit_ etc.) depend on the CA. 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 also a [`CSRBuilder`](../apidocs/org/shredzone/acme4j/util/CSRBuilder.html) for your convenience:
|
||||
|
||||
```java
|
||||
KeyPair domainKeyPair = ... // KeyPair to be used for HTTPS encryption
|
||||
|
||||
CSRBuilder csrb = new CSRBuilder();
|
||||
csrb.addDomain("example.org");
|
||||
csrb.addDomain("www.example.org");
|
||||
csrb.setOrganization("The Example Organization")
|
||||
csrb.sign(domainKeyPair);
|
||||
byte[] csr = csrb.getEncoded();
|
||||
```
|
||||
|
||||
Now all you need to do is to pass in a binary representation of the CSR and request the certificate:
|
||||
|
||||
```java
|
||||
byte[] csr = ... // your CSR
|
||||
|
||||
URI certUri = client.requestCertificate(account, csr);
|
||||
```
|
||||
|
||||
`certUri` contains an URI where the signed certificate can be downloaded from. You can either download it from there yourself (e.g. with `curl`), or just use the `AcmeClient`:
|
||||
|
||||
```java
|
||||
X509Certificate cert = client.downloadCertificate(certUri);
|
||||
```
|
||||
|
||||
Congratulations! You have just created your first certificate via _acme4j_.
|
||||
|
||||
## Renewal
|
||||
|
||||
Renewing your certificate depends on the CA. Some may require you to go through the authorization process again, while others may just provide an updated certificate for download at the `certUri` above.
|
|
@ -0,0 +1,20 @@
|
|||
# Connect to an ACME server
|
||||
|
||||
[`AcmeClientFactory.connect()`](../apidocs/org/shredzone/acme4j/AcmeClientFactory.html) creates an [`AcmeClient`](../apidocs/org/shredzone/acme4j/AcmeClient.html) and connects it to an ACME server.
|
||||
|
||||
The `connect()` method expects the URI of the ACME server's directory service, as it is documented by the CA. For example, this is how to connect to the _Let's Encrypt_ staging server:
|
||||
|
||||
```java
|
||||
AcmeClient client =
|
||||
AcmeClientFactory.connect("https://acme-staging.api.letsencrypt.org/directory");
|
||||
```
|
||||
|
||||
However, such an URI is hard to remember and might even change in the future. Java also does not accept the certificate used by the _Let's Encrypt_ server, so calls to the `AcmeClient` are likely to throw a certificate exception.
|
||||
|
||||
For this reason, special ACME URIs should be preferred:
|
||||
|
||||
```java
|
||||
AcmeClient client = AcmeClientFactory.connect("acme://letsencrypt.org/staging");
|
||||
```
|
||||
|
||||
Instead of a generic provider, this call uses a special _Let's Encrypt_ provider that also accepts the _Let's Encrypt_ certificate.
|
|
@ -0,0 +1,21 @@
|
|||
# How to Use _acme4j_
|
||||
|
||||
_acme4j_ is a client library that helps connecting to ACME servers without worrying about specification details.
|
||||
|
||||
Central part of the communication is an [`Account`](../apidocs/org/shredzone/acme4j/Account.html) object, which contains a key pair. The ACME server identifies your account by the public key, and verifies that your requests are signed with your private key. For this reason, you should keep the key pair in a safe place. If you should lose it, you would need to recover access to your account.
|
||||
|
||||
The first step is to create a Java `KeyPair`, save it somewhere, and then pass it to the constructor of `Account`:
|
||||
|
||||
```java
|
||||
KeyPair keypair = ... // your key pair
|
||||
Account account = new Account(keypair);
|
||||
```
|
||||
|
||||
You need this `Account` instance as identifier for almost all API calls.
|
||||
|
||||
To get a certificate, these steps need to be performed:
|
||||
|
||||
* [Connect to an ACME server](./connect.html)
|
||||
* [Register and Create an Account](./register.html)
|
||||
* [Authorize your Domains](./authorization.html)
|
||||
* [Request and Download a Certificate](./certificate.html)
|
|
@ -0,0 +1,39 @@
|
|||
# Register an Account
|
||||
|
||||
The first thing to do is to register your `Account` with the CA.
|
||||
|
||||
You need a `Registration` instance that serves as a data transfer object, and fill the object with details of your account. The `AcmeClient.newRegistration()` call then completes the data transfer object with server side account data.
|
||||
|
||||
This code fragment registers your account with the CA. Optionally you can add contact URIs (like email addresses or phone numbers) to the registration, which will help the CA getting in contact with you.
|
||||
|
||||
```java
|
||||
Registration reg = new Registration();
|
||||
reg.getContacts().add("mailto:acme@example.com"); // optional
|
||||
|
||||
client.newRegistration(account, reg);
|
||||
|
||||
URI accountLocationUri = reg.getLocation(); // your account's server URI
|
||||
```
|
||||
|
||||
After invocating `newRegistration()`, the `location` property contains the URI of your newly created account on server side.
|
||||
|
||||
`newRegistration()` may fail and throw an `AcmeException` for various reasons. When your public key was already registered with the CA, an `AcmeConflictException` is thrown, but the `location` property will still hold your account URI after the call. This may be helpful if you forgot your account URI and need to recover it.
|
||||
|
||||
## Update an Account
|
||||
|
||||
At some point, you may want to update your account. For example your contact address might have changed, or you were asked by the CA to accept the current terms and conditions.
|
||||
|
||||
To do so, create a `Registration` object again, and set the `location` property to the URI that you previously got via `newRegistration()`. Also set whatever you like to change to your account.
|
||||
|
||||
The following example accepts the terms and conditions by explicitly setting the URL to the agreement document.
|
||||
|
||||
```java
|
||||
URI accountLocationUri = ... // your account's URI
|
||||
URI agreementUri = ... // TAC link provided by the CA
|
||||
|
||||
Registration reg = new Registration();
|
||||
reg.setLocation(accountLocationUri);
|
||||
reg.setAgreement(agreementUri);
|
||||
|
||||
client.updateRegistration(account, reg);
|
||||
```
|
|
@ -1,6 +0,0 @@
|
|||
a.externalLink, a.externalLink:link, a.externalLink:visited, a.externalLink:active, a.externalLink:hover {
|
||||
background: none;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
|
|
@ -20,18 +20,39 @@
|
|||
<version position="right"/>
|
||||
<body>
|
||||
<links>
|
||||
<item name="Home" href="index.html"/>
|
||||
<item name="Project Management" href="http://acme4j.shredzone.org"/>
|
||||
<item name="API javadoc" href="./apidocs/index.html"/>
|
||||
<item name="GitHub" href="https://github.com/shred/acme4j"/>
|
||||
</links>
|
||||
<breadcrumbs>
|
||||
<item name="shredzone.org" href="http://www.shredzone.org"/>
|
||||
<item name="acme4j" href="index.html"/>
|
||||
</breadcrumbs>
|
||||
<menu name="Main">
|
||||
<menu name="Documentation">
|
||||
<item name="Introduction" href="index.html"/>
|
||||
<item name="Project Management" href="http://acme4j.shredzone.org"/>
|
||||
<item name="How to Use" href="usage/index.html">
|
||||
<item name="Connection" href="usage/connect.html"/>
|
||||
<item name="Account" href="usage/register.html"/>
|
||||
<item name="Authorization" href="usage/authorization.html"/>
|
||||
<item name="Certificate" href="usage/certificate.html"/>
|
||||
</item>
|
||||
<item name="Challenges" href="challenge/index.html">
|
||||
<item name="HTTP" href="challenge/http.html"/>
|
||||
<item name="DNS" href="challenge/dns.html"/>
|
||||
<item name="tls-sni" href="challenge/tls-sni.html"/>
|
||||
<item name="Proof of Possession" href="challenge/proof-of-possession.html"/>
|
||||
</item>
|
||||
<item name="CAs" href="ca/index.html">
|
||||
<item name="Let's Encrypt" href="ca/letsencrypt.html"/>
|
||||
</item>
|
||||
<item name="ACME Client Provider" href="provider.html"/>
|
||||
</menu>
|
||||
<menu ref="modules"/>
|
||||
<menu ref="reports"/>
|
||||
</body>
|
||||
|
||||
<skin>
|
||||
<groupId>org.apache.maven.skins</groupId>
|
||||
<artifactId>maven-fluido-skin</artifactId>
|
||||
<version>1.4</version>
|
||||
</skin>
|
||||
</project>
|
||||
|
|
Loading…
Reference in New Issue