mirror of https://github.com/shred/acme4j
Add method to download full cert and chain
parent
ae4ef0f2ab
commit
69fbe81e2d
|
@ -77,7 +77,10 @@ public class Certificate extends AcmeResource {
|
|||
}
|
||||
|
||||
/**
|
||||
* Downloads the certificate. The result is cached.
|
||||
* Downloads the certificate. The result is only the end-entity certificate, without
|
||||
* the issuer chain.
|
||||
* <p>
|
||||
* The result is cached.
|
||||
*
|
||||
* @return {@link X509Certificate} that was downloaded
|
||||
* @throws AcmeRetryAfterException
|
||||
|
@ -85,6 +88,7 @@ public class Certificate extends AcmeResource {
|
|||
* estimated date when it will be ready for download. You should wait for
|
||||
* the date given in {@link AcmeRetryAfterException#getRetryAfter()}
|
||||
* before trying again.
|
||||
* @see #downloadFullChain()
|
||||
*/
|
||||
public X509Certificate download() throws AcmeException {
|
||||
if (cert == null) {
|
||||
|
@ -102,7 +106,9 @@ public class Certificate extends AcmeResource {
|
|||
}
|
||||
|
||||
/**
|
||||
* Downloads the certificate chain. The result is cached.
|
||||
* Downloads the issuer chain. The result does not contain the end-entity certificate.
|
||||
* <p>
|
||||
* The result is cached.
|
||||
*
|
||||
* @return Chain of {@link X509Certificate}s
|
||||
* @throws AcmeRetryAfterException
|
||||
|
@ -144,6 +150,30 @@ public class Certificate extends AcmeResource {
|
|||
return Arrays.copyOf(chain, chain.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the certificate and the corresponding issuer chain. The issued
|
||||
* certificate is always on index 0, followed by the CA certificates, with the root CA
|
||||
* being at the last index.
|
||||
* <p>
|
||||
* The result is cached.
|
||||
*
|
||||
* @return Chain of {@link X509Certificate}s
|
||||
* @throws AcmeRetryAfterException
|
||||
* the certificate is still being created, and the server returned an
|
||||
* estimated date when it will be ready for download. You should wait for
|
||||
* the date given in {@link AcmeRetryAfterException#getRetryAfter()}
|
||||
* before trying again.
|
||||
* @since 1.1
|
||||
*/
|
||||
public X509Certificate[] downloadFullChain() throws AcmeException {
|
||||
downloadChain();
|
||||
|
||||
X509Certificate[] result = new X509Certificate[chain.length + 1];
|
||||
result[0] = cert;
|
||||
System.arraycopy(chain, 0, result, 1, chain.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes this certificate.
|
||||
*/
|
||||
|
|
|
@ -49,6 +49,7 @@ public class CertificateTest {
|
|||
@Test
|
||||
public void testDownload() throws AcmeException, IOException {
|
||||
final X509Certificate originalCert = TestUtils.createCertificate();
|
||||
final X509Certificate issuerCert = TestUtils.createIssuerCertificate();
|
||||
|
||||
TestableConnectionProvider provider = new TestableConnectionProvider() {
|
||||
private boolean isLocationUrl;
|
||||
|
@ -75,7 +76,11 @@ public class CertificateTest {
|
|||
|
||||
@Override
|
||||
public X509Certificate readCertificate() {
|
||||
return originalCert;
|
||||
if (isLocationUrl) {
|
||||
return originalCert;
|
||||
} else {
|
||||
return issuerCert;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -99,12 +104,23 @@ public class CertificateTest {
|
|||
|
||||
X509Certificate[] downloadedChain = cert.downloadChain();
|
||||
assertThat(downloadedChain.length, is(1));
|
||||
assertThat(downloadedChain[0], is(sameInstance(originalCert)));
|
||||
assertThat(downloadedChain[0], is(sameInstance(issuerCert)));
|
||||
|
||||
// Make sure the chain array is a local copy
|
||||
X509Certificate[] downloadedFullChain = cert.downloadFullChain();
|
||||
assertThat(downloadedFullChain.length, is(2));
|
||||
assertThat(downloadedFullChain[0], is(sameInstance(originalCert)));
|
||||
assertThat(downloadedFullChain[1], is(sameInstance(issuerCert)));
|
||||
|
||||
// Make sure the chain arrays are a local copy
|
||||
downloadedChain[0] = null;
|
||||
X509Certificate[] downloadedChain2 = cert.downloadChain();
|
||||
assertThat(downloadedChain2[0], is(sameInstance(originalCert)));
|
||||
assertThat(downloadedChain2[0], is(sameInstance(issuerCert)));
|
||||
|
||||
downloadedFullChain[0] = null;
|
||||
downloadedFullChain[1] = null;
|
||||
X509Certificate[] downloadedFullChain2 = cert.downloadFullChain();
|
||||
assertThat(downloadedFullChain2[0], is(sameInstance(originalCert)));
|
||||
assertThat(downloadedFullChain2[1], is(sameInstance(issuerCert)));
|
||||
|
||||
provider.close();
|
||||
}
|
||||
|
|
|
@ -241,6 +241,21 @@ public final class TestUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the issuer certificate for testing. This certificate is read from a test
|
||||
* resource and is guaranteed not to change between test runs.
|
||||
*
|
||||
* @return {@link X509Certificate} for testing
|
||||
*/
|
||||
public static X509Certificate createIssuerCertificate() throws IOException {
|
||||
try (InputStream cert = TestUtils.class.getResourceAsStream("/issuer.pem")) {
|
||||
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
|
||||
return (X509Certificate) certificateFactory.generateCertificate(cert);
|
||||
} catch (CertificateException ex) {
|
||||
throw new IOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a matcher that matches an array of int primitives. The array must contain
|
||||
* exactly all of the given values, in any order.
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
|
||||
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
|
||||
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
|
||||
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
|
||||
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
|
||||
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
|
||||
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
|
||||
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
|
||||
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
|
||||
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
|
||||
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
|
||||
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
|
||||
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
|
||||
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
|
||||
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
|
||||
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
|
||||
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
|
||||
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
|
||||
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
|
||||
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
|
||||
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
|
||||
-----END CERTIFICATE-----
|
|
@ -41,8 +41,13 @@ The `Certificate` object offers methods to download the certificate and the cert
|
|||
```java
|
||||
X509Certificate cert = cert.download();
|
||||
X509Certificate[] chain = cert.downloadChain();
|
||||
X509Certificate[] fullChain = cert.downloadFullChain();
|
||||
```
|
||||
|
||||
* `cert` is the issued certificate.
|
||||
* `chain` is the issuer chain that corresponds to `cert`.
|
||||
* `fullChain` is the issued certificate (at index 0), followed by the issuer chain.
|
||||
|
||||
Congratulations! You have just created your first certificate via _acme4j_.
|
||||
|
||||
`download()` may throw an `AcmeRetryAfterException`, giving an estimated time in `getRetryAfter()` for when the certificate is ready for download. You should then wait until that moment has been reached, before trying again.
|
||||
|
@ -64,6 +69,14 @@ try (FileWriter fw = new FileWriter("cert-chain.crt")) {
|
|||
}
|
||||
```
|
||||
|
||||
Alternatively:
|
||||
|
||||
```java
|
||||
try (FileWriter fw = new FileWriter("cert-chain.crt")) {
|
||||
CertificateUtils.writeX509CertificateChain(fw, null, fullChain);
|
||||
}
|
||||
```
|
||||
|
||||
Some older servers may need the leaf certificate and the certificate chain in different files. Use this snippet to write both files:
|
||||
|
||||
```java
|
||||
|
|
Loading…
Reference in New Issue