From d9ce3af5aa8cef63d33f3c41b26498129ca4a6a9 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Fri, 20 Aug 2021 23:10:13 +0200 Subject: [PATCH] Fixed certificate handling --- gradlew | 0 hal-core/src/se/hal/HalContext.java | 7 +-- hal-core/src/se/hal/HalServer.java | 36 +++++++++++--- .../src/se/hal/util/HalAcmeDataStore.java | 48 ++++++++++++++++--- .../daemon/PCDataSynchronizationDaemon.java | 18 +++---- run.sh | 0 6 files changed, 84 insertions(+), 25 deletions(-) mode change 100755 => 100644 gradlew mode change 100755 => 100644 run.sh diff --git a/gradlew b/gradlew old mode 100755 new mode 100644 diff --git a/hal-core/src/se/hal/HalContext.java b/hal-core/src/se/hal/HalContext.java index 6dac5dbd..e49412da 100644 --- a/hal-core/src/se/hal/HalContext.java +++ b/hal-core/src/se/hal/HalContext.java @@ -24,6 +24,7 @@ public class HalContext { public static final String CONFIG_HTTP_PORT = "hal_core.http_port"; public static final String CONFIG_HTTP_EXTERNAL_PORT = "hal_core.http_external_port"; public static final String CONFIG_HTTP_EXTERNAL_DOMAIN = "hal_core.http_external_domain"; + public static final String CONFIG_HTTP_EXTERNAL_ACME_TYPE = "hal_core.http_external_acme_type"; public static final String CONFIG_MAP_BACKGROUND_IMAGE = "hal_core.map_bgimage"; public static final String RESOURCE_ROOT; @@ -104,10 +105,10 @@ public class HalContext { registerProperty(key); String value = null; - if (dbConf != null) - value = dbConf.getProperty(key); if (fileConf != null) value = fileConf.getProperty(key); + if (value == null && dbConf != null) + value = dbConf.getProperty(key); return value != null ? value : defaultValue; } @@ -116,7 +117,7 @@ public class HalContext { } public static int getIntegerProperty(String key, int defaultValue){ String value = getStringProperty(key); - return value != null ? getIntegerProperty(key) : defaultValue; + return value != null ? Integer.parseInt(getStringProperty(key)) : defaultValue; } public static boolean getBooleanProperty(String key) { diff --git a/hal-core/src/se/hal/HalServer.java b/hal-core/src/se/hal/HalServer.java index ef21bf88..e45ffe4e 100644 --- a/hal-core/src/se/hal/HalServer.java +++ b/hal-core/src/se/hal/HalServer.java @@ -8,7 +8,10 @@ import se.hal.util.HalAcmeDataStore; import zutil.db.DBConnection; import zutil.io.file.FileUtil; import zutil.log.LogUtil; +import zutil.net.acme.AcmeChallengeFactory; import zutil.net.acme.AcmeClient; +import zutil.net.acme.AcmeHttpChallengeFactory; +import zutil.net.acme.AcmeManualDnsChallengeFactory; import zutil.net.http.HttpPage; import zutil.net.http.HttpServer; import zutil.net.http.page.HttpFilePage; @@ -79,16 +82,35 @@ public class HalServer { if (HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_PORT) && HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_DOMAIN)) { - // Start a non secure server to retrieve handle the ACME protocol challenge - HttpServer tmpHttpExternal = new HttpServer(HalContext.getIntegerProperty(CONFIG_HTTP_EXTERNAL_PORT)); - tmpHttpExternal.start(); + AcmeClient acme; + HttpServer tmpHttpServer = null; - AcmeClient acme = new AcmeClient(new HalAcmeDataStore()); - Certificate certificate = acme.fetchCertificate(tmpHttpExternal, HalContext.getStringProperty(CONFIG_HTTP_EXTERNAL_DOMAIN)); + if ("dns".equals(HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE, ""))) { + acme = new AcmeClient(new HalAcmeDataStore(), new AcmeManualDnsChallengeFactory(), AcmeClient.ACME_SERVER_LETSENCRYPT_STAGING); + } else if ("http".equals(HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE, "http"))) { + tmpHttpServer = new HttpServer(80); + tmpHttpServer.start(); - tmpHttpExternal.close(); - httpExternal = new HttpServer(HalContext.getIntegerProperty(CONFIG_HTTP_EXTERNAL_PORT)); + acme = new AcmeClient(new HalAcmeDataStore(), new AcmeHttpChallengeFactory(tmpHttpServer), AcmeClient.ACME_SERVER_LETSENCRYPT_STAGING); + } else { + throw new IllegalArgumentException("Unknown config value for " + HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE + ": " + + HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE)); + } + + acme.addDomain(HalContext.getStringProperty(CONFIG_HTTP_EXTERNAL_DOMAIN)); + acme.prepareRequest(); + Certificate certificate = acme.requestCertificate(); + + httpExternal = new HttpServer(HalContext.getIntegerProperty(CONFIG_HTTP_EXTERNAL_PORT), certificate); httpExternal.start(); + + // Cleanup + + if ("http".equals(HalContext.getStringProperty(HalContext.CONFIG_HTTP_EXTERNAL_ACME_TYPE, "http"))) { + tmpHttpServer.close(); + } + + logger.info("External https server up and running at: https://" + HalContext.getStringProperty(CONFIG_HTTP_EXTERNAL_DOMAIN) + ":" + HalContext.containsProperty(CONFIG_HTTP_EXTERNAL_PORT)); } else { logger.warning("Missing '" + CONFIG_HTTP_EXTERNAL_PORT + "' and '" + CONFIG_HTTP_EXTERNAL_DOMAIN + "' configuration, will not setup external http server."); return; diff --git a/hal-core/src/se/hal/util/HalAcmeDataStore.java b/hal-core/src/se/hal/util/HalAcmeDataStore.java index a686d2b9..461448e7 100644 --- a/hal-core/src/se/hal/util/HalAcmeDataStore.java +++ b/hal-core/src/se/hal/util/HalAcmeDataStore.java @@ -1,30 +1,66 @@ package se.hal.util; +import org.shredzone.acme4j.util.KeyPairUtils; +import se.hal.HalContext; +import zutil.log.LogUtil; import zutil.net.acme.AcmeDataStore; +import zutil.parser.Base64Decoder; +import zutil.parser.Base64Encoder; +import java.io.*; import java.security.KeyPair; +import java.util.logging.Level; +import java.util.logging.Logger; public class HalAcmeDataStore implements AcmeDataStore { + private static final Logger logger = LogUtil.getLogger(); + private static final String CONFIG_HTTP_EXTERNAL_USER_KEY = "hal_core.http_external_user_key"; private static final String CONFIG_HTTP_EXTERNAL_DOMAIN_KEY = "hal_core.http_external_domain_key"; @Override public KeyPair loadUserKeyPair() { - return null; - } - - @Override - public void storeUserKeyPair(KeyPair keyPair) { - + return loadKeyPair(CONFIG_HTTP_EXTERNAL_USER_KEY); } @Override public KeyPair loadDomainKeyPair() { + return loadKeyPair(CONFIG_HTTP_EXTERNAL_DOMAIN_KEY); + } + + private KeyPair loadKeyPair(String configName) { + if (HalContext.containsProperty(configName)) { + try { + byte[] data = Base64Decoder.decodeToByte( + HalContext.getStringProperty(configName)); + return KeyPairUtils.readKeyPair(new InputStreamReader(new ByteArrayInputStream(data))); + } catch (IOException e) { + logger.log(Level.SEVERE, "Was unable to load KeyPair from DB.", e); + } + } return null; } + + @Override + public void storeUserKeyPair(KeyPair keyPair) { + storeKeyPair(keyPair, CONFIG_HTTP_EXTERNAL_USER_KEY); + } + @Override public void storeDomainKeyPair(KeyPair keyPair) { + storeKeyPair(keyPair, CONFIG_HTTP_EXTERNAL_DOMAIN_KEY); + } + private void storeKeyPair(KeyPair keyPair, String configName) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + OutputStreamWriter writer = new OutputStreamWriter(out); + KeyPairUtils.writeKeyPair(keyPair, writer); + + HalContext.setProperty(configName, Base64Encoder.encode(out.toByteArray())); + } catch (IOException e) { + logger.log(Level.SEVERE, "Was unable to store KeyPair to DB.", e); + } } } diff --git a/plugins/hal-powerchallenge/src/se/hal/plugin/powerchallenge/daemon/PCDataSynchronizationDaemon.java b/plugins/hal-powerchallenge/src/se/hal/plugin/powerchallenge/daemon/PCDataSynchronizationDaemon.java index 4a69d942..af065e80 100644 --- a/plugins/hal-powerchallenge/src/se/hal/plugin/powerchallenge/daemon/PCDataSynchronizationDaemon.java +++ b/plugins/hal-powerchallenge/src/se/hal/plugin/powerchallenge/daemon/PCDataSynchronizationDaemon.java @@ -58,7 +58,7 @@ public class PCDataSynchronizationDaemon extends ThreadedTCPNetworkServer implem public static final int PROTOCOL_VERSION = 5; // Increment for protocol changes - public PCDataSynchronizationDaemon() { + public PCDataSynchronizationDaemon() throws IOException { super(HalContext.getIntegerProperty(PROPERTY_SYNC_PORT)); } @@ -81,20 +81,20 @@ public class PCDataSynchronizationDaemon extends ThreadedTCPNetworkServer implem private class DataSynchronizationDaemonThread implements ThreadedTCPNetworkServerThread{ - private Socket s; + private Socket socket; private ObjectOutputStream out; private ObjectInputStream in; - public DataSynchronizationDaemonThread(Socket s) throws IOException{ - this.s = s; - this.out = new ObjectOutputStream(s.getOutputStream()); - this.in = new ObjectInputStream(s.getInputStream()); + public DataSynchronizationDaemonThread(Socket socket) throws IOException{ + this.socket = socket; + this.out = new ObjectOutputStream(socket.getOutputStream()); + this.in = new ObjectInputStream(socket.getInputStream()); } public void run(){ - logger.fine("User connected: "+ s.getInetAddress().getHostName()); + logger.fine("User connected: "+ socket.getInetAddress().getHostName()); DBConnection db = HalContext.getDB(); try { @@ -166,12 +166,12 @@ public class PCDataSynchronizationDaemon extends ThreadedTCPNetworkServer implem } out.close(); in.close(); - s.close(); + socket.close(); } catch (Exception e) { logger.log(Level.SEVERE, null, e); } - logger.fine("User disconnected: "+ s.getInetAddress().getHostName()); + logger.fine("User disconnected: "+ socket.getInetAddress().getHostName()); } } diff --git a/run.sh b/run.sh old mode 100755 new mode 100644