mirror of https://github.com/shred/acme4j
Add new writer for certificate chains
parent
ef42e04793
commit
7c033095e6
|
@ -50,6 +50,7 @@ public class ClientTest {
|
|||
private static final File DOMAIN_KEY_FILE = new File("domain.key");
|
||||
private static final File DOMAIN_CERT_FILE = new File("domain.crt");
|
||||
private static final File CERT_CHAIN_FILE = new File("chain.crt");
|
||||
private static final File DOMAIN_CHAIN_FILE = new File("domain-chain.crt");
|
||||
private static final File DOMAIN_CSR_FILE = new File("domain.csr");
|
||||
|
||||
private static final int KEY_SIZE = 2048;
|
||||
|
@ -181,14 +182,21 @@ public class ClientTest {
|
|||
|
||||
// Download the certificate
|
||||
X509Certificate cert = certificate.download();
|
||||
X509Certificate[] chain = certificate.downloadChain();
|
||||
|
||||
// Write certificate only (e.g. for Apache's SSLCertificateFile)
|
||||
try (FileWriter fw = new FileWriter(DOMAIN_CERT_FILE)) {
|
||||
CertificateUtils.writeX509Certificate(cert, fw);
|
||||
}
|
||||
|
||||
// Download the certificate chain
|
||||
X509Certificate[] chain = certificate.downloadChain();
|
||||
// Write chain only (e.g. for Apache's SSLCertificateChainFile)
|
||||
try (FileWriter fw = new FileWriter(CERT_CHAIN_FILE)) {
|
||||
CertificateUtils.writeX509CertificateChain(chain, fw);
|
||||
CertificateUtils.writeX509CertificateChain(fw, null, chain);
|
||||
}
|
||||
|
||||
// Write combined certificate and chain (e.g. for nginx)
|
||||
try (FileWriter fw = new FileWriter(DOMAIN_CHAIN_FILE)) {
|
||||
CertificateUtils.writeX509CertificateChain(fw, cert, chain);
|
||||
}
|
||||
|
||||
// Revoke the certificate (uncomment if needed...)
|
||||
|
|
|
@ -44,7 +44,7 @@ import org.bouncycastle.util.io.pem.PemWriter;
|
|||
/**
|
||||
* Generator for a CSR (Certificate Signing Request) suitable for ACME servers.
|
||||
* <p>
|
||||
* Requires {@code Bouncy Castle}.
|
||||
* Requires {@code Bouncy Castle}. This class is part of the {@code acme4j-utils} module.
|
||||
*/
|
||||
public class CSRBuilder {
|
||||
private static final String SIGNATURE_ALG = "SHA256withRSA";
|
||||
|
@ -199,7 +199,8 @@ public class CSRBuilder {
|
|||
* Writes the signed certificate request to a {@link Writer}.
|
||||
*
|
||||
* @param w
|
||||
* {@link Writer} to write the PEM file to
|
||||
* {@link Writer} to write the PEM file to. The {@link Writer} is closed
|
||||
* after use.
|
||||
*/
|
||||
public void write(Writer w) throws IOException {
|
||||
if (csr == null) {
|
||||
|
@ -215,7 +216,8 @@ public class CSRBuilder {
|
|||
* Writes the signed certificate request to an {@link OutputStream}.
|
||||
*
|
||||
* @param out
|
||||
* {@link OutputStream} to write the PEM file to
|
||||
* {@link OutputStream} to write the PEM file to. The {@link OutputStream}
|
||||
* is closed after use.
|
||||
*/
|
||||
public void write(OutputStream out) throws IOException {
|
||||
write(new OutputStreamWriter(out, "utf-8"));
|
||||
|
|
|
@ -42,7 +42,7 @@ import org.shredzone.acme4j.challenge.TlsSni02Challenge;
|
|||
/**
|
||||
* Utility class offering convenience methods for certificates.
|
||||
* <p>
|
||||
* Requires {@code Bouncy Castle}.
|
||||
* Requires {@code Bouncy Castle}. This class is part of the {@code acme4j-utils} module.
|
||||
*/
|
||||
public final class CertificateUtils {
|
||||
|
||||
|
@ -54,7 +54,8 @@ public final class CertificateUtils {
|
|||
* Reads an {@link X509Certificate} PEM file from an {@link InputStream}.
|
||||
*
|
||||
* @param in
|
||||
* {@link InputStream} to read the certificate from.
|
||||
* {@link InputStream} to read the certificate from. The
|
||||
* {@link InputStream} is closed after use.
|
||||
* @return {@link X509Certificate} that was read
|
||||
*/
|
||||
public static X509Certificate readX509Certificate(InputStream in) throws IOException {
|
||||
|
@ -72,7 +73,8 @@ public final class CertificateUtils {
|
|||
* @param cert
|
||||
* {@link X509Certificate} to write
|
||||
* @param out
|
||||
* {@link OutputStream} to write the PEM file to
|
||||
* {@link OutputStream} to write the PEM file to. The {@link OutputStream}
|
||||
* is closed after use.
|
||||
*/
|
||||
public static void writeX509Certificate(X509Certificate cert, OutputStream out) throws IOException {
|
||||
writeX509Certificate(cert, new OutputStreamWriter(out, "utf-8"));
|
||||
|
@ -84,7 +86,8 @@ public final class CertificateUtils {
|
|||
* @param cert
|
||||
* {@link X509Certificate} to write
|
||||
* @param w
|
||||
* {@link Writer} to write the PEM file to
|
||||
* {@link Writer} to write the PEM file to. The {@link Writer} is closed
|
||||
* after use.
|
||||
*/
|
||||
public static void writeX509Certificate(X509Certificate cert, Writer w) throws IOException {
|
||||
try (JcaPEMWriter jw = new JcaPEMWriter(w)) {
|
||||
|
@ -92,27 +95,56 @@ public final class CertificateUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a X.509 certificate chain to a PEM file.
|
||||
*
|
||||
* @param w
|
||||
* {@link Writer} to write the certificate chain to. The {@link Writer} is
|
||||
* closed after use.
|
||||
* @param cert
|
||||
* {@link X509Certificate} to write, {@code null} to skip this certificate
|
||||
* @param chain
|
||||
* {@link X509Certificate} chain to add to the certificate. {@code null}
|
||||
* values are ignored, array may be empty.
|
||||
*/
|
||||
public static void writeX509CertificateChain(Writer w, X509Certificate cert, X509Certificate... chain)
|
||||
throws IOException {
|
||||
try (JcaPEMWriter jw = new JcaPEMWriter(w)) {
|
||||
if (cert != null) {
|
||||
jw.writeObject(cert);
|
||||
}
|
||||
if (chain != null) {
|
||||
for (X509Certificate c : chain) {
|
||||
if (c != null) {
|
||||
jw.writeObject(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an X.509 certificate chain PEM file.
|
||||
*
|
||||
* @param chain
|
||||
* {@link X509Certificate[]} to write
|
||||
* @param w
|
||||
* {@link Writer} to write the PEM file to
|
||||
* {@link Writer} to write the PEM file to. The {@link Writer} is closed
|
||||
* after use.
|
||||
* @deprecated Use
|
||||
* {@link #writeX509CertificateChain(Writer, X509Certificate, X509Certificate...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static void writeX509CertificateChain(X509Certificate[] chain, Writer w) throws IOException {
|
||||
try (JcaPEMWriter jw = new JcaPEMWriter(w)) {
|
||||
for (X509Certificate cert : chain) {
|
||||
jw.writeObject(cert);
|
||||
}
|
||||
}
|
||||
writeX509CertificateChain(w, null, chain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a CSR PEM file.
|
||||
*
|
||||
* @param in
|
||||
* {@link InputStream} to read the CSR from.
|
||||
* {@link InputStream} to read the CSR from. The {@link InputStream} is
|
||||
* closed after use.
|
||||
* @return CSR that was read
|
||||
*/
|
||||
public static PKCS10CertificationRequest readCSR(InputStream in) throws IOException {
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
|
|||
/**
|
||||
* Utility class offering convenience methods for {@link KeyPair}.
|
||||
* <p>
|
||||
* Requires {@code Bouncy Castle}.
|
||||
* Requires {@code Bouncy Castle}. This class is part of the {@code acme4j-utils} module.
|
||||
*/
|
||||
public class KeyPairUtils {
|
||||
|
||||
|
@ -83,7 +83,8 @@ public class KeyPairUtils {
|
|||
* Reads a {@link KeyPair} from a PEM file.
|
||||
*
|
||||
* @param r
|
||||
* {@link Reader} to read the PEM file from
|
||||
* {@link Reader} to read the PEM file from. The {@link Reader} is closed
|
||||
* after use.
|
||||
* @return {@link KeyPair} read
|
||||
*/
|
||||
public static KeyPair readKeyPair(Reader r) throws IOException {
|
||||
|
@ -101,7 +102,8 @@ public class KeyPairUtils {
|
|||
* @param keypair
|
||||
* {@link KeyPair} to write
|
||||
* @param w
|
||||
* {@link Writer} to write the PEM file to
|
||||
* {@link Writer} to write the PEM file to. The {@link Writer} is closed
|
||||
* after use.
|
||||
*/
|
||||
public static void writeKeyPair(KeyPair keypair, Writer w) throws IOException {
|
||||
try (JcaPEMWriter jw = new JcaPEMWriter(w)) {
|
||||
|
|
|
@ -54,6 +54,29 @@ URI locationUri = ... // location URI from cert.getLocation()
|
|||
Certificate cert = Certificate.bind(session, locationUri);
|
||||
```
|
||||
|
||||
### Saving Certificates
|
||||
|
||||
Most web servers, like _Apache_, _nginx_, but also other servers like _postfix_ or _dovecot_, need a combined certificate file that contains the leaf certificate itself, and the certificate chain up to the root certificate. `acme4j-utils` offers a method that helps to write the necessary file:
|
||||
|
||||
```java
|
||||
try (FileWriter fw = new FileWriter("cert-chain.crt")) {
|
||||
CertificateUtils.writeX509CertificateChain(fw, cert, chain);
|
||||
}
|
||||
```
|
||||
|
||||
Some older servers may need the leaf certificate and the certificate chain in different files. Use this snippet to write both files:
|
||||
|
||||
```java
|
||||
try (FileWriter fw = new FileWriter("cert.pem")) {
|
||||
CertificateUtils.writeX509Certificate(cert, fw);
|
||||
}
|
||||
try (FileWriter fw = new FileWriter("chain.pem")) {
|
||||
CertificateUtils.writeX509CertificateChain(fw, null, chain);
|
||||
}
|
||||
```
|
||||
|
||||
These utility methods should be sufficient for most use cases. If you need the certificate written in a different format, see the [source code of `CertificateUtils`](https://github.com/shred/acme4j/blob/master/acme4j-utils/src/main/java/org/shredzone/acme4j/util/CertificateUtils.java) to find out how certificates are written using _Bouncy Castle_.
|
||||
|
||||
### Multiple Domains
|
||||
|
||||
The example above generates a certificate per domain. However, you would usually prefer to use a single certificate for multiple domains (for example, the domain itself and the `www.` subdomain).
|
||||
|
|
Loading…
Reference in New Issue