From d9c4446ccc0931ba1fdbbc5156c60740b97dea6e Mon Sep 17 00:00:00 2001 From: cpw Date: Sun, 10 Feb 2019 23:41:40 -0500 Subject: [PATCH] Enable https to Let's Encrypt endpoints by using an SSL factory with the two extra Let's Encrypt root certs installed into an auxiliary keystore. The keystore was generated using standard commands, documented in the FixSSL class. The Let's Encrypt certificates are not provided by default in Java 8 prior to update 101. Signed-off-by: cpw --- .../fml/loading/FMLCommonLaunchHandler.java | 2 +- .../minecraftforge/fml/loading/FMLLoader.java | 2 + .../minecraftforge/fml/loading/FixSSL.java | 91 ++++++++++++++++++ src/fmllauncher/resources/lekeystore.jks | Bin 0 -> 2346 bytes .../minecraftforge/fml/VersionChecker.java | 2 +- 5 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 src/fmllauncher/java/net/minecraftforge/fml/loading/FixSSL.java create mode 100644 src/fmllauncher/resources/lekeystore.jks diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLCommonLaunchHandler.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLCommonLaunchHandler.java index 5327c619cf..0c3d1a45c6 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLCommonLaunchHandler.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLCommonLaunchHandler.java @@ -49,7 +49,7 @@ public abstract class FMLCommonLaunchHandler // standard libs "joptsimple.", "org.lwjgl.", "com.mojang.guava.", "com.google.", "org.apache.commons.", "io.netty.", "org.apache.logging.log4j.", "org.apache.http.", "org.apache.maven.", "org.objectweb.asm.", - "paulscode.sound.", "com.ibm.icu.", "sun.", "gnu.trove.", "com.electronwill.nightconfig.", + "paulscode.sound.", "com.ibm.icu.", "sun.", "javax.", "gnu.trove.", "com.electronwill.nightconfig.", "net.minecraftforge.fml.loading.", "net.minecraftforge.fml.language.", "net.minecraftforge.eventbus.", "net.minecraftforge.api.", "com.mojang.util.QueueLogAppender" ); diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLLoader.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLLoader.java index 4197d3db2b..7c4f216ee5 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLLoader.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLLoader.java @@ -113,6 +113,8 @@ public class FMLLoader coreModProvider = coreModProviders.get(0); final Package coremodPackage = coreModProvider.getClass().getPackage(); LOGGER.debug(CORE,"FML found CoreMod version : {}", coremodPackage.getImplementationVersion()); + + FixSSL.fixup(); } static void setupLaunchHandler(final IEnvironment environment, final Map arguments) diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/FixSSL.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/FixSSL.java new file mode 100644 index 0000000000..6739f18e53 --- /dev/null +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/FixSSL.java @@ -0,0 +1,91 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.fml.loading; + +import org.apache.logging.log4j.LogManager; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; + +import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.rethrowBiConsumer; +import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.rethrowFunction; +import static net.minecraftforge.fml.loading.LogMarkers.CORE; + + +/** + * This class fixes older Java SSL setups which don't contain the correct root certificates to trust Let's Encrypt + * https endpoints. + * + * It uses a secondary JKS keystore: lekeystore.jks, which contains the two root certificate keys as documented here: + * https://letsencrypt.org/certificates/ + * + * To create the keystore, the following commands were run: + *
+ *     keytool -import -alias letsencryptisrgx1 -file isrgrootx1.pem -keystore lekeystore.jks -storetype jks -storepass supersecretpassword -v
+ *     keytool -import -alias identrustx3 -file identrustx3.pem -keystore lekeystore.jks -storetype jks -storepass supersecretpassword -v
+ * 
+ * + * The PEM files were obtained from the above URL. + */ +class FixSSL { + static void fixup() { + try { + final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + Path ksPath = Paths.get(System.getProperty("java.home"),"lib", "security", "cacerts"); + keyStore.load(Files.newInputStream(ksPath), "changeit".toCharArray()); + final Map jdkTrustStore = Collections.list(keyStore.aliases()).stream().collect(Collectors.toMap(a -> a, rethrowFunction(keyStore::getCertificate))); + + final KeyStore leKS = KeyStore.getInstance(KeyStore.getDefaultType()); + final InputStream leKSFile = FixSSL.class.getResourceAsStream("/lekeystore.jks"); + leKS.load(leKSFile, "supersecretpassword".toCharArray()); + final Map leTrustStore = Collections.list(leKS.aliases()).stream().collect(Collectors.toMap(a -> a, rethrowFunction(leKS::getCertificate))); + + final KeyStore mergedTrustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + mergedTrustStore.load(null, new char[0]); + jdkTrustStore.forEach(rethrowBiConsumer(mergedTrustStore::setCertificateEntry)); + leTrustStore.forEach(rethrowBiConsumer(mergedTrustStore::setCertificateEntry)); + + final TrustManagerFactory instance = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + instance.init(mergedTrustStore); + final SSLContext tls = SSLContext.getInstance("TLS"); + tls.init(null, instance.getTrustManagers(), null); + HttpsURLConnection.setDefaultSSLSocketFactory(tls.getSocketFactory()); + LogManager.getLogger().info(CORE, "Added Lets Encrypt root certificates as additional trust"); + } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | KeyManagementException e) { + LogManager.getLogger().fatal(CORE,"Failed to load lets encrypt certificate. Expect problems", e); + } + + } +} diff --git a/src/fmllauncher/resources/lekeystore.jks b/src/fmllauncher/resources/lekeystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..b8a56b6a00c3fef15e795bbdf8c515a0c917cfb0 GIT binary patch literal 2346 zcmb`Hc{J4f8^>oc#=Z>(g&{F0ea8@kEO9f8Y@-;oh)I?PvskVrjhc+zEy6^ie(7f^ z`%;K2OI*a|+SlwIdAgC?Cgjxekh;}X%0){}uES^4#9?Vy(V*@yr z)~}|1fG{t=1`E&H5(a}|Fc4sZQ2~^Bp=Wpm5C<%LynW~%{wSi4H^qa_ppsEe+%YKg z04)p>km7bh5h4~uCzNAAz<${b<$?tikiq}};IM!;2BVF^xgv$NFH~{k3CbN#p;KRl`xfd90_?rHD~NC>!S=zDRo8nzD4g&rPiUQN z>@W*lm8K4;uIit`nfLB|m2o#+zq>M!#YvQ}8#!FtIyBiN1u-Zbp{yHgZMgH@Ga8KX zc`L?|)u>W;o}D|vx&Hxj4gv*(!1*TuQ$Te8hvX4p@E#8gfbL&_2)7{0E%5Ab11})Y z)gnC7Jd!PsOCN?G3HmZRO-NzvwMbpO$rk(8<^9#zcNq-Impj5ig4~}dyhC5sGiZ!y zGa>xQpPPm{H#QdKEI*I#Nc zWB*HX>z;WmO|$IO?8D%kv^f`bBJq#C%_5YW!~}v=hk{OA)2c!OO3z z(6~k^^1=4akaS;x#1O%uR6(93_^5i7z`JawuCCZ0)QS6(=`=FMlNuIC_n}d}Lot7F z7g7`Z7k97#fC=;4XOH+Ncj6$XSkJRQ(^-;*=hSmgW<2OycLn#sv%?4i{9L4X5s))P zj5?sk6#@v96@^ZwQpj`^k?hH!`q0Brj$|6ygX(z&Wl0TS1Y)EB1h*B65V9gVTK>tR z3x*3KMi)2^=wL8_4px63MC`Zn|38ok`8SvlE|`#gFd<-2@uCXtv!vc9PL8HC`rxgG zvFb_vlmv>=ymM~o7Na?Dcf*&m39>_vPF!L6TimWH_53O+;n%3xw~XN^MZLiq)!{eB z!zRmX_9WJovItFatRNrj%a{F=ql^L@i`A8RKfQf9A6+s-NUqL|x&yu6Z+SN&6Mu-f zs9$0y5D=sF#>zP%nqD<>tXDrV92%%}fbkJ9`jT8SKH^!pB5l{4Bu4AJ^r z7H&OdBXL+LFcGSrJ55wsMGU`_Z4@iFPB3BTdpJxK-Gblw>>0GGH51^LaebQYt`p`T z{N6C-QrP_H!>nVfuX@F%MJ9&DlBBn*w+gn}<{*KHrjX|@eB5-h;fauWVK)r;b?lCmdzb~VyfZr>GVyRcxT|_#6CHoq6ko}6+ zOx>7dJg&N-(jorXHQ&Zm@zjIN%Etx{6qaF5B=xZbER?in><}s?2u)7xJq9Z?4!1r? zpur?|T9>En5fSFM>E*BK3rUJ#zFy#Gx1i${@VX`daK~3O4Kw}|c`+_8U!B=iS0BT3 zATI`L_FxdUexSMPLqP<~@Kga_BX%q}E4We7_t6R2jyGr>S9753z3|$=n%n)IOaF|af92HQxfE7Gnh&pq<*El zQ42Of+hu(hi*W^l%SffOH`nb&NGsh_q@}tJsrRhxlI9g>BC(HEq8ewC+{ynxnqv^L>;yEA?RO;abO$ z3y-$MKiORUq05Lmx!CM7?=M6`#0d7)TV|ShIF#Ub?TK1ut zhN%HG55foo%^CmRKe-hy(|T>fGRXv;!^7M2$Vn%pewEExLYhyyjb7MIQgF`u$uv9a flJdxej9T;Yt7T5JE!}rzciNRQUo+I&u+-lHjD^W* literal 0 HcmV?d00001 diff --git a/src/main/java/net/minecraftforge/fml/VersionChecker.java b/src/main/java/net/minecraftforge/fml/VersionChecker.java index 7b66b75890..96f351a87f 100644 --- a/src/main/java/net/minecraftforge/fml/VersionChecker.java +++ b/src/main/java/net/minecraftforge/fml/VersionChecker.java @@ -271,7 +271,7 @@ public class VersionChecker } catch (Exception e) { - LOGGER.debug("Failed to process update information", e); + LOGGER.warn("Failed to process update information", e); status = FAILED; } results.put(mod, new CheckResult(status, target, changes, display_url));