Versions Compared

Key

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

Code should be signed only if it requires elevated privileges to perform one or more tasks (see ENV00-J. Do not sign code that performs only unprivileged operations for more information). For example, applets are denied the privilege of making HTTP connections to any hosts except the host from which they came. When an applet requires an HTTP connection with an external host to download plug-ins or extensions, its vendor may provide signed code rather than force the user to arbitrarily assign the permissions it requires. Because executing privilege-elevated signed code can be extremely dangerous, verifying the authenticity of its origin is of utmost importance.

Java-based technologies typically use the Java Archive (JAR) feature for packaging files to facilitate platform independent deployment. Be it desktop applications, Enterprise Java to package files for platform-independent deployment. JAR files are the preferred means of distribution for Enterprise Java-Beans (EJB), MIDlets (J2ME) or , and Weblogic Server J2EE applications, for example, jar files are the preferred distribution mechanism. The point-and-click installation provided by Java Web Start also relies on the jar JAR file format for packaging.

It is in the interest of the user to verify the authenticity and integrity of the artifacts that they wish to deploy. At the same time, it is the software vendor's responsibility to ensure that all files, supporting documents like help files, installation instructions and other software artifacts, are digitally signed to thwart man in the middle attacks. Likewise, any software updates or patches must be signed by the vendor and verified explicitly by the preexisting software implementation at the remote user's side, usually without any user intervention.

Vendors sign their JAR files when required. Signing certifies the authenticity of the code, but it cannot guarantee the security of the code.

