From 47f58d2388d450265ddf8738f788ed1553a27c36 Mon Sep 17 00:00:00 2001 From: FalsePattern Date: Tue, 15 Apr 2025 18:36:18 +0200 Subject: [PATCH] port over LetsEncrypt root certificate fix from ArchaicFix --- .../lib/internal/asm/CoreLoadingPlugin.java | 2 + .../lib/internal/asm/RFBLoadingPlugin.java | 2 + .../lib/internal/config/EarlyConfig.java | 5 ++ .../impl/dependencies/LetsEncryptHelper.java | 84 +++++++++++++++++++ .../resources/letsencrypt/isrg-root-x2.pem | 14 ++++ src/main/resources/letsencrypt/isrgrootx1.pem | 31 +++++++ 6 files changed, 138 insertions(+) create mode 100644 src/main/java/com/falsepattern/lib/internal/impl/dependencies/LetsEncryptHelper.java create mode 100644 src/main/resources/letsencrypt/isrg-root-x2.pem create mode 100644 src/main/resources/letsencrypt/isrgrootx1.pem diff --git a/src/main/java/com/falsepattern/lib/internal/asm/CoreLoadingPlugin.java b/src/main/java/com/falsepattern/lib/internal/asm/CoreLoadingPlugin.java index 99be01f..916e0bd 100644 --- a/src/main/java/com/falsepattern/lib/internal/asm/CoreLoadingPlugin.java +++ b/src/main/java/com/falsepattern/lib/internal/asm/CoreLoadingPlugin.java @@ -25,6 +25,7 @@ package com.falsepattern.lib.internal.asm; import com.falsepattern.lib.internal.FPLog; import com.falsepattern.lib.internal.Tags; import com.falsepattern.lib.internal.impl.dependencies.DependencyLoaderImpl; +import com.falsepattern.lib.internal.impl.dependencies.LetsEncryptHelper; import com.falsepattern.lib.internal.logging.CrashImprover; import com.falsepattern.lib.internal.logging.NotEnoughVerbosity; import com.falsepattern.lib.mapping.MappingManager; @@ -62,6 +63,7 @@ public class CoreLoadingPlugin implements IFMLLoadingPlugin { private static boolean obfuscated; static { + LetsEncryptHelper.replaceSSLContext(); FPLog.LOG.info("Removing skill issues..."); try { Class.forName("thermos.Thermos"); diff --git a/src/main/java/com/falsepattern/lib/internal/asm/RFBLoadingPlugin.java b/src/main/java/com/falsepattern/lib/internal/asm/RFBLoadingPlugin.java index 4c66254..0f4db86 100644 --- a/src/main/java/com/falsepattern/lib/internal/asm/RFBLoadingPlugin.java +++ b/src/main/java/com/falsepattern/lib/internal/asm/RFBLoadingPlugin.java @@ -25,10 +25,12 @@ package com.falsepattern.lib.internal.asm; import com.falsepattern.lib.internal.core.LowLevelCallMultiplexer; import com.falsepattern.lib.internal.impl.dependencies.DependencyLoaderImpl; +import com.falsepattern.lib.internal.impl.dependencies.LetsEncryptHelper; import com.gtnewhorizons.retrofuturabootstrap.api.RfbPlugin; public class RFBLoadingPlugin implements RfbPlugin { static { + LetsEncryptHelper.replaceSSLContext(); LowLevelCallMultiplexer.rfbDetected(); DependencyLoaderImpl.executeDependencyLoading(false); } diff --git a/src/main/java/com/falsepattern/lib/internal/config/EarlyConfig.java b/src/main/java/com/falsepattern/lib/internal/config/EarlyConfig.java index 8fdb4d3..0c21a6f 100644 --- a/src/main/java/com/falsepattern/lib/internal/config/EarlyConfig.java +++ b/src/main/java/com/falsepattern/lib/internal/config/EarlyConfig.java @@ -50,6 +50,10 @@ public class EarlyConfig { @StableAPI.Expose(since = "__INTERNAL__") private boolean enableLibraryDownloads; + @Expose + @StableAPI.Expose(since = "__INTERNAL__") + private boolean enableLetsEncryptRoot; + private static volatile EarlyConfig instance = null; private static final Logger LOG = LogManager.getLogger(Tags.MODNAME + " Early Config"); @@ -83,6 +87,7 @@ public class EarlyConfig { if (config == null) { config = new EarlyConfig(); config.enableLibraryDownloads(true); + config.enableLetsEncryptRoot(true); try { Files.write(configFile, gson.toJson(config).getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { diff --git a/src/main/java/com/falsepattern/lib/internal/impl/dependencies/LetsEncryptHelper.java b/src/main/java/com/falsepattern/lib/internal/impl/dependencies/LetsEncryptHelper.java new file mode 100644 index 0000000..087a5d2 --- /dev/null +++ b/src/main/java/com/falsepattern/lib/internal/impl/dependencies/LetsEncryptHelper.java @@ -0,0 +1,84 @@ +/* + * This file is part of FalsePatternLib. + * + * Copyright (C) 2022-2024 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * FalsePatternLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FalsePatternLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FalsePatternLib. If not, see . + */ + +package com.falsepattern.lib.internal.impl.dependencies; + +import com.falsepattern.lib.internal.FPLog; +import com.falsepattern.lib.internal.config.EarlyConfig; +import lombok.val; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.cert.CertificateFactory; + +/** + * Add Let's Encrypt root certificates to the default SSLContext. + * CurseForge launcher uses the vanilla JDK for 1.7.10, which is version 8u51. + * This version does not include these certificates, support for ISRG Root X1 was added in 8u141. + * Based on LetsEncryptCraft by Cloudhunter (MIT) + */ +public class LetsEncryptHelper { + private static volatile boolean patched = false; + private LetsEncryptHelper() {} + @SuppressWarnings("java:S6437") + public static void replaceSSLContext() { + if (!EarlyConfig.getInstance().enableLetsEncryptRoot()) { + return; + } + if (patched) { + return; + } + patched = true; + + try (val x1 = LetsEncryptHelper.class.getResourceAsStream("/letsencrypt/isrgrootx1.pem"); + val x2 = LetsEncryptHelper.class.getResourceAsStream("/letsencrypt/isrg-root-x2.pem")) { + val merged = KeyStore.getInstance(KeyStore.getDefaultType()); + val cacerts = Paths.get(System.getProperty("java.home"),"lib", "security", "cacerts"); + merged.load(Files.newInputStream(cacerts), "changeit".toCharArray()); + + val cf = CertificateFactory.getInstance("X.509"); + + val cx1 = cf.generateCertificate(x1); + merged.setCertificateEntry("archaicfix-isrgx1", cx1); + + val cx2 = cf.generateCertificate(x2); + merged.setCertificateEntry("archaicfix-isrgx2", cx2); + + val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(merged); + val sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, tmf.getTrustManagers(), null); + SSLContext.setDefault(sslContext); + FPLog.LOG.info("[LetsEncryptHelper] Added certificates to trust store."); + } catch (IOException e) { + FPLog.LOG.error("[LetsEncryptHelper] Failed to load certificates from classpath.", e); + } catch (GeneralSecurityException e) { + FPLog.LOG.error("[LetsEncryptHelper] Failed to load default keystore.", e); + } + } +} \ No newline at end of file diff --git a/src/main/resources/letsencrypt/isrg-root-x2.pem b/src/main/resources/letsencrypt/isrg-root-x2.pem new file mode 100644 index 0000000..7d903ed --- /dev/null +++ b/src/main/resources/letsencrypt/isrg-root-x2.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- diff --git a/src/main/resources/letsencrypt/isrgrootx1.pem b/src/main/resources/letsencrypt/isrgrootx1.pem new file mode 100644 index 0000000..b85c803 --- /dev/null +++ b/src/main/resources/letsencrypt/isrgrootx1.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE-----