2013-03-08 00:25:48 +00:00
/ *
2016-06-23 03:49:47 +00:00
* Minecraft Forge
2018-07-01 21:17:28 +00:00
* Copyright ( c ) 2016 - 2018 .
2013-03-09 20:24:43 +00:00
*
2016-06-23 03:49:47 +00:00
* 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
2013-03-08 00:25:48 +00:00
* /
2014-09-23 05:01:24 +00:00
package net.minecraftforge.fml.common.asm ;
2012-08-04 15:26:51 +00:00
2013-01-27 22:09:00 +00:00
import java.io.File ;
2016-12-21 19:13:27 +00:00
import java.io.InputStream ;
2013-07-09 12:30:47 +00:00
import java.net.URLDecoder ;
2017-07-13 04:50:28 +00:00
import java.nio.charset.StandardCharsets ;
2012-12-16 03:30:16 +00:00
import java.security.CodeSource ;
import java.security.cert.Certificate ;
2012-08-04 15:26:51 +00:00
import java.util.Map ;
2013-07-09 02:10:06 +00:00
import java.util.jar.JarEntry ;
import java.util.jar.JarFile ;
2014-09-23 05:01:24 +00:00
2018-03-18 01:41:16 +00:00
import net.minecraftforge.fml.common.FMLLog ;
2016-12-23 23:23:31 +00:00
import org.apache.commons.io.IOUtils ;
2012-08-04 15:26:51 +00:00
2013-06-14 21:21:49 +00:00
import net.minecraft.launchwrapper.LaunchClassLoader ;
2014-09-23 05:01:24 +00:00
import net.minecraftforge.fml.common.CertificateHelper ;
import net.minecraftforge.fml.common.FMLCommonHandler ;
2018-06-21 19:37:32 +00:00
import net.minecraftforge.fml.common.asm.deobf.FMLDeobfuscatingRemapper ;
2014-09-23 05:01:24 +00:00
import net.minecraftforge.fml.common.patcher.ClassPatchManager ;
2018-06-21 19:37:32 +00:00
import net.minecraftforge.api.distmarker.Dist ;
2013-06-14 21:21:49 +00:00
2013-07-09 02:10:06 +00:00
import com.google.common.io.ByteStreams ;
2012-08-04 15:26:51 +00:00
public class FMLSanityChecker implements IFMLCallHook
{
2013-07-09 02:10:06 +00:00
private static final String FMLFINGERPRINT = " 51:0A:FB:4C:AF:A4:A0:F2:F5:CF:C5:0E:B4:CC:3C:30:24:4A:E3:8E " . toLowerCase ( ) . replace ( " : " , " " ) ;
2013-07-12 10:05:20 +00:00
private static final String FORGEFINGERPRINT = " E3:C3:D5:0C:7C:98:6D:F7:4C:64:5C:0A:C5:46:39:74:1C:90:A5:57 " . toLowerCase ( ) . replace ( " : " , " " ) ;
2013-07-09 02:10:06 +00:00
private static final String MCFINGERPRINT = " CD:99:95:96:56:F7:53:DC:28:D8:63:B4:67:69:F7:F8:FB:AE:FC:FC " . toLowerCase ( ) . replace ( " : " , " " ) ;
2013-06-14 21:21:49 +00:00
private LaunchClassLoader cl ;
2014-08-20 14:28:50 +00:00
private boolean liveEnv ;
2013-08-27 16:31:37 +00:00
public static File fmlLocation ;
2012-08-04 15:26:51 +00:00
@Override
public Void call ( ) throws Exception
{
2012-12-16 03:30:16 +00:00
CodeSource codeSource = getClass ( ) . getProtectionDomain ( ) . getCodeSource ( ) ;
boolean goodFML = false ;
2013-07-09 02:10:06 +00:00
boolean fmlIsJar = false ;
2012-12-16 03:30:16 +00:00
if ( codeSource . getLocation ( ) . getProtocol ( ) . equals ( " jar " ) )
{
2013-07-09 02:10:06 +00:00
fmlIsJar = true ;
2012-12-16 03:30:16 +00:00
Certificate [ ] certificates = codeSource . getCertificates ( ) ;
2012-12-18 00:55:46 +00:00
if ( certificates ! = null )
2012-12-16 03:30:16 +00:00
{
2012-12-18 00:55:46 +00:00
for ( Certificate cert : certificates )
2012-12-17 02:22:55 +00:00
{
2012-12-18 00:55:46 +00:00
String fingerprint = CertificateHelper . getFingerprint ( cert ) ;
if ( fingerprint . equals ( FMLFINGERPRINT ) )
{
2018-03-18 01:41:16 +00:00
FMLLog . log . info ( " Found valid fingerprint for FML. Certificate fingerprint {} " , fingerprint ) ;
2012-12-18 00:55:46 +00:00
goodFML = true ;
}
else if ( fingerprint . equals ( FORGEFINGERPRINT ) )
{
2018-03-18 01:41:16 +00:00
FMLLog . log . info ( " Found valid fingerprint for Minecraft Forge. Certificate fingerprint {} " , fingerprint ) ;
2012-12-18 00:55:46 +00:00
goodFML = true ;
}
else
{
2018-03-18 01:41:16 +00:00
FMLLog . log . error ( " Found invalid fingerprint for FML: {} " , fingerprint ) ;
2012-12-18 00:55:46 +00:00
}
2012-12-17 02:22:55 +00:00
}
2012-12-16 03:30:16 +00:00
}
}
else
{
goodFML = true ;
}
2014-08-16 14:32:22 +00:00
// Server is not signed, so assume it's good - a deobf env is dev time so it's good too
boolean goodMC = FMLLaunchHandler . side ( ) = = Side . SERVER | | ! liveEnv ;
2013-07-14 17:11:32 +00:00
int certCount = 0 ;
2013-07-09 02:10:06 +00:00
try
{
2013-11-10 16:49:06 +00:00
Class < ? > cbr = Class . forName ( " net.minecraft.client.ClientBrandRetriever " , false , cl ) ;
2013-07-09 02:10:06 +00:00
codeSource = cbr . getProtectionDomain ( ) . getCodeSource ( ) ;
}
catch ( Exception e )
{
2013-07-14 17:11:32 +00:00
// Probably a development environment, or the server (the server is not signed)
2013-07-09 02:10:06 +00:00
goodMC = true ;
}
2013-08-17 15:40:15 +00:00
JarFile mcJarFile = null ;
2013-07-09 02:10:06 +00:00
if ( fmlIsJar & & ! goodMC & & codeSource . getLocation ( ) . getProtocol ( ) . equals ( " jar " ) )
{
try
{
String mcPath = codeSource . getLocation ( ) . getPath ( ) . substring ( 5 ) ;
mcPath = mcPath . substring ( 0 , mcPath . lastIndexOf ( '!' ) ) ;
2017-07-13 04:50:28 +00:00
mcPath = URLDecoder . decode ( mcPath , StandardCharsets . UTF_8 . name ( ) ) ;
2013-08-17 15:40:15 +00:00
mcJarFile = new JarFile ( mcPath , true ) ;
2013-07-09 02:10:06 +00:00
mcJarFile . getManifest ( ) ;
2013-07-14 17:11:32 +00:00
JarEntry cbrEntry = mcJarFile . getJarEntry ( " net/minecraft/client/ClientBrandRetriever.class " ) ;
2016-12-21 19:13:27 +00:00
InputStream mcJarFileInputStream = mcJarFile . getInputStream ( cbrEntry ) ;
try
{
ByteStreams . toByteArray ( mcJarFileInputStream ) ;
}
finally
{
IOUtils . closeQuietly ( mcJarFileInputStream ) ;
}
2013-07-14 17:11:32 +00:00
Certificate [ ] certificates = cbrEntry . getCertificates ( ) ;
certCount = certificates ! = null ? certificates . length : 0 ;
2013-07-09 02:10:06 +00:00
if ( certificates ! = null )
{
for ( Certificate cert : certificates )
{
String fingerprint = CertificateHelper . getFingerprint ( cert ) ;
if ( fingerprint . equals ( MCFINGERPRINT ) )
{
2018-03-18 01:41:16 +00:00
FMLLog . log . info ( " Found valid fingerprint for Minecraft. Certificate fingerprint {} " , fingerprint ) ;
2013-07-09 02:10:06 +00:00
goodMC = true ;
}
}
}
}
catch ( Throwable e )
{
2018-03-18 01:41:16 +00:00
FMLLog . log . error ( " A critical error occurred trying to read the minecraft jar file " , e ) ;
2013-07-09 02:10:06 +00:00
}
2013-08-17 15:40:15 +00:00
finally
{
2017-06-15 18:26:14 +00:00
IOUtils . closeQuietly ( mcJarFile ) ;
2013-08-17 15:40:15 +00:00
}
2013-07-09 02:10:06 +00:00
}
else
{
goodMC = true ;
}
if ( ! goodMC )
{
2018-03-18 01:41:16 +00:00
FMLLog . log . error ( " The minecraft jar {} appears to be corrupt! There has been CRITICAL TAMPERING WITH MINECRAFT, it is highly unlikely minecraft will work! STOP NOW, get a clean copy and try again! " , codeSource . getLocation ( ) . getFile ( ) ) ;
2013-07-09 02:10:06 +00:00
if ( ! Boolean . parseBoolean ( System . getProperty ( " fml.ignoreInvalidMinecraftCertificates " , " false " ) ) )
{
2018-03-18 01:41:16 +00:00
FMLLog . log . error ( " For your safety, FML will not launch minecraft. You will need to fetch a clean version of the minecraft jar file " ) ;
FMLLog . log . error ( " Technical information: The class net.minecraft.client.ClientBrandRetriever should have been associated with the minecraft jar file, " +
2013-07-14 17:11:32 +00:00
" and should have returned us a valid, intact minecraft jar location. This did not work. Either you have modified the minecraft jar file (if so " +
" run the forge installer again), or you are using a base editing jar that is changing this class (and likely others too). If you REALLY " +
" want to run minecraft in this configuration, add the flag -Dfml.ignoreInvalidMinecraftCertificates=true to the 'JVM settings' in your launcher profile. " ) ;
2014-08-16 14:32:22 +00:00
FMLCommonHandler . instance ( ) . exitJava ( 1 , false ) ;
2013-07-09 02:10:06 +00:00
}
else
{
2018-03-18 01:41:16 +00:00
FMLLog . log . error ( " FML has been ordered to ignore the invalid or missing minecraft certificate. This is very likely to cause a problem! " ) ;
FMLLog . log . error ( " Technical information: ClientBrandRetriever was at {}, there were {} certificates for it " , codeSource . getLocation ( ) , certCount ) ;
2013-07-09 02:10:06 +00:00
}
}
2012-12-16 03:30:16 +00:00
if ( ! goodFML )
{
2018-03-18 01:41:16 +00:00
FMLLog . log . error ( " FML appears to be missing any signature data. This is not a good thing " ) ;
2012-12-16 03:30:16 +00:00
}
2012-08-04 15:26:51 +00:00
return null ;
}
@Override
public void injectData ( Map < String , Object > data )
{
2014-08-16 14:32:22 +00:00
liveEnv = ( Boolean ) data . get ( " runtimeDeobfuscationEnabled " ) ;
2013-06-14 21:21:49 +00:00
cl = ( LaunchClassLoader ) data . get ( " classLoader " ) ;
2013-06-12 12:53:10 +00:00
File mcDir = ( File ) data . get ( " mcLocation " ) ;
2013-08-27 16:31:37 +00:00
fmlLocation = ( File ) data . get ( " coremodLocation " ) ;
2013-06-15 00:45:52 +00:00
ClassPatchManager . INSTANCE . setup ( FMLLaunchHandler . side ( ) ) ;
2013-09-24 15:09:27 +00:00
FMLDeobfuscatingRemapper . INSTANCE . setup ( mcDir , cl , ( String ) data . get ( " deobfuscationFileName " ) ) ;
2012-08-04 15:26:51 +00:00
}
}