Signing Java with Microsoft's Authenticode

Thursday Oct 29th 1998 by John Viega
Share:

Want to let your applet play outside the sandbox? We've looked at Sun and Netscape schemes for assuring security by signing applets, now we turn to Microsoft's Authenticode.

Not surprisingly, Microsoft, Netscape, and Sun have each developed a separate system for signing Java code, allowing applets to play outside the sandbox. In other articles in this series, we cover Netscape's and Sun's system; here is a look at Microsoft's.

Step one is securing an identity with which you can sign code.

Getting an Authenticode Certificate

A number of vendors distribute certificates suitable for Authenticode. Verisign, the certificate authority (CA) that provides Netscape Object Signing certificates, also issues Authenticode certificates.

You'll need to select a flavor of ID. For personal use, select class 2 (US$20 on your credit card). For business use, select class 3.

You'll be given a form to fill out, after which Verisign will try to verify you are who you say you are, mainly by running a credit check. Sometimes the credit check won't have up-to-date information. If you're rejected, try using the address of the last place you lived; that's the most common problem.

Once your data has been approved, Verisign sends an e-mail with instructions for picking up the certificate. When downloading the certificate, you will need to save two files: the private key file and the certificate file. Remember the password used to protect the private key; it will be needed when it comes time to sign code. For the sake of simplicity, we'll assume you saved your certificate as a:\Cert.spc and your private key as a:\Key.pvc.

Getting the signing software

Before signing anything with the certificates, download and install the Microsoft Java SDK.

We'll assume you installed the Java SDK in the directory C:\SDK-Java.31. All of the programs we're going to need for signing Java code live in C:\SDK-Java.31\Bin\PackSign, so you should probably add that directory to your path. Under Windows 95/98/NT, running the following command at the DOS prompt will fix up your path for the current session:

PATH=%PATH%;C:\SDK-Java.31\Bin\PackSign

You can add this command to your autoexec.bat file to make the change persist through a reboot.

Cabinet files

Unlike the other signing tools we discussed (which work on JAR files), Authenticode signing only works on cabinet (CAB) files. There's nothing special about the CAB format; it's just another way of archiving many files into one. However, it's the only archive format IE supports for signing Java code.

Say we have an applet that consists of two files: file1.class and file2.class. We can create a CAB file in the same directory by typing the following at the DOS prompt:


cabarc N test.cab file1.class file2.class

If there are no other class files in the directory, we can also type:


cabarc N test.cab *.class

Security zones

In order to understand what signing a CAB file means, we need to know a little something about what an IE "security zone" is. By default, a security zone is a group of Web sites. Each zone is assigned a security level, which may be Low, Medium, High, or Custom. We won't cover Custom zones, except to say that they can implement arbitrary security policies.

There's a default zone called Trusted Sites, into which a user can put any server. All code from that zone will be completely trusted (i.e., the zone has a Low security level). Similarly, there's a Restricted Sites zone. Any sites the user puts in this zone will need explicit permission before they can run anything "outside the sandbox." By default, most everything else falls into the Internet zone, which is assigned a Medium security level. Code can run outside the Java sandbox in a limited manner. For example, code can use up to 1 megabyte of data in a restricted area on your hard disk by using the API com.ms.io.clientstorage, which works out of the box with Internet Explorer only. Unlike fully trusted applets, applets restricted to the Medium security level should not otherwise be able to use your file system.

When signing our cabinet file, we request to run either with Medium or High privileges (we can also request Low privileges, but since we'll always be allowed to run in the sandbox, doing so is mainly useful only to prove you vouch for the CAB file). If our code ends up in a Low security zone, our code will always run without prompting the user for permission. If our code ends up in a Medium security zone, then before code that requests Medium level privileges can run, the user will be prompted as to whether to let the code run. If our code ends up in a High security zone, all code that wants to run outside the sandbox will need to be approved through a dialog with the user.

Signing CAB files

To sign test.cab, we're going to use the signcode command, which is included in the Java SDK. Here's a typical command line:


signcode -j JavaSign.dll -jp <br>
High -spc a:\Cert.spc -v <br>
a:\Key.pvk -n "My Applet" -i <Br>
http://www.mywebpage.com/ test.cab<br>

The flags here are a bit arcane. If you want your CAB file to request permisions, the -j flag should always be there, and take JavaSign.dll as a parameter, unless you're signing something other than Java code (the same command can be used to sign Active X controls and other mobile code too). The -jp flag passes a parameter to the DLL. For Java signing, that's how we request High privileges. The -spc flag and -v flag are used to specify the location of your certificate and private key, respectively. The -n option needs to be present, and it specifies the name of the software, which is displayed to the user before the user decides whether to run your code. The -i option specifies where to go for more information about the product, which also gets displayed when the user is prompted to give your code permission to run. You can also "timestamp" your signature, so that after your certificate expires, your applet will still work. However, doing so requires a timestamp server, which isn't covered here. For more information on Authenticode for Java, visit Trust-Based Security for Java.

To confirm that everything has worked properly so far, run the command:

chkjava test.cab

A window should appear similar to the one an end user will see when IE asks if the application should be allowed to run.

Making test certificates

To avoid putting down some cash for a real certificate from a CA and still be able to play around with Authenticode, you can make a test certificate. The first step is to create the certificate with the command:

makecert -sk Key.pvk -n "CN=Your Name" Cert.cer

That command makes a certificate and a private key you can use in other applications, but it won't work for code signing. To get it to work with code signing, convert it to a Software Publisher Certificate (SPC) by typing:

cert2spc Cert.cer Cert.spc

Now you can use Key.pvk and Cert.spc for testing purposes in the same way as if they came from a CA.



Special HTML tag

When deploying a signed CAB file in an HTML page, a slight variation on the APPLET tag is used. As with all applets, the name of the class that extends java.applet.Applet goes in the CODE attribute. However, instead of putting the name of the CAB file in the ARCHIVE attribute, where JAR files appear, Authenticode signed CAB files are passed using the PARAM tag. As an illustration, the tag to embed the signed applet "MyApplet" stored in myapp.cab into a Web page would look like:




The named parameter "cabbase" is how Internet Explorer finds the CAB file containing the class specified in the CODE attribute.

Using Microsoft's Client Storage API

It is possible to circumvent the need for a certificate for certain operations by using Microsoft's APIs. Here we'll show you how to use their Client Storage API, which will allow you to write up to a megabyte of data onto the hard disk of the machine running the applet, and later retrieve that data.

The Client Storage API comes with various Microsoft products, including Internet Explorer, so if you have IE installed, you can use it without downloading anything. If you use Microsoft's J++ environment, or just their Java compiler, those classes should be automatically available to you. If you use Sun's JDK, you will need to specify where those classes live before you can compile code that uses them. You should look for the Microsoft Java classes on your machine. On a Windows NT box, they will generally live in C:\WINNT\Java\Classes\classes.zip. You can confirm that the archive you found is the right one by opening it in WinZip or a similar product. If you see many com.ms classes, including com.ms.io.clientstorage, you've found the right archive.

To use these classes, you must have the archive in your class search path. Unfortunately, we've found that if you add those classes to your CLASSPATH variable directly, you are likely to find that your compiler no longer works. Fortunately, there's an easy way around the problem. When you compile an applet, specify the path to the zip file in the -classpath option as such:

javac -classpath C:\WINNT\Java
\Classes\classes.zip
test.java

Here's a simple example applet that will write the string "Hello, World!" to disk, and then read in the same string, drawing it to the applet:


import java.applet.*;
import java.awt.*;
import java.io.*;
import com.ms.io.clientstorage.*;
import com.ms.security.*;

public class AuthenticodeHelloWorld extends Applet{

  private String the_greeting;

  public void start(){ 

    // Tell the security system we want to use the client store.
    PolicyEngine.assertPermission(PermissionID.CLIENTSTORE);
    try {
      // Open scratch space and write into it.
      OutputStream os = ClientStorageManager.openWritable("scratch.txt");
      os.write("Hello, World!".getBytes());
      os.close();
    } catch(IOException ie) {
      the_greeting = "IOError: " + ie.toString();
      return;
    } catch (SecurityException se) {
      the_greeting = "denied: " + se.toString();
      return;
    }

    // Read in 13 bytes from a scratch file
    byte[] the_bytes = new byte[13];
    try {
      InputStream is = ClientStorageManager.openReadable("scratch.txt");
      is.read(the_bytes);
      is.close();
    } catch(IOException ie) {
      the_greeting = "IOError: " + ie.toString();
      return;
    } catch (SecurityException se) {
      the_greeting = "denied2: " + se.getMessage();
      return;
    }

    the_greeting = new String(the_bytes);
  }
 
  public void paint(Graphics g){
    g.drawString(the_greeting, 20, 20);
  }
}  

The above applet makes three calls to Microsoft APIs. The first call is a call to PolicyEngine.assertPermission to tell the security system that the applet needs to use the client store in order to operate as expected. If the applet can be extended permissions to use the client store based on the local security policy but hasn't been extended those permissions yet, the security system will do so when this call is made.

The second Microsoft API call is the call to ClientStorageManager.openWritable. This call gets an OutputStream object through which your applet can write into the scratch space. The final call to a Microsoft API is the call to ClientStorageManager.openReadable, which provides an InputStream object for reading from the scratch space.

The ClientStorage API can't give your applet access to any files that are outside the client store. Nonetheless, the API does offer a large range of file system functionality. For example, you can make directories, list files, and specify if other scratch space users can use your files. We won't cover this API in any more detail here, but full documentation can be found in Microsoft's Java SDK documentation.

Comparing Authenticode to Netscape Object Signing

Microsoft's Authenticode model is somewhat simpler than the Communicator model for the end user. Assuming the user doesn't know anything about zones, lots of stuff runs without asking the user for permission; the user is prompted only to approve code generally when the code requests full access and doesn't already have permission. Less interaction generally means less hassle for the user. You can make more dialog boxes disappear if you check boxes like, "always trust code from this person," and "always trust code from this site," which appear in the window that announces that code is trying to gain permissions. However, spreading trust around so easily just to avoid dialog boxes can have bad consequences.

Authenticode is also simpler for the developer. There's no need for calls to a capabilities library, meaning you can simply request an access level, as opposed to requesting a set of privileges. However, Netscape is capable of finer-grained access control, which allows the applet to secure only the resources it needs to run without a user feeling the need to give a program complete access to the computer before the applet can run.

Another convenience of Authenticode over Object Signing is that the user only gets prompted at most once per applet. Netscape prompts the user whenever new privileges are requested (which is usually during execution). While the Netscape model is more intrusive, it does afford the user a bit more control over what privilege is granted to an applet.

Resources

John Viega is a research associate at Reliable Software Technologies, in Sterling, Va. He holds an M.S. in Computer Science from the University of Virginia. He developed and maintains Mailman, the Gnu mailing list manager. His research interests include software assurance, programming languages, and object-oriented systems.

Tom O'Connor is a software engineer in the research division at Reliable Software Technologies. His interests are computer security and object-oriented software development.

Portions of this article will appear as an appendix in the forthcoming book Securing Java: Getting Down to Business with Mobile Code (John Wiley & Sons, 1998), the second edition of McGraw and Felten's book, Java Security: Hostile Applets, Holes, & Antidotes.


Share:
Home
Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved