prevent hijacking of signed Getdown to run malicious code; greater torrent download speed tolerance

This commit is contained in:
Elizabeth Fong
2006-08-20 09:45:21 +00:00
parent a98376a2f7
commit c92e372d39
5 changed files with 128 additions and 6 deletions
+1
View File
@@ -8,6 +8,7 @@
-injars dist/getdown.jar(!**/tools/DigesterTask*,!**/tools/Differ*) -injars dist/getdown.jar(!**/tools/DigesterTask*,!**/tools/Differ*)
-injars lib/jRegistryKey.jar(!META-INF/*) -injars lib/jRegistryKey.jar(!META-INF/*)
-injars lib/samskivert.jar(!META-INF/*,!**/velocity/**,!**/xml/**) -injars lib/samskivert.jar(!META-INF/*,!**/velocity/**,!**/xml/**)
-injars lib/commons-codec.jar(!META-INF/*)
-injars lib/commons-io.jar(!META-INF/*) -injars lib/commons-io.jar(!META-INF/*)
-injars lib/snark.jar(!META-INF/*) -injars lib/snark.jar(!META-INF/*)
+1
View File
@@ -1,5 +1,6 @@
samskivert.jar samskivert.jar
ant.jar ant.jar
commons-codec.jar
commons-io.jar commons-io.jar
javaws.jar javaws.jar
snark.jar snark.jar
@@ -23,6 +23,9 @@ package com.threerings.getdown.launcher;
import java.awt.Container; import java.awt.Container;
import java.awt.Image; import java.awt.Image;
import java.net.URL; import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.Signature;
import java.security.cert.Certificate;
import javax.swing.JApplet; import javax.swing.JApplet;
import javax.swing.JPanel; import javax.swing.JPanel;
@@ -32,6 +35,8 @@ import java.io.FileOutputStream;
import java.io.File; import java.io.File;
import java.io.PrintStream; import java.io.PrintStream;
import org.apache.commons.codec.binary.Base64;
import com.samskivert.util.RunAnywhere; import com.samskivert.util.RunAnywhere;
import com.samskivert.util.StringUtil; import com.samskivert.util.StringUtil;
@@ -46,6 +51,54 @@ public class GetdownApplet extends JApplet
@Override // documentation inherited @Override // documentation inherited
public void init () public void init ()
{ {
// First off, verify that we are not being hijacked to execute
// malicious code in the name of the signer.
String appbase = getParameter("appbase");
String appname = getParameter("appname");
String imgpath = getParameter("bgimage");
if (appbase == null) {
appbase = "";
}
if (appname == null) {
appname = "";
}
if (imgpath == null) {
imgpath = "";
}
String params = appbase + appname + imgpath;
String signature = getParameter("signature");
if (signature == null) {
signature = "";
}
Object[] signers = GetdownApplet.class.getSigners();
if (signers.length == 0) {
_safe = true;
}
for (Object signer : signers) {
if (!_safe && signer instanceof Certificate) {
Certificate cert = (Certificate)signer;
try {
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(cert);
Log.info(params);
sig.update(params.getBytes());
byte[] rawsig = Base64.decodeBase64(signature.getBytes());
if (sig.verify(rawsig)) {
_safe = true;
}
} catch (GeneralSecurityException gse) {
// ignore the error - the default is to not launch.
}
}
}
if (!_safe) {
Log.warning("Signed getdown invoked on unsigned application; " +
"aborting installation.");
return;
}
// when run from an applet, we install // when run from an applet, we install
String root; String root;
if (RunAnywhere.isWindows()) { if (RunAnywhere.isWindows()) {
@@ -56,7 +109,6 @@ public class GetdownApplet extends JApplet
root = ".getdown"; root = ".getdown";
} }
String appname = getParameter("appname");
String appdir = System.getProperty("user.home") + String appdir = System.getProperty("user.home") +
File.separator + root + File.separator + appname; File.separator + root + File.separator + appname;
@@ -82,7 +134,6 @@ public class GetdownApplet extends JApplet
// if our getdown.txt file does not exist, auto-create it // if our getdown.txt file does not exist, auto-create it
File gdfile = new File(appDir, "getdown.txt"); File gdfile = new File(appDir, "getdown.txt");
if (!gdfile.exists()) { if (!gdfile.exists()) {
String appbase = getParameter("appbase");
if (StringUtil.isBlank(appbase)) { if (StringUtil.isBlank(appbase)) {
Log.warning("Missing 'appbase' cannot auto-create " + Log.warning("Missing 'appbase' cannot auto-create " +
"application directory."); "application directory.");
@@ -96,7 +147,6 @@ public class GetdownApplet extends JApplet
} }
// if a background image was specified, grabbit // if a background image was specified, grabbit
String imgpath = getParameter("bgimage");
try { try {
if (!StringUtil.isBlank(imgpath)) { if (!StringUtil.isBlank(imgpath)) {
_bgimage = getImage(new URL(getDocumentBase(), imgpath)); _bgimage = getImage(new URL(getDocumentBase(), imgpath));
@@ -156,6 +206,10 @@ public class GetdownApplet extends JApplet
@Override // documentation inherited @Override // documentation inherited
public void start () public void start ()
{ {
if (!_safe) {
return;
}
try { try {
_getdown.start(); _getdown.start();
} catch (Exception e) { } catch (Exception e) {
@@ -188,4 +242,10 @@ public class GetdownApplet extends JApplet
protected Getdown _getdown; protected Getdown _getdown;
protected Image _bgimage; protected Image _bgimage;
/**
* Getdown will refuse to initialize if the jar is signed but the
* parameters are not validated to prevent malicious code from being run.
*/
protected boolean _safe = false;
} }
@@ -83,14 +83,15 @@ public class TorrentDownloader extends Downloader
Snark snark = _torrentmap.get(rsrc); Snark snark = _torrentmap.get(rsrc);
SnarkShutdown snarkStopper = _stoppermap.get(rsrc); SnarkShutdown snarkStopper = _stoppermap.get(rsrc);
snark.collectPieces(); snark.collectPieces();
// Override the start time, since Snark allocates storage prior to
// doing any downloading
_start = System.currentTimeMillis();
while (_currentSize != snark.meta.getTotalLength()) { while (_currentSize != snark.meta.getTotalLength()) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if ((now - _lastUpdate) >= UPDATE_DELAY) { if ((now - _lastUpdate) >= UPDATE_DELAY) {
_currentSize = snark.coordinator.getDownloaded(); _currentSize = snark.coordinator.getDownloaded();
if ((_currentSize < SIZE_THRESHOLD && if ((_currentSize < SIZE_THRESHOLD &&
(now - _start) >= TIME_THRESHOLD) || (now - _start) >= TIME_THRESHOLD)) {
(_currentSize == 0 &&
(now - _start) >= TIME_THRESHOLD / 4)) {
Log.info("Torrenting too slow, falling back to HTTP."); Log.info("Torrenting too slow, falling back to HTTP.");
// The download isn't going as planned, abort; // The download isn't going as planned, abort;
snarkStopper.run(); snarkStopper.run();
@@ -0,0 +1,59 @@
package com.threerings.getdown.tools;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Signature;
import org.apache.commons.codec.binary.Base64;
/**
* Produces a signed hash of the appbase, appname, and image path to ensure
* that signed copies of Getdown are not hijacked to run malicious code.
*/
public class AppletParamSigner
{
public static void main (String[] args)
{
try {
if (args.length != 7) {
System.err.println(
"AppletParamSigner keystore storepass alias keypass " +
"appbase appname imgpath"
);
System.exit(255);
}
String keystore = args[0];
String storepass = args[1];
String alias = args[2];
String keypass = args[3];
String appbase = args[4];
String appname = args[5];
String imgpath = args[6];
String params = appbase + appname + imgpath;
KeyStore store = KeyStore.getInstance("JKS");
store.load(new BufferedInputStream(new FileInputStream(keystore)),
storepass.toCharArray());
PrivateKey key = (PrivateKey)store.getKey(alias,
keypass.toCharArray());
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initSign(key);
sig.update(params.getBytes());
String signed = new String(Base64.encodeBase64(sig.sign()));
System.out.println(
"<param name=\"appbase\" value=\"" + appbase + "\" />");
System.out.println(
"<param name=\"appname\" value=\"" + appname + "\" />");
System.out.println(
"<param name=\"bgimage\" value=\"" + imgpath + "\" />");
System.out.println(
"<param name=\"signature\" value=\"" + signed + "\" />");
} catch (Exception e) {
System.err.println("Failed to produce signature.");
e.printStackTrace();
}
}
}