Java security evolution and concepts, Part 3: Applet security

Tackle Java applet security with confidence

Java's early growth was spurred by code downloadable over a network, better know as applets. Applet security has evolved with the growth of Java, and today is a source of frequent confusion due to the variety of Java versions, commercially available browsers, and plug-ins.

This article, the third in the series, will cover the various requirements for securely running Java code downloaded from a network. Although mobile code is not a revolutionary concept, Java and the Internet present some unique challenges to computer security. The evolution of the Java architecture and its impact on core Java security was discussed in Parts 1 and 2. This article takes a different tack: a hands-on approach to tie all the concepts together by deploying a simple applet that writes to the local filesystem.

Java security evolution and concepts: Read the whole series!

At the example applet's core is public-key cryptography, introduced earlier in this series. Code signed using the private key of the signer can be run on client machines once the public key corresponding to the signer is deemed as trusted on the respective machine. We'll also discuss how policy files, which accord permissions and keystore, can be used as a repository for public and private keys. Moreover, we'll highlight the Java 2 SDK security tools and Netscape's signtool, since they enable deployment.

This article traces the evolution of Java security, beginning with application security in the initial release of Java 2 and moving on to the latest version of Java 2, version 1.3. This approach helps introduce the concepts gradually, starting with very simple concepts and culminating in a fairly advanced example.

This series does not intend to provide a comprehensive guide to computer security. Computer security is a multifaceted issue touching several disciplines, departments, and cultures. Investments in technologies should be followed up with investments in personnel training, strict enforcement of policies, and periodic review of the overall security policy.

Note: This article features a running Java applet designed to demonstrate applet security issues. Read below for more details.

Application security

Let's begin our investigation by looking at application security. In Part 2 we saw how Java security has evolved from a sandbox model to a fine-grained security model. We also saw that applications (local code) by default get a free reign and are not subject to the same control as applets (network-downloadable code), which are typically deemed as untrusted. In a change from the past, in Java 2 security applications can be optionally subject to the same level of control as applets.

First, a quick note about writeFile.java, the code used in this article to illustrate the security features in Java 2. This program is a slightly modified version of the applet code provided by Sun, available over the Web to illustrate some of the features of Java 2 security. The program, modified to provide application support, attempts to create and write a file on the local filesystem. Access to a local filesystem is screened by the security manager. We will see throughout this article how this particular operation can be permitted in a secure manner.

/**
  * By default, this raises a security exception as an applet.
  *
  * With JDK 1.2 appletviewer, 
  *  if you configure your system to grant applets signed by "Duke"
  *  and downloaded from the Java Software Website to write a file
  *  to your /tmp directory (or to the file named "C:\tmpfoo" on a 
  *  Windows system), then this applet can run.
  *  
  * @version JDK 1.2
  * @author  Marianne Mueller
  * @Modified by Raghavan Srinivas[Rags]
  */
import java.awt.*;
import java.io.*;
import java.lang.*;
import java.applet.*;
public class writeFile extends Applet {
    String myFile = "/tmp/foo";
    File f = new File(myFile);
    DataOutputStream dos;
  public void init() {
    
    String osname = System.getProperty("os.name");
    if (osname.indexOf("Windows") != -1) {
      myFile="C:" + File.separator + "tmpfoo";
    }
  }
  public void paint(Graphics g) {
     try {
         dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(myFile),128));
       dos.writeBytes("Cats can hypnotize you when you least expect it\n");
       dos.flush();
       dos.close();
       g.drawString("Successfully wrote to the file named " + myFile + " -- go take a look at it!", 10, 10);
     }
     catch (SecurityException e) {
       g.drawString("writeFile: caught security exception", 10, 10);
        }
     catch (IOException ioe) {
          g.drawString("writeFile: caught i/o exception", 10, 10);
        }
   }
    public static void main(String args[]) {
     Frame f = new Frame("writeFile");
     writeFile     writefile = new writeFile();
     writefile.init();
     writefile.start();
     f.add("Center", writefile);
     f.setSize(300, 100);
     f.show();
    }
}

Running the bytecode generated in a Java 2 Runtime Environment, Standard Edition (JRE) will let the application modify the file on the local filesystem by default, since the default policy does not subject Java 2 applications to a security manager. This policy is justified because applications are typically locally generated code and not downloaded over the network. The following command line produces the window shown in Figure 1, indicating that the file was created and written into.

$ java writeFile
Figure 1. writeFile Application -- no security manager

To subject the code to the Java 2 security manager, invoke the following command line, which should produce the results indicated in Figure 2. Notice that the application generated a security exception caused by an attempt to modify the local filesystem. The explicitly included security manager generated the exception.

$ java -Djava.security.manager writeFile
Figure 2. writeFile Application -- including the security manager

The cases illustrated above represent extreme examples of security policy. In the former case, the application was not subject to any control; in the latter, it was subject to a very rigid control. In most cases it will be necessary to set the policy somewhere in between.

You can accomplish an in-between policy using a policy file. To do so, create a policy file called all.policy in the working directory:

grant {
  permission java.io.FilePermission "<<ALL FILES>>", "write";
};

Running the same piece of code with the following command line will allow modification of the local filesystem:

$ java -Djava.security.manager -Djava.security.policy=all.policy writeFile

In this example, the application was subject to the security manager, but the overall policy was governed by the policy file, which allowed all files on the local filesystem to be modified. A stricter policy might have been to allow modification of only the relevant file -- tmpfoo in this case.

I'll cover more details of the policy file, including the syntax of the entries, later in this article. But first, let's look at applet security and contrast it with application security.

Applet security

So far, we've studied application security. As such, most of the security features can be accessed and modified via the command line. Providing an adequately secure and yet somewhat flexible policy in an applet environment proves substantially more challenging. We will start by looking at the deployment of an applet in Appletviewer. We'll look at browser-deployed applets later.

Java code policy is primarily dictated by CodeSource, which comprises two pieces of information: the place where the code originated and the person who signed it.

Appletviewer

Create a file called writeFile.html with the following contents:

<html>
<title> Java Security Example: Writing Files</title>
<h1> Java Security Example: Writing Files </h1>
<hr>
<APPLET  CODE = writeFile.class  WIDTH = 500 HEIGHT = 50 >
</APPLET>
<hr>
</html>

Running the applet with the following command line would result in the window shown in Figure 3:

$ appletviewer writeFile.html
Figure 3. appletviewer -- applets subject to security manager by default

Notice that -- in contrast to what would happen with an application -- the applet generated an exception since the applet is subject to the security manager by default. The installation can be governed by a customizable policy, if required. Running the following command line:

appletviewer -J"-Djava.security.policy=all.policy" writeFile.html

would, as you might expect, allow modification of the tmpfoo file, since this was permitted in accordance with the policy file.

Browsers

Applet security in browsers strives to prevent untrusted applets from performing potentially dangerous operations, while simultaneously allowing optimal access to trusted applets. Applet security deployment in browsers is substantially different from what we have seen so far, primarily due to the following reasons:

  • A default lack of trust in code downloaded over the network
  • Insufficient access to the command-line options for running the JVM, since the JVM is hosted in the context of a browser
  • Inadequate support for some of the latest security features in the JVMs bundled with browsers

As for the first problem, to obviate the potential problems resulting from running untrusted code, earlier versions of Java used the sandbox model (see "Sidebar 1: Sandbox Model"). Trust is a largely philosophical or emotional issue, rather than a technical issue; however, technology can help. For example, Java code can be signed using certificates. In this example, the signer implicitly vouches for the code by signing it. The onus is ultimately upon the user running the code to trust the signing entity or not, given that these certificates guarantee that the code was indeed signed by the intended person or organization.

The second problem stems from the lack of access to the options for running the JVM in the browser context. For example, there is no simple way to deploy and use customized policy files as we could in the previous example. Instead, such policies will have to be set by files based on the JRE installation. Customized class loaders or security managers cannot be installed easily.

The third problem, the lack of support for the latest versions of the JRE in the default JVM with the browser, is solved by using the Java plug-in (see "Sidebar 2: Java Plug-in Primer"). Indeed, an underlying issue is that modification of policy files is not very straightforward. Since applets may be deployed on thousands or even millions of client machines, there might be environments where users might not have a good understanding of security or may not be acquainted with methods for modifying the policy file. The Java plug-in provides a workaround, although it's recommended to use policy files wherever practical and applicable.

Next, we'll look in more detail at applet security involving code-signing examples in a browser environment with a Java plug-in. We will confine the discussion to Java plug-in version 1.3 unless explicitly stated otherwise.

The Java plug-in and security

The Java plug-in supports the standard Java 2 SDK, Standard Edition (J2SE), including the security model. All applets run under the standard applet security manager, which prevents potentially malicious applets from performing dangerous operations, such as reading local files. RSA-signed applets can be deployed using the Java plug-in. Additionally, the Java plug-in attempts to run applets in an identical way in both Netscape Navigator and Internet Explorer by avoiding browser-specific resources. This ensures that an RSA-signed applet will run identically in both browsers with the Java plug-in. The Java plug-in also supports HTTPS, a secure version of HTTP.

In order for a plug-in-enhanced browser to trust an applet and grant it all privileges or a set of fine-grained permissions (as specified in a J2EE policy file), the user has to preconfigure his or her cache of trusted signer certificates (the .keystore file in JRE 1.3) to add the applet's signer to it. However, this solution does not scale well if the applet needs to be deployed on thousands of client machines, and may not always be feasible because users may not know in advance who signed the applet that they are trying to run. Also, earlier versions of the Java plug-in supported code signing using DSA, which is not as widely prevalent as RSA.

A new class loader, sun.plugin.security.PluginClassLoader in the Java plug-in 1.3, overcomes the limitations mentioned above. It implements support for RSA verification and dynamic trust management.

The Software Development Kit (SDK) tools

The three tools dealing with security, available as part of the Java 2 SDK, are:

  • keytool -- Manages keystores and certificates
  • jarsigner -- Generates and verifies JAR signatures
  • policytool -- Manages policy files via a GUI-based tool

We will look at some of these tools' important options in the sections below. Refer to Resources for more detailed documentation associated with particular tools.

We will frequently refer to two system properties based on the system used and where the requisite software is installed. They are:

  • ${java.home}: refers to the location where the JRE is installed
  • ${user.home}: refers to the user's home directory

The actual values for these on my windows system, as an example, are C:\Program Files\JavaSoft\JRE\1.3 and C:\WINDOWS, respectively. The corresponding values on a Solaris system might be /files/j2sdk_1_3_0/jre and /home/raghavan, respectively.

All three tools use the keystore, a repository that stores keys and certificates for the installation. Entries are accessed by unique names referred to as aliases.

keytool