According to the Java Tutorials [Java Tutorials], Wiki MarkupAccording to \[[Tutorials 08|AA. Java References#Tutorials 08]\]:

If you are creating applet code that you will sign, it needs to be placed in a JAR file. The same is true if you are creating application code that may be similarly restricted by running it with a security manager. The reason you need the JAR file is that when a policy file specifies that code signed by a particular entity is permitted one or more operations, such as specific file reads or writes, the code is expected to come from a signed JAR file. (The term "signed code" is an abbreviated way of saying "code in a class file that appears in a JAR file that was signed.")

Noncompliant Code Example

This noncompliant example creates the jar file but does not address code signing through digital signatures. Anyone can replace the package or individual files with malicious code while the file is in transit.

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#ccccff

jar cf updates-jar-file.jar input-file(s)
jarsigner -keystore /home/kstore.jks -storepass password1 -keypass userpassword
-signedjar signed-updates-jar-file.jar updates-jar-file.jar user

Noncompliant Code Example

Naturally, equally important is verifying the signature at the client side. Depending on how the client code works, signatures may or may not be automatically checked. For instance, any Client code may lack programmatic checks of code signatures. For example, instances of URLClassLoader and its subclasses and java.util.jar automatically verify a signature whenever the jar file appears to be signed. If however, the developer implements a custom classloader that goes on to subclass the ClassLoader, this step is not performed automatically. Moroever, the automatic verification just involves an integrity check and does not authenticate the loaded class. This is because the check uses a public key that is contained within the jar. This public key can be easily replaced with a new one and the other files can be tampered with to reflect the hashes computed over the malicious class file. signatures of signed JAR files. Developer-implemented custom class loaders may lack this check. Moreover, even in the URLClassLoader case, the automatic verification performs only an integrity check; it fails to authenticate the loaded class because the check uses the public key contained within the JAR without validating the public key. The legitimate JAR file may be replaced with a malicious JAR file containing a different public key along with appropriately modified digest values.

The default automatic signature verification process may still be used but is not sufficient. Systems that use the default automatic signature verification process must perform additional checks to ensure that the signature is correct (such as comparing it against a known trusted signature).

Noncompliant Code Example

This noncompliant code example demonstrates the JarRunner application [Tutorials 08] that , which can be used to dynamically execute a particular class residing within a jar fileJAR file (abridged version of the class in The Java Tutorials [Java Tutorials]). It creates a JarClassLoader that loads an application update, plugin plug-in, or patch over an untrusted network such as the Internet. The URL to fetch the code is specified as the first argument (for example, http://somewebsite.comwww.securecoding.cert.org/software-updates.jarImage Removed) and ; any other arguments specify the arguments that are to be passed to the class to be that is loaded. Reflection is used JarRunner uses reflection to invoke the main() method of the loaded class. Unfortunately, there are no built in checks for verifying the signature. Any man in the middle can construct a class that will run with the permissions specified for this code source in the policy by default, JarClassLoader verifies the signature using the public key contained within the JAR file.

Code Block
bgColor#FFcccc

public class JarRunner {
  public static void main(String[] args)
 {
      if (args.length < 1) { usage(); }
throws IOException, ClassNotFoundException,
        URL url = null;
   NoSuchMethodException, tryInvocationTargetException {
  
    URL 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..]");
  }
}

final 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

...

(jarsigner)

Users can—but usually do not—explicitly check JAR file signatures at the command line. This solution may be adequate for programs that require manual installation of JAR files. Any malicious tampering results in 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.

Code Block
bgColor#ccccff

jarsigner -verify signed-updates-jar-file.jar

Compliant Solution (Certificate Chain)

When the local system cannot reliably verify the signature, the invoking program must verify the signature programmatically An explicit signature verification check should be built within the invoking program. This can be achieved by obtaining the chain of certificates from the CodeSource of the class being loaded and checking if whether any one of the certificates belongs belong to the a trusted signer whose certificate has been securely obtained securely beforehand and is stored in a local keystore. The invokeClass method can be modified to do this as shown in this compliant solution.This compliant solution demonstrates the necessary modifications to the invokeClass() method:

Code Block
bgColor#ccccff
public void invokeClass(String name, String[] args)
    throws ClassNotFoundException, NoSuchMethodException, 
           InvocationTargetException, GeneralSecurityException,
           IOException {
  Class c = loadClass(name);
  Certificate[] certs = 
      c.getProtectionDomain().getCodeSource().getCertificates();
  if (certs == null) {
    // Return, do not execute if unsigned
    System.out.println("No signature!");
 return;  // return,; do not
 execute if unsigned
}  

  KeyStore ks = KeyStore.getInstance("JKS");
  ks.load(new FileInputStream(System.getProperty(
      "user.home"+ File.separator + "keystore.jks")),
      "loadkeystorepassword".toCharArray());
  // User is the alias
  Certificate pubCert = ks.getCertificate("user");  
  // userCheck iswith the alias
 trusted public key, else throws exception
  certs[0].verify(pubCert.getPublicKey()); // check with the trusted public key, else throws exception

}

Because the invokeClass() method now has two additional exceptions in its throws clause, the catch block in the main() method must be altered accordingly.

The It is not always the case that arbitrary code characterized by system damage gets executed. By default, the URLClassLoader and all its subclasses are given by default only given enough permissions to interact with the URL that was specified when the URLClassLoader object was created. This , which means that one the loaded code can interact only with the specified host by default. This however, does not eliminate the risk since the loaded file may need to be granted appropriate privileges to perform more . It fails to mitigate the risk completely, however, because the loaded code may have been granted privileges that permit other sensitive operations such as updating an existing local jar JAR file. Code signing gives the receiver the confidence to grant the remote code the requisite permissions.

Risk Assessment

Running unsigned code obtained from both trusted or untrusted locations can lead to execution of arbitrary code supplied by an attacker, given sufficient permissions in the security policyFailure to verify a digital signature, whether manually or programmatically, can result in the execution of malicious code.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

SEC05

SEC06-J

high

High

probable

Probable

medium

Medium

P12

L1

Automated Detection

...

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[API 06|AA. Java References#API 06]\] 
\[[Gong 03|AA. Java References#Gong 03]\] 12.8.3 jarsigner
\[[Eclipse 08|AA. Java References#Eclipse 08]\] [JAR Signing|http://wiki.eclipse.org/JAR_Signing] and [Signed bundles and protecting against malicious code|http://help.eclipse.org/stable/index.jsp?topic=/org.eclipse.platform.doc.isv/guide]
\[[Halloway 01|AA. Java References#Halloway 01]\] 
\[[Flanagan 05|AA. Java References#Flanagan 05]\] Chapter 24. The java.util.jar Package
\[[Oaks 01|AA. Java References#Oaks 01]\] Chapter 12: Digital Signatures, Signed Classes
\[[Tutorials 08|AA. Java References#Tutorials 08]\] [The JarRunner Class|http://java.sun.com/docs/books/tutorial/deployment/jar/jarrunner.html], [Lesson: API and Tools Use for Secure Code and File Exchanges|http://java.sun.com/docs/books/tutorial/security/sigcert/index.html] and [Verifying Signed JAR Files|http://java.sun.com/docs/books/tutorial/deployment/jar/verify.html]
\[[JarSpec 08|AA. Java References#JarSpec 08]\] Signature Validation 
\[[Bea 08|AA. Java References#Bea 08]\] 
\[[Muchow 01|AA. Java References#Muchow 01]\] 
\[[MITRE 09|AA. Java References#MITRE 09]\] [CWE ID 300|http://cwe.mitre.org/data/definitions/300.html] "Channel Accessible by Non-Endpoint (aka 'Man-in-the-Middle')", [CWE ID 319|http://cwe.mitre.org/data/definitions/319.html] "Cleartext Transmission of Sensitive Information", [CWE ID 494|http://cwe.mitre.org/data/definitions/494.html] "Download of Code Without Integrity Check", [CWE ID 347|http://cwe.mitre.org/data/definitions/347.html] "Improperly Verified Signature"

Automated detection is not feasible in the fully general case. However, an approach similar to Design Fragments [Fairbanks 2007] could assist both programmers and static analysis tools.

ToolVersionCheckerDescription
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

JAVA.IO.INJ.ANDROID.MESSAGE
JAVA.IO.TAINT.MESSAGE

Android Message Injection (Java)
Tainted Message (Java)

Related Guidelines

ISO/IEC TR 24772:2010

Improperly Verified Signature [XZR]

MITRE CWE

CWE-300, Channel Accessible by Non-endpoint (aka "Man-in-the-Middle")
CWE-319, Cleartext Transmission of Sensitive Information
CWE-347, Improper Verification of Cryptographic Signature
CWE-494, Download of Code without Integrity Check

Bibliography


...

Image Added Image Added Image AddedSEC04-J. Beware of standard APIs that perform access checks against the immediate caller      00. Security (SEC)      SEC06-J. Assume that all Java clients can be reverse engineered, monitored, and modified