Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
bgColor#FFcccc
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
bgColor#FFcccc
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.

...