From e589b16d989f63b614410c074f3ddcd1fc45c6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20K=C3=B6rber?= Date: Thu, 22 Aug 2024 20:16:35 +0200 Subject: [PATCH] Allow custom pebble.minica.pem files Also changes from a Java proprietary truststore file to the official Pebble PEM file. --- .../provider/pebble/PebbleHttpConnector.java | 43 ++++++++++++++++-- .../acme4j/provider/pebble/pebble.minica.pem | 19 ++++++++ .../acme4j/provider/pebble/pebble.truststore | Bin 844 -> 0 bytes 3 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 acme4j-client/src/main/resources/org/shredzone/acme4j/provider/pebble/pebble.minica.pem delete mode 100644 acme4j-client/src/main/resources/org/shredzone/acme4j/provider/pebble/pebble.truststore diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/PebbleHttpConnector.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/PebbleHttpConnector.java index 640bc486..2b9c3af9 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/PebbleHttpConnector.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/PebbleHttpConnector.java @@ -20,7 +20,9 @@ import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import javax.net.ssl.SSLContext; @@ -28,12 +30,15 @@ import javax.net.ssl.TrustManagerFactory; import org.shredzone.acme4j.connector.HttpConnector; import org.shredzone.acme4j.connector.NetworkSettings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * {@link HttpConnector} to be used for Pebble. Pebble uses a static, self-signed SSL * certificate. */ public class PebbleHttpConnector extends HttpConnector { + private static final Logger LOG = LoggerFactory.getLogger(PebbleHttpConnector.class); private static final AtomicReference SSL_CONTEXT_REF = new AtomicReference<>(); public PebbleHttpConnector(NetworkSettings settings) { @@ -53,9 +58,11 @@ public class PebbleHttpConnector extends HttpConnector { */ protected SSLContext createSSLContext() { if (SSL_CONTEXT_REF.get() == null) { - try (var in = getClass().getResourceAsStream("/org/shredzone/acme4j/provider/pebble/pebble.truststore")) { - var keystore = KeyStore.getInstance(KeyStore.getDefaultType()); - keystore.load(in, "acme4j".toCharArray()); + try { + var keystore = readPemFile("/pebble.minica.pem") + .or(() -> readPemFile("/META-INF/pebble.minica.pem")) + .or(() -> readPemFile("/org/shredzone/acme4j/provider/pebble/pebble.minica.pem")) + .orElseThrow(() -> new RuntimeException("Could not find a Pebble root certificate")); var tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keystore); @@ -63,12 +70,38 @@ public class PebbleHttpConnector extends HttpConnector { var sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); SSL_CONTEXT_REF.set(sslContext); - } catch (IOException | KeyStoreException | CertificateException - | NoSuchAlgorithmException | KeyManagementException ex) { + } catch (KeyStoreException | NoSuchAlgorithmException | KeyManagementException ex) { throw new RuntimeException("Could not create truststore", ex); } } return Objects.requireNonNull(SSL_CONTEXT_REF.get()); } + /** + * Reads a PEM file from a resource, and returns a {@link KeyStore} that uses this + * certificate as root CA. + * + * @param resource + * Resource name + * @return A {@link KeyStore} if the resource could be read successfully, otherwise + * empty. + */ + private Optional readPemFile(String resource) { + try (var in = getClass().getResourceAsStream(resource)) { + if (in == null) { + return Optional.empty(); + } + var cf = CertificateFactory.getInstance("X.509"); + var cert = cf.generateCertificate(in); + var keystore = KeyStore.getInstance(KeyStore.getDefaultType()); + keystore.load(null, "acme4j".toCharArray()); + keystore.setCertificateEntry("pebble", cert); + return Optional.of(keystore); + } catch (IOException | KeyStoreException | CertificateException + | NoSuchAlgorithmException ex) { + LOG.error("Failed to read PEM from resource '{}'", resource, ex); + return Optional.empty(); + } + } + } diff --git a/acme4j-client/src/main/resources/org/shredzone/acme4j/provider/pebble/pebble.minica.pem b/acme4j-client/src/main/resources/org/shredzone/acme4j/provider/pebble/pebble.minica.pem new file mode 100644 index 00000000..a69a4c41 --- /dev/null +++ b/acme4j-client/src/main/resources/org/shredzone/acme4j/provider/pebble/pebble.minica.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCTCCAfGgAwIBAgIIJOLbes8sTr4wDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE +AxMVbWluaWNhIHJvb3QgY2EgMjRlMmRiMCAXDTE3MTIwNjE5NDIxMFoYDzIxMTcx +MjA2MTk0MjEwWjAgMR4wHAYDVQQDExVtaW5pY2Egcm9vdCBjYSAyNGUyZGIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5WgZNoVJandj43kkLyU50vzCZ +alozvdRo3OFiKoDtmqKPNWRNO2hC9AUNxTDJco51Yc42u/WV3fPbbhSznTiOOVtn +Ajm6iq4I5nZYltGGZetGDOQWr78y2gWY+SG078MuOO2hyDIiKtVc3xiXYA+8Hluu +9F8KbqSS1h55yxZ9b87eKR+B0zu2ahzBCIHKmKWgc6N13l7aDxxY3D6uq8gtJRU0 +toumyLbdzGcupVvjbjDP11nl07RESDWBLG1/g3ktJvqIa4BWgU2HMh4rND6y8OD3 +Hy3H8MY6CElL+MOCbFJjWqhtOxeFyZZV9q3kYnk9CAuQJKMEGuN4GU6tzhW1AgMB +AAGjRTBDMA4GA1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB +BQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEAF85v +d40HK1ouDAtWeO1PbnWfGEmC5Xa478s9ddOd9Clvp2McYzNlAFfM7kdcj6xeiNhF +WPIfaGAi/QdURSL/6C1KsVDqlFBlTs9zYfh2g0UXGvJtj1maeih7zxFLvet+fqll +xseM4P9EVJaQxwuK/F78YBt0tCNfivC6JNZMgxKF59h0FBpH70ytUSHXdz7FKwix +Mfn3qEb9BXSk0Q3prNV5sOV3vgjEtB4THfDxSz9z3+DepVnW3vbbqwEbkXdk3j82 +2muVldgOUgTwK8eT+XdofVdntzU/kzygSAtAQwLJfn51fS1GvEcYGBc1bDryIqmF +p9BI7gVKtWSZYegicA== +-----END CERTIFICATE----- diff --git a/acme4j-client/src/main/resources/org/shredzone/acme4j/provider/pebble/pebble.truststore b/acme4j-client/src/main/resources/org/shredzone/acme4j/provider/pebble/pebble.truststore deleted file mode 100644 index 103478a23527739831e4f53c03ee1027e9180c66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 844 zcmezO_TO6u1_mY|W(3o01*u6%IjKNy!u7e_x(uuldZq@J3=GV?22ISI22G3~7cet1 zGBI(eJi1+VUdL~r0WTY;R+~rLcV0$DZdL{Z1w%Ol88+rn7G`15+|0bp>pdij`Xl`g^U}k7(Vq|C#CBbiGh$29Q8BL5z$QCoQGB7tW@-qP4$Hmmd z$jGoWip_UnP}JNTKkj*QpY$u)Z!j|}%6RXUj5`mLv>M*dTGVfv;%lAZ^o5o8sKLpi zzS6{VX1l*mz5Drgp2+687JZh{=}eZpy4G<#D~p(Ru`Ttr8_yH5_4|!(vCjCZxaIv} zJ&U&sPZ%j_U5&XfF+G8Qk6iS+FY#P?OD0{Dt2`}Mn}6<}rhMaN>up&w2RRx~%~-mi zcyZ~yxLf=(5qIp?tv;cvDr&N=d)bL?ch98jEscJhXK?;{K7%&IWwIxRB*%Wc<&JvoW%= zvNJQnSxg2(AZcNcat;GFAjQPUfE>`k7zPG3BZK(4{PJFQ?I=AS?y!ot{&}VIB|Mv+ zmhE_d+P3ua+%KB>%adi2jZ+!I&%ASw>0cAqalUX|4@kd#+tGLvs-2TW}RT|aj1-<{9