...
| Code Block | ||
|---|---|---|
| ||
jar cfm updates-jar-file.jar Manifest.txt input-file(s).class |
...
Compliant Solution
The jarsigner tool is used to digitally sign jar files. To do this, it uses key and certificate information from a keystore. This compliant solution shows how to sign the jar file that was generated in the noncompliant code example. The URL of the keystore kstore follows the -keystore flag. The -signedjar option can be used to specify a different name for the signed archive to be generated. The private key associated with the alias user, will be used to digitally sign the jar file.
...
| Code Block | ||
|---|---|---|
| ||
public class JarRunner {
public static void main(String[] args) {
if (args.length < 1) { usage(); }
URL url = null;
try {
url = new URL(args[0]);
} catch (MalformedURLException e) { fatal("Invalid URL: " + args[0]); }
// Create the class loader for the application jar file
JarClassLoader cl = new JarClassLoader(url);
// Get the application's main class name
String name = null;
try {
name = cl.getMainClassName();
} catch (IOException e) { System.err.println("I/O error while loading JAR file:");
System.exit(1); }
if (name == null)
{ fatal("Specified jar file does not contain a 'Main-Class'" + " manifest attribute"); }
// Get arguments for the application
String[] newArgs = new String[args.length - 1];
System.arraycopy(args, 1, newArgs, 0, newArgs.length);
// Invoke application's main class
try {
cl.invokeClass(name, newArgs);
} catch (ClassNotFoundException e) { fatal("Class not found: " + name); }
catch (NoSuchMethodException e) { fatal("Class does not define a 'main' method: " + name); }
catch (InvocationTargetException e) { e.getTargetException().printStackTrace(); System.exit(1); }
}
private static void fatal(String s) {
System.err.println(s);
System.exit(1);
}
private static void usage() {
fatal("Usage: java JarRunner url [args..]");
}
}
class JarClassLoader extends URLClassLoader {
private URL url;
public JarClassLoader(URL url) {
super(new URL[] { url });
this.url = url;
}
public String getMainClassName() throws IOException {
URL u = new URL("jar", "", url + "!/");
JarURLConnection uc = (JarURLConnection) u.openConnection();
Attributes attr = uc.getMainAttributes();
return attr != null ? attr.getValue(Attributes.Name.MAIN_CLASS) : null;
}
public void invokeClass(String name, String[] args)
throws ClassNotFoundException, NoSuchMethodException,
InvocationTargetException {
Class c = loadClass(name);
Method m = c.getMethod("main", new Class[] { args.getClass() });
m.setAccessible(true);
int mods = m.getModifiers();
if (m.getReturnType() != void.class || !Modifier.isStatic(mods)
|| !Modifier.isPublic(mods)) { throw new NoSuchMethodException("main"); }
try {
m.invoke(null, new Object[] { args });
} catch (IllegalAccessException e) { System.out.println("Access denied"); }
}
}
|
Compliant Solution
If the program expects the user to manually install the new jar file, the user can explicitly check the signature from the command line. Any malicious tampering will lead to a SecurityException when the jarsigner tool is invoked with the -verify option.
...