2013-03-08 00:25:48 +00:00
/ *
* Forge Mod Loader
* Copyright ( c ) 2012 - 2013 cpw .
* All rights reserved . This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2 . 1
* which accompanies this distribution , and is available at
* http : //www.gnu.org/licenses/old-licenses/gpl-2.0.html
2013-03-09 20:24:43 +00:00
*
2013-03-08 00:25:48 +00:00
* Contributors :
* cpw - implementation
* /
2012-08-06 20:12:50 +00:00
package cpw.mods.fml.common.asm ;
2012-08-04 15:26:51 +00:00
2012-12-18 00:55:46 +00:00
import java.io.ByteArrayInputStream ;
2013-01-27 22:09:00 +00:00
import java.io.File ;
2012-12-18 00:55:46 +00:00
import java.io.InputStreamReader ;
2012-12-16 03:30:16 +00:00
import java.io.ObjectInputStream.GetField ;
2012-12-18 00:55:46 +00:00
import java.io.StringReader ;
2012-12-16 03:30:16 +00:00
import java.net.JarURLConnection ;
2013-07-09 02:10:06 +00:00
import java.net.URL ;
2013-07-09 12:30:47 +00:00
import java.net.URLDecoder ;
2012-12-18 00:55:46 +00:00
import java.nio.charset.Charset ;
2012-12-16 03:30:16 +00:00
import java.security.CodeSource ;
2012-12-18 00:55:46 +00:00
import java.security.cert.CertPath ;
import java.security.cert.CertPathValidator ;
2012-12-16 03:30:16 +00:00
import java.security.cert.Certificate ;
2012-12-18 00:55:46 +00:00
import java.security.cert.CertificateFactory ;
import java.security.cert.PKIXCertPathValidatorResult ;
import java.security.cert.PKIXParameters ;
import java.security.cert.TrustAnchor ;
import java.security.cert.X509Certificate ;
import java.util.Arrays ;
import java.util.Collections ;
2013-06-12 12:53:10 +00:00
import java.util.Locale ;
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 ;
import java.util.logging.Level ;
import java.util.zip.ZipEntry ;
2012-08-04 15:26:51 +00:00
import javax.swing.JOptionPane ;
2013-06-14 21:21:49 +00:00
import net.minecraft.launchwrapper.LaunchClassLoader ;
2012-08-04 15:26:51 +00:00
import org.objectweb.asm.ClassReader ;
import org.objectweb.asm.ClassVisitor ;
import org.objectweb.asm.FieldVisitor ;
import org.objectweb.asm.Opcodes ;
2013-07-09 12:30:47 +00:00
import com.google.common.base.Charsets ;
2013-07-09 02:10:06 +00:00
import com.google.common.io.ByteStreams ;
2012-12-16 03:30:16 +00:00
import cpw.mods.fml.common.CertificateHelper ;
2013-01-27 22:09:00 +00:00
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper ;
2013-06-12 12:53:10 +00:00
import cpw.mods.fml.common.patcher.ClassPatchManager ;
2013-06-14 21:21:49 +00:00
import cpw.mods.fml.relauncher.FMLLaunchHandler ;
2013-01-28 03:42:36 +00:00
import cpw.mods.fml.relauncher.FMLRelaunchLog ;
2012-08-06 20:12:50 +00:00
import cpw.mods.fml.relauncher.IFMLCallHook ;
2013-07-09 10:27:29 +00:00
import cpw.mods.fml.relauncher.Side ;
2012-08-06 20:12:50 +00:00
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 ( " : " , " " ) ;
2012-08-04 15:26:51 +00:00
static class MLDetectorClassVisitor extends ClassVisitor
{
private boolean foundMarker = false ;
private MLDetectorClassVisitor ( )
{
super ( Opcodes . ASM4 ) ;
}
@Override
public FieldVisitor visitField ( int arg0 , String arg1 , String arg2 , String arg3 , Object arg4 )
{
2012-08-06 20:12:50 +00:00
if ( " fmlMarker " . equals ( arg1 ) )
2012-08-04 15:26:51 +00:00
{
foundMarker = true ;
}
return null ;
}
}
2013-06-14 21:21:49 +00:00
private LaunchClassLoader cl ;
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 ) )
{
2013-01-28 03:42:36 +00:00
FMLRelaunchLog . info ( " Found valid fingerprint for FML. Certificate fingerprint %s " , fingerprint ) ;
2012-12-18 00:55:46 +00:00
goodFML = true ;
}
else if ( fingerprint . equals ( FORGEFINGERPRINT ) )
{
2013-01-28 03:42:36 +00:00
FMLRelaunchLog . info ( " Found valid fingerprint for Minecraft Forge. Certificate fingerprint %s " , fingerprint ) ;
2012-12-18 00:55:46 +00:00
goodFML = true ;
}
else
{
2013-01-28 03:42:36 +00:00
FMLRelaunchLog . severe ( " Found invalid fingerprint for FML: %s " , 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 ;
}
2013-07-09 02:10:06 +00:00
2013-07-09 12:30:47 +00:00
boolean goodMC = FMLLaunchHandler . side ( ) = = Side . SERVER ; //Server is not signed, so assume it's good.
2013-07-14 17:11:32 +00:00
int certCount = 0 ;
2013-07-09 02:10:06 +00:00
try
{
2013-07-14 17:11:32 +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 ;
}
if ( fmlIsJar & & ! goodMC & & codeSource . getLocation ( ) . getProtocol ( ) . equals ( " jar " ) )
{
try
{
String mcPath = codeSource . getLocation ( ) . getPath ( ) . substring ( 5 ) ;
mcPath = mcPath . substring ( 0 , mcPath . lastIndexOf ( '!' ) ) ;
2013-07-09 12:30:47 +00:00
mcPath = URLDecoder . decode ( mcPath , Charsets . UTF_8 . name ( ) ) ;
2013-07-09 02:10:06 +00:00
JarFile mcJarFile = new JarFile ( mcPath , true ) ;
mcJarFile . getManifest ( ) ;
2013-07-14 17:11:32 +00:00
JarEntry cbrEntry = mcJarFile . getJarEntry ( " net/minecraft/client/ClientBrandRetriever.class " ) ;
ByteStreams . toByteArray ( mcJarFile . getInputStream ( cbrEntry ) ) ;
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 ) )
{
FMLRelaunchLog . info ( " Found valid fingerprint for Minecraft. Certificate fingerprint %s " , fingerprint ) ;
goodMC = true ;
}
}
}
}
catch ( Throwable e )
{
FMLRelaunchLog . log ( Level . SEVERE , e , " A critical error occurred trying to read the minecraft jar file " ) ;
}
}
else
{
goodMC = true ;
}
if ( ! goodMC )
{
FMLRelaunchLog . severe ( " The minecraft jar %s 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 ( ) ) ;
if ( ! Boolean . parseBoolean ( System . getProperty ( " fml.ignoreInvalidMinecraftCertificates " , " false " ) ) )
{
FMLRelaunchLog . severe ( " For your safety, FML will not launch minecraft. You will need to fetch a clean version of the minecraft jar file " ) ;
2013-07-14 17:11:32 +00:00
FMLRelaunchLog . severe ( " Technical information: The class net.minecraft.client.ClientBrandRetriever should have been associated with the minecraft jar file, " +
" 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. " ) ;
2013-07-09 02:10:06 +00:00
System . exit ( 1 ) ;
}
else
{
2013-07-14 17:11:32 +00:00
FMLRelaunchLog . severe ( " FML has been ordered to ignore the invalid or missing minecraft certificate. This is very likely to cause a problem! " ) ;
FMLRelaunchLog . severe ( " Technical information: ClientBrandRetriever was at %s, there were %d certificates for it " , codeSource . getLocation ( ) , certCount ) ;
2013-07-09 02:10:06 +00:00
}
}
2012-12-16 03:30:16 +00:00
if ( ! goodFML )
{
2013-01-28 03:42:36 +00:00
FMLRelaunchLog . severe ( " 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
byte [ ] mlClass = cl . getClassBytes ( " ModLoader " ) ;
// Only care in obfuscated env
if ( mlClass = = null )
{
return null ;
}
MLDetectorClassVisitor mlTester = new MLDetectorClassVisitor ( ) ;
ClassReader cr = new ClassReader ( mlClass ) ;
cr . accept ( mlTester , ClassReader . SKIP_CODE ) ;
if ( ! mlTester . foundMarker )
{
2012-08-06 20:12:50 +00:00
JOptionPane . showMessageDialog ( null , " <html>CRITICAL ERROR<br/> " +
2012-08-04 15:26:51 +00:00
" ModLoader was detected in this environment<br/> " +
" ForgeModLoader cannot be installed alongside ModLoader<br/> " +
" All mods should work without ModLoader being installed<br/> " +
" Because ForgeModLoader is 100% compatible with ModLoader<br/> " +
" Re-install Minecraft Forge or Forge ModLoader into a clean<br/> " +
" jar and try again. " ,
" ForgeModLoader critical error " ,
JOptionPane . ERROR_MESSAGE ) ;
throw new RuntimeException ( " Invalid ModLoader class detected " ) ;
}
return null ;
}
@Override
public void injectData ( Map < String , Object > data )
{
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 " ) ;
FMLDeobfuscatingRemapper . INSTANCE . setup ( mcDir , cl , ( String ) data . get ( " deobfuscationFileName " ) ) ;
2013-06-15 00:45:52 +00:00
ClassPatchManager . INSTANCE . setup ( FMLLaunchHandler . side ( ) ) ;
2012-08-04 15:26:51 +00:00
}
}