keytool manages the keystore -- for example, it can:

  • Create public/private key pairs
  • Issue certificate requests (sent to the appropriate Certification Authority)
  • Import certificate replies (obtained from the Certification Authority you contacted)
  • Designate public keys belonging to other parties as trusted

keytool currently handles X.509 certificates, although other formats can be supported by adding the respective providers. The Java Secure Socket Extension (JSSE) 1.0.2, for example, adds limited support to pkcs12. Different formats can be specified via the -storetype option in the command line.

keytool allows users to specify any key-pair generation and signature algorithm supplied by any of the registered cryptographic service providers via the -keyalg and -sigalg command-line options, respectively. The key size can be specified via the -keysize option.

Other useful options for keytool are listed in Table 1.

Table 1. Selected keytool options
OptionDescription
-genkey Generates a key pair (a public key and associated private key) 
-import Reads the certificate or certificate chain and stores it in the keystore entry identified by alias 
-certreq Generates a Certificate Signing Request (CSR), using the pkcs10 format 
-export Exports a certificate associated with the alias 
-list Prints the contents of the entire keystore or the specified alias 
-storepasswd Changes the password used to protect the integrity of the keystore contents 
-keypasswd Changes the password under which the key identified by alias is protected 
-delete Deletes entries from the keystore 

The following command, using the RSA algorithm, will generate a key that is valid for 750 days. The command will store the key as an alias rags in the default keystore -- .keystore -- in the home directory (or, more precisely in the directory that is resolved by the system property ${user.home}, as explained earlier):

C:signtool> keytool -genkey -alias rags -keyalg rsa -validity 750
Enter keystore password:  
What is your first and last name?
  [Unknown]:  Raghavan Srinivas
What is the name of your organizational unit?
  [Unknown]:  MDDR
What is the name of your organization?
  [Unknown]:  Sun Microsystems
What is the name of your City or Locality?
  [Unknown]:  Burlington
What is the name of your State or Province?
  [Unknown]:  MA
What is the two-letter country code for this unit?
  [Unknown]:  US
Is >CN=Raghavan Srinivas, OU=MDDR, O=Sun Microsystems, L=Burlington, ST=MA, C=US
> correct?
  [no]:  yes
Enter key password for <rags>
        (RETURN if same as keystore password):  

The following illustrates a X.509 certificate that I got back from the CA.

C:\signtool> type rags.cer
-----BEGIN CERTIFICATE-----
MIIDSDCCArGgAwIBAgIDB8CTMA0GCSqGSIb3DQEBBAUAMIHEMQswCQYDVQQGEwJaQTEVMBMGA1UE
CBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xHTAbBgNVBAoTFFRoYXd0ZSBDb25z
dWx0aW5nIGNjMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMRkwFwYD
VQQDExBUaGF3dGUgU2VydmVyIENBMSYwJAYJKoZIhvcNAQkBFhdzZXJ2ZXItY2VydHNAdGhhd3Rl
LmNvbTAeFw0wMDEyMTMyMTE4MzhaFw0wMTEyMjEyMjIwMjJaMIGPMQswCQYDVQQGEwJVUzELMAkG
A1UECBMCTUExEzARBgNVBAcTCkJ1cmxpbmd0b24xHTAbBgNVBAoTFFJhZ2hhdmFuIE4uIFNyaW5p
dmFzMSAwHgYDVQQLExdTdW4gTWljcm9zeXN0ZW1zIChNRERSKTEdMBsGA1UEAxMUUmFnaGF2YW4g
Ti4gU3Jpbml2YXMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMIZayo84gLZ+Lfe/rR5Tx5p
qIBuywwMVwc7lh2iwFc80JJJH8HrZspeQ1X8ixkT0az1rFQtVcM7KmuPGU6Xn4bl/ZLNG45L5KD2
PjNn565YJUP1gIjRtIWhZucuVvQU2b08dvgsLFBL6QhlxIcInTeqtz4C0RHPHviwroPhrMapAgMB
AAGjezB5MB8GA1UdJQQYMBYGCCsGAQUFBwMDBgorBgEEAYI3AgEWMBEGCWCGSAGG+EIBAQQEAwIE
EDAdBgNVHQQEFjAUMA4wDAYKKwYBBAGCNwIBFgMCB4AwFgYDVR0RBA8wDYILd3d3LnN1bi5jb20w
DAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQQFAAOBgQAyKVQucm4GlINqao2LD0OBQe5Vc47/NguS
/KL6jigW0ojkBJW31FmArtiMT9TpHx6E0qhLZrHcFPqcwdU1Ujr1WUox14tk3UHofOax2BQFHol/
uEw5HVbD+3qtSxMomGPkiDKewhkApKBrdMjWW7Z6dt8o7th3BOfZtynEbQf85A==
-----END CERTIFICATE-----

The public key created above can be imported into a keystore to enable trusting code that is signed by the private key corresponding to the public key.

C:\signtool> keytool -v -printcert -file rags.cer
Owner: CN=Raghavan N. Srinivas, OU=Sun Microsystems (MDDR), O=Raghavan N. Srinivas, L=Burlington, ST=MA, C=US
Issuer: EmailAddress=server-certs@thawte.com, CN=Thawte Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
Serial number: 7c093
Valid from: Wed Dec 13 16:18:38 EST 2000 until: Fri Dec 21 17:20:22 EST 2001
Certificate fingerprints:
         MD5:  34:6C:32:F9:2E:0D:0D:B3:99:13:FC:EC:F3:D9:8B:AF
         SHA1: 77:5D:D9:EC:62:4D:C7:47:D9:58:05:73:B9:34:60:F6:38:A8:36:94

The following command lists the keys in the keystore, which indicates that it's the default type -- Java Key Store (jks). Other formats, such pkcs12, can be used as well; however, they require that JSSE be installed.

C:\signtool> keytool -list -keystore writeFile.keystore
Enter keystore password:  
Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry:
rags, Thu Dec 14 12:39:31 EST 2000, trustedCertEntry,
Certificate fingerprint (MD5): 34:6C:32:F9:2E:0D:0D:B3:99:13:FC:EC:F3:D9:8B:AF

jarsigner

The jarsigner tool accesses a keystore created and managed by keytool, when it needs to find the private key and its associated certificate chain to use for signing a jar file. Since passwords protect access to the keystore and to private keys, only people who know the passwords will be able to access the key and use it to sign a jar file. The jarsigner tool prompts for needed passwords.

Some useful options for jarsigner are listed in Table 2.

Table 2. Selected jarsigner options
OptionDescription
-storepass Specifies the required password to access the keystore during signing 
-keypass Specifies the password used to protect the private key of the keystore alias entry 
-signedjar Specifies the name to be used for the signed jar file 
-verify Jar file verification 
-verbose Output extra information as to the progress of the jar signing or verification 
-certs Used in conjunction with -verify and -verbose options, the output includes certificate information for each signer of the jar file 

Note: in this article's code examples, I did not use jarsigner to sign the files; instead, I used Netscape's signtool.

policytool

The policytool command creates and modifies the external policy configuration files that define the installation's security policy. This tool has a graphical user interface, with which you select buttons and other options rather than type in commands as you would with the other tools. The tool modifies a regular text policy file. For default policy implementation and policy file syntax, see Resources.

Figure 4 below shows the top-level window used to specify the location of the policy file and the keystore. If the policy file does not exist, an empty file may need to be created before using this tool. The window also displays the different entries.

Figure 4. policytool: modify the locations of the keystore and the policy file Click on thumbnail to view full-size image (14 KB)

Figure 5 below shows the next step of adding or modifying a policy entry. You may set the CodeBase and the SignedBy properties in this window.

Figure 5. policytool: CodeBase and SignedBy properties Click on thumbnail to view full-size image (15 KB)

Finally, Figure 6 illustrates how permissions can be added or modified.

Figure 6. policytool: setting permissions

The file {java.home}/lib/security/java.security by default contains two policy files -- {java.home}/lib/security/java.policy and {user.home}/.java.policy. policytool typically modifies the latter file.

Later, we will see several examples of how to modify policy files; this can be accomplished either with the policytool or a text editor. policytool does the validation (enforces the syntax, checks for keys in the keystore, and so on), a considerable advantage.

Netscape's signtool for object signing

Like jarsigner, Netscape's signtool is a stand-alone command-line tool that creates digital signatures and uses the Java Archive (JAR) format to associate them with files in a directory. Some useful options for signtool are listed in Table 3.

Table 3. Selected signtool options
OptionDescription
-d certdir Specifies your certificate database directory containing key3.db and cert7.db files  
-G nickname Generates a new private-public key pair and corresponding object-signing certificate with the given nickname 
-k key Specifies the nickname (key) of the certificate you want to sign with 
-l Lists signing certificates, including issuing CAs; specifies invalid or expired certificates 
-L Lists the certificates in your database. An asterisk appears to the left of the nickname for any certificate that can be used to sign objects with signtool 
-v archive Verifies the cryptographic integrity of the archive 
-w archive Displays the names of signers of any files in the archive 
-Z jarfile Creates a jar file with the specified name 

Several examples of signtool commands are illustrated later.

Applet Deployment under Java 2 version 1.2

Instructions for running a Java 2, version 1.2 applet, including source code, is available from http://java.sun.com/security/signExample12/.

Without repeating Sun's instructions here, let's summarize what happened when we followed them:

  • We discovered that applets can be deployed for plug-in support by using the Java plug-in HTML converter (see Resources).
  • By default, the applet generated a security exception due to the restrictions placed on downloaded code.
  • We imported the public key corresponding to the key used to sign the code.
  • To overcome the restrictions placed, we provided permissions based on the URL and the signer.
  • Finally, we were able to run the code without generating an exception. In fact, the code runs identically on Netscape Navigator and Internet Explorer without any changes.

Be aware that to run applet code that is signed, we had to import the public key of the signer into the keystore before we could run the code. This may not always be feasible. Worse yet, the process of importing signatures to a number of client machines does not scale well. Both these issues have been fixed in version 1.3 of the Java plug-in.

Evolution to Java 2 version 1.3

To utilize a variety of security enhancements in the platform and the Java plug-in, we will try to upgrade the applet that we studied in the 1.2 environment to the 1.3 environment using the plug-in. Some of the enhancements in the platform include:

  • Full support for RSA signatures.
  • Full interoperation with Verisign's code-signing certificates. As such, keytool is now able to import Verisign certificates.

Some of the enhancements to the Java plug-in v1.3 include:

  • New support for RSA-signed applets, thus removing the need to distribute an identitydb.obj file to client machines.
  • Support for the standard Java 2 SDK, Standard Edition version 1.3 security model.

In the earlier example, we simply used signed code. However, it's more interesting to sign and deploy our own applet. With the armory of tools and the knowledge we have now obtained, we are more or less ready for the undertaking.

It's recommended that you delete earlier versions of the plug-in before installing a more recent version. However, I have not seen any major ill effects myself of not doing so. To be reasonably sure that you are running the right version of the plug-in, you may want to use the plug-in panel available via the Control Panel (in Windows).

Generate an RSA-signed applet

The first step in the process will be to sign the code; for this task, I used Netscape's signtool. To sign the code, we need an object- or code-signing certificate, specifically for Netscape. This procedure can vary depending on what Certifying Authority (CA) you use. An important distinction between 1.3 and 1.2: self-certified signatures that worked in 1.2 do not work in 1.3. Signatures must be certified by a standard CA in 1.3. The turnaround times are different, as they involve some form of physical checks. Also, there are different certificate classes. Finally, the process involves some form of payment -- typically in the hundreds of dollars. Typically, this process starts off by generating a key pair. The private key will be stored safely on a local disk or a smart card. The public key is then sent to the CA for certification. Most CAs will follow a manual procedure at this point to ascertain the identity of the signer before issuing a certificate. (For a list of CAs, see Resources.)

Eventually, you will receive a public key encapsulated as a certificate. The public key certificate needs to be imported into Netscape's database. This process can be done in a variety of ways depending on the format used to receive the certificate. You may use the Import A Certificate option in Certificates/Yours in the security window as seen in Figure 7 below. Or you may paste the certificate into a text file and then import it.

Figure 7. Netscape security window: manipulation of certificates Click on thumbnail to view full-size image (37 KB)

After installing the certificate, copy the relevant Netscape .db files to the signtool directory:

C:\signtool> copy c:"\Program Files\netscape\users\rags"\*.db
c:\Program Files\netscape\users\rags\cert7.db
c:\Program Files\netscape\users\rags\key3.db
c:\Program Files\netscape\users\rags\secmod.db

The files contain the keys and certificates needed to sign the code. The -l and -L options on signtool can be used to find certificates that can be used for code signing:

C:\signtool> signtool -l
using certificate directory: .
Object signing certificates
---------------------------------------
Sun Microsystems Inc.'s Thawte Consulting cc ID
    Issued by: Thawte Server CA (Thawte Server CA)
    Expires: Fri Dec 21, 2001
Raghavan N. Srinivas's Thawte Consulting cc ID
    Issued by: Thawte Server CA (Thawte Server CA)
    Expires: Fri Dec 21, 2001
Raghavan N. Srinivas's Sun Microsystems Inc ID
    Issued by: SMI Information Technology Test CA - Sun Microsystems Inc (SMI Information Technology Test CA)
    Expires: Fri Nov 24, 2000
---------------------------------------
For a list including CA's, use "signtool -L"
C:\signtool> signtool -L
using certificate directory: .
S Certificates
- ------------
  Verisign Class 1 Public Primary Certification Authority
  GlobalSign Primary Class 3 CA
  ValiCert OCSP Responder
  Verisign/RSA Commercial CA
  TC TrustCenter, Germany, Class 2 CA
  GlobalSign Primary Class 2 CA
  E-Certify Commerce ID
  Entrust.net Secure Personal CA
  TC TrustCenter, Germany, Class 3 CA
  Digital Signature Trust Co. Global CA 1
  Thawte Personal Freemail CA
  ValiCert Class 1 VA
  TC TrustCenter, Germany, Class 4 CA
  ValiCert Class 2 VA
  Verisign Class 3 Public Primary Certification Authority - G3
  Verisign/RSA Secure Server CA
  Thawte Personal Basic CA
  ValiCert Class 3 VA
  Verisign Class 4 Public Primary Certification Authority - G3
* Sun Microsystems Inc.'s Thawte Consulting cc ID
  GlobalSign Partners CA
  Equifax Secure CA
  Deutsche Telekom AG Root CA
  Sun Microsystems Inc TEST Root CA - GTE Corporation
  Digital Signature Trust Co. Global CA 2
  GTE CyberTrust Global Root
  GTE CyberTrust Root 3
  GTE CyberTrust Japan Secure Server CA
  VeriSign Class 4 Primary CA
  GTE CyberTrust Root 5
  GTE CyberTrust Japan Root CA
  TC TrustCenter, Germany, Class 0 CA
  Verisign Class 2 Public Primary Certification Authority - G2
  Verisign Class 3 Public Primary Certification Authority - G2
  GlobalSign Primary Class 1 CA
  Thawte Universal CA Root
  Entrust.net Premium 2048 Secure Server CA
* Raghavan N. Srinivas's Thawte Consulting cc ID
  GTE CyberTrust Root CA
  GTE CyberTrust Root 4
  American Express CA
  BelSign Object Publishing CA
  Verisign Class 1 Public Primary Certification Authority - G3
  Sun Microsystems Inc Test Root CA - GTE Corporation
  Sun Microsystems Inc TEST CA - Sun Microsystems Inc
  GTE CyberTrust Root 2
  TC TrustCenter, Germany, Class 1 CA
  Verisign Class 3 Public Primary Certification Authority
  Verisign Class 4 Public Primary Certification Authority - G2
  GlobalSign Root CA
  Personal Freemail RSA 1999.9.16 - Thawte Consulting
  Thawte Personal Premium CA
  SMI Information Technology Test CA - Sun Microsystems Inc
* Raghavan N. Srinivas's Sun Microsystems Inc ID
  BelSign Secure Server CA
  ABAecom (sub., Am. Bankers Assn.) Root CA
  American Express Global CA
  Equifax Premium CA
  E-Certify Internet ID
  Thawte Server CA
  Digital Signature Trust Co. Global CA 4
  Verisign Class 2 Public Primary Certification Authority - G3
  Verisign Class 2 Public Primary Certification Authority
  Digital Signature Trust Co. Global CA 3
  Verisign Class 1 Public Primary Certification Authority - G2
  Thawte Premium Server CA
  Entrust.net Secure Server CA
- ------------
Certificates that can be used to sign objects have *'s to their left.

Notice the *, which indicates a code-signing certificate. Next, sign the file and generate the jar file:

C:\signtool> mkdir writeFileDir
C:\signtool> copy writeFile.class writeFileDir
C:\signtool> signtool -k "Raghavan N. Srinivas's Thawte Consulting cc ID" -Z writeFile.jar writeFileDir
using certificate directory: .
Generating writeFileDir/META-INF/manifest.mf file..
--> writeFile.class
adding writeFileDir/writeFile.class to writeFile.jar...(deflated 44%)
Generating zigbert.sf file..
Enter Password or Pin for "Communicator Certificate DB":
Enter Password or Pin for "Communicator Certificate DB":
adding writeFileDir/META-INF/manifest.mf to writeFile.jar...(deflated 15%)
adding writeFileDir/META-INF/zigbert.sf to writeFile.jar...(deflated 27%)
adding writeFileDir/META-INF/zigbert.rsa to writeFile.jar...(deflated 36%)
tree "writeFileDir" signed successfully

Finally, verify the jar file:

C:\signtool> signtool -w writeFile.jar
using certificate directory: .
Signer information:
nickname: Raghavan N. Srinivas's Thawte Consulting cc ID
subject name: CN=Raghavan N. Srinivas, OU=Sun Microsystems (MDDR), O=Raghavan N. Srinivas, L=Burlington, ST=MA, C=US
issuer name: E=server-certs@thawte.com, CN=Thawte Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA

This certificate may be imported into the Java .keystore, if needed, using the following steps:

  1. Export the certificate as a pkcs12 format -- default Netscape support
  2. Use the .p12 file as a keystore of storetype pkcs12 -- supported by installing JSSE; alternatively, export out of the pkcs12 keystore and import into the default JKS keystore

The following command lists the keys in the pkcs12 keystore after the certificate was exported from the navigator:

C:\signtool> keytool -list -storetype pkcs12 -keystore rags.p12
Enter keystore password: 
Keystore type: pkcs12
Keystore provider: SunJSSE
Your keystore contains 1 entry:
raghavan n. srinivas's thawte consulting cc id, Thu Dec 14 13:25:44 EST 2000, keyEntry,
Certificate fingerprint (MD5): 

After the jar file has been successfully signed, we are ready to deploy the applet.

Deploy the applet

Having signed the code as highlighted in the previous step, we are now ready to deploy the applet -- almost. The deployment directory must contain the signed jar file and the HTML file for the code to be downloaded and run, as illustrated in the version 1.2 example earlier.

Move writeFile.jar to the deployment directory. The HTML file needs to work with version 1.3 of the Java 2 plug-in. The final writeFile.html in the deployment directory must look something like the code below. Notice that this is only a slight modification of the HTML file we used earlier with changes to incorporate the later version of the plug-in:

<html>
<title> Java Security Example: Writing Files</title>
<h1> Java Security Example: Writing Files </h1>
<hr>
Here's an applet that tries to write to the file <code>/tmp/foo</code>
on a Solaris system (or to the file <code>C:\tmpfoo</code> on a
Windows 95 or Windows NT system.)
<p>
<!--"CONVERTED_APPLET"-->
<!-- CONVERTER VERSION 1.0 -->
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
WIDTH = 500 HEIGHT = 50  codebase="http://java.sun.com/products/plugin/1.3/jinstall-13-win32.cab#Version=1,3,0,0">
<PARAM NAME = CODE VALUE = writeFile.class>
<PARAM NAME = ARCHIVE VALUE = "writeFile.jar">
<PARAM NAME="type" VALUE="application/x-java-applet;version=1.3">
<COMMENT>
<EMBED type="application/x-java-applet;version=1.3" 
java_CODE = writeFile.class java_ARCHIVE = "writeFile.jar" 
WIDTH = 500 HEIGHT = 50   pluginspage="http://java.sun.com/products/plugin/1.3/plugin-install.html">
<NOEMBED>
</COMMENT>
</NOEMBED></EMBED>
</OBJECT>
<!--
<APPLET  CODE = writeFile.class ARCHIVE = "writeFile.jar" WIDTH = 500 HEIGHT = 50 >
</APPLET>
-->
<!--"END_CONVERTED_APPLET"-->
<p>
and here's the <a href=writeFile.java>source</a>. 
<p>
This applet is a signed applet.
</center>
<hr>
</html>

Having deployed the applet, you are now ready to run it. Applets can be tested by deploying them initially on a local system. Eventually, they will need to be deployed in a Web server environment.

Run the applet

Having deployed the applet on the server, we are now ready to run it from the client. It's not necessary to have a Web server to test the deployment. It can be run from a filesystem using the file: protocol instead of http:.

Before running the applet, make sure that the policy files, ${java.home}/lib/security/java.policy and ${user.home}/.java.policy, do not accord any special permissions besides the default.

Point the browser at writeFile.html in the publicly available URL. If you do not have the latest version of the plug-in installed, you may have to go through the additional step of installing it. When users of the Java plug-in encounter an RSA-signed applet, the plug-in will verify that the applet is correctly signed, and that the RSA certificate chain and the root CA are valid. If these are all valid, the plug-in will pop up a security dialog explaining who signed the applet and providing four options, as shown in Figure 8. Depending on whether you trust the signer of the code, you could do one of the following:

  • Grant this session: If selected, the applet will be granted AllPermission. Any signed applet signed using the same certificate will be trusted automatically within the same browser session.
  • Deny: If selected, the applet will be treated as an untrusted applet.
  • Grant always: If selected, the applet will be granted AllPermission. Any signed applet signed using the same certificate will be trusted automatically in the future, and no security dialog will pop up when this certificate is encountered again. This decision can be changed from the Java plug-in control panel.
  • More Info: If selected, users can examine the attributes of each certificate in the certificate chain in the jar file.
Figure 8. Plug-in warning pop-up window Click on thumbnail to view full-size image (16 KB)

Once the user selects the options from the security dialog, the applet will run in the corresponding security context. All of these decisions are determined on the fly, and no preconfiguration is required.

All certificates trusted by the plug-in can be viewed from the plug-in panel, illustrated in Figure 9.

Figure 9. Plug-in trusted certificates Click on thumbnail to view full-size image (12 KB)

At this point you may ask, "If trusting the certificate grants complete access to the signed applet, where does the fine-grained security professed in Java 2 come in?"

In fact, the model does not seem a whole lot different from version 1.1. However, the plug-in default behavior can be overridden by specifying a new permission named usePolicy under RuntimePermission in the policy file. The pop-up dialog box serves a useful role for unsophisticated users and for temporary exceptions to the installed policy, but only at the sole discretion of the user.

Figures 10 and 11 show the applet running in Netscape Navigator on Solaris and Internet Explorer on Windows, respectively.

Figure 10. Applet in Netscape Navigator Click on thumbnail to view full-size image (63 KB)
Figure 11. Applet in Internet Explorer Click on thumbnail to view full-size image (26 KB)

The applet may be run from http://www.javaworld.com/javaworld/jw-12-2000/security/writeFile.html.

The policy file's role

Let's remove the trusted certificate from the Java plug-in control panel to understand the role of the policy file. Select the certificate in the plug-in control panel and hit Remove. Close the control panel and bring it up again to ensure that the certificate has indeed been deleted.

We will look at several policy instances to understand the interaction of the plug-in and the policy file in making access-control decisions. We saw an instance where the user selected the security context since the policy file did not contain any relevant entries.

Let's modify the policy file to contain the entry below:

grant {
  permission java.lang.RuntimePermission "usePolicy";
};

Now, run the applet as before. Notice that the pop-up dialog box does not appear due to the permission usePolicy in the policy file. The applet generated a security exception since there was nothing specified in the policy file to permit that operation. To explicitly provide that permission, add an entry to the policy file:

grant {
  permission java.lang.RuntimePermission "usePolicy";
  permission java.io.FilePermission "C:${/}tmpfoo", "write";
};

As you might expect, rerunning the applet will create and modify the file without popping up the dialog box.

Finally, let's remove the usePolicy entry in the policy file:

grant {
  permission java.io.FilePermission "C:${/}tmpfoo", "write";
};

The dialog box pops up again as expected and, regardless of what security context is chosen in the dialog box, the file will be modified. In other words, it does not matter if access was granted or denied. Why? The installation's policy is ultimately governed by the policy file. The pop-up dialog box should be used very selectively, especially in situations where it might be unreasonable to expect the user to modify the policy file. My mom would be a good example of such a user. Hopefully, she will trust me enough to provide access to an applet that I have signed and let me out of the sandbox.

In summary, the Java plug-in checks for the permission entry usePolicy and will pop up the dialog box described earlier only if that entry is not present. If that entry is present, the plug-in quietly accords permission based on the installation's policy. The policy file entry can override the security decisions made by the plug-in, thus permitting greater access. Of course, if the code is not signed, it's confined to the sandbox.

Fine-tuning the policy file

In the examples above, the policy was set at a very coarse level. You may want to fine-tune the policy to incorporate the origin of the code and the signer, as we saw in the example with Java 2.1.2.

As a first step, import the public-key certificate into the keystore.

C:\signtool> keytool -printcert -file rags.cer
Owner: CN=Raghavan N. Srinivas, OU=Sun Microsystems (MDDR), O=Raghavan N. Srinivas, L=Burlington, ST=MA, C=US
Issuer: EmailAddress=server-certs@thawte.com, CN=Thawte Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
Serial number: 7c093
Valid from: Wed Dec 13 16:18:38 EST 2000 until: Fri Dec 21 17:20:22 EST 2001
Certificate fingerprints:
         MD5:  34:6C:32:F9:2E:0D:0D:B3:99:13:FC:EC:F3:D9:8B:AF
         SHA1: 77:5D:D9:EC:62:4D:C7:47:D9:58:05:73:B9:34:60:F6:38:A8:36:94
C:\signtool> keytool -import -file rags.cer -alias rags
Enter keystore password: 
Owner: CN=Raghavan N. Srinivas, OU=Sun Microsystems (MDDR), O=Raghavan N. Srinivas, L=Burlington, ST=MA, C=US
Issuer: EmailAddress=server-certs@thawte.com, CN=Thawte Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
Serial number: 7c093
Valid from: Wed Dec 13 16:18:38 EST 2000 until: Fri Dec 21 17:20:22 EST 2001
Certificate fingerprints:
         MD5:  34:6C:32:F9:2E:0D:0D:B3:99:13:FC:EC:F3:D9:8B:AF
         SHA1: 77:5D:D9:EC:62:4D:C7:47:D9:58:05:73:B9:34:60:F6:38:A8:36:94
Trust this certificate? [no]:  yes
Certificate was added to keystore

Change the key and the origin of the code in the policy file to look something like this:

C:\signtool> type c:\windows\.java.policy
/* AUTOMATICALLY GENERATED ON Mon Dec 04 21:19:33 EST 2000*/
/* DO NOT EDIT */
keystore ".keystore", "jks";
grant signedBy "rags" codeBase "http://www.javaworld.com/jw-12-2000/security/writeFile.jar" {
  permission java.lang.RuntimePermission "usePolicy";
  permission java.io.FilePermission "C:${/}tmpfoo", "write";
};

The keystore is relative to the URL of the policy file. In this particular case, the keystore file -- .keystore -- is in the same directory as the policy file.

As alluded to before, fine-grained policy can be achieved by according separate permissions based on the CodeSource that comprises both the signedBy and codeBase properties. In the example above, permissions to write a file on the local filesystem are provided to the code based on its signature and its origin. Similarly, other permissions can be accorded in the policy file.

Automatic deployment of policy files

Looking at the role of policy file above, it seems like a chicken and egg problem -- if we could only modify the policy files, the policy files could then provide the optimal access to an applet that we deploy. It's unreasonable to expect unsophisticated users to modify their policy files. The user has to provide initial access for the applet to be able to modify the policy file anyway. Assuming this happens -- that is, even if the user grants access just for the session -- the applet can modify the policy file to provide the appropriate level of access to itself without popping up the dialog box in the future.

Given all this, is it a reasonable approach for an applet to modify the policy file directly without informing the user? I personally think that approach is akin to sneaking up behind an unsuspecting friend. The approach may not always work, especially when a similar approach is used by more than one applet. Also, the user may always modify the policy file explicitly in the future, invalidating some of the changes made. You may also lose some friends and business due to your covert action.

A more acceptable approach might be to deploy a separate applet that informs the user and updates the policy file with his or her consent, clearly outlining the potential risk in the operation. Since the initial step can happen only with the permission of the user, it's a reasonable way to work with the user to modify the policy file -- the applet aids the user in providing the necessary permissions via the policy file.

In intranet scenarios, separate policy files can be maintained for each applet. These can be added to the ${java.home}lib/security/java.security file via an entry which looks like this:

policy.url.3=http://www.javaworld.com/javaworld/jw-12-2000/security/writeFile.policy

For a Solaris or Linux system, add the following entry:

policy.url.3=http://www.javaworld.com/javaworld/jw-12-2000/security/writeFile-unix.policy

The writeFile.policy file's contents are:

/* AUTOMATICALLY GENERATED ON Fri Nov 10 17:07:18 EST 2000*/
/* DO NOT EDIT */
keystore "writeFile.keystore", "jks";
grant signedBy "rags" codeBase "http://www.javaworld.com/jw-12-2000/security/writeFile.jar" {
  permission java.lang.RuntimePermission "usePolicy";
  permission java.io.FilePermission "C:${/}tmpfoo", "write";
};

Correspondingly, the file contents of writeFile-unix.policy are:

/* AUTOMATICALLY GENERATED ON Fri Nov 10 17:07:18 EST 2000*/
/* DO NOT EDIT */
keystore "writeFile.keystore", "jks";
grant signedBy "rags" codeBase "http://www.javaworld.com/jw-12-2000/security/writeFile.jar" {
  permission java.lang.RuntimePermission "usePolicy";
  permission java.io.FilePermission "/tmp/foo", "write";
};

after the policy.url.1 and policy.url.2 entries. This policy will affect multiple users that run the plug-in from the same path. The content of all the policy files will be used to administer the overall policy.

Conclusion

In earlier articles, we discussed the different aspects of Java security, starting with its evolution. This article aimed to combine the concepts presented earlier with get-your-hands dirty applet code, a frequently misunderstood aspect of Java security. As we've seen, by signing the code once, the applet can be run identically on a variety of operating systems -- Linux, Solaris, and Windows -- and under a variety of browsers and browser versions. Keep in mind that code signing should not be construed as a silver bullet to solving all security problems. It's a critical link in the whole security chain.

In my next article in this series, I'll discuss the Java Security extensions, also referred to as optional packages. I'll also touch upon the Java 2 Platform, Enterprise Edition (J2EE) and RMI security, both of which take a different approach to security. Under these schemes, it is no longer left to the developer to assemble the building blocks to provide security; instead, the developer and the deployer share responsibility in providing overall system security with lesser emphasis on programming and more emphasis on customization via a declarative model.

Raghavan Srinivas is a Java technology evangelist at Sun Microsystems who specializes in Java and distributed systems. He is a proponent of Java technology who teaches graduate and undergraduate classes in the evening. Srinivas holds a master's degree in computer science from the Center of Advanced Computer Studies at the University of Southwestern Louisiana. He likes hiking, running, and traveling, but most of all loves to eat, especially spicy food.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies