This appendix shows you how to use the jarsigner
tool of the Java 2 platform to sign JAR files. It can also be used as a command-line reference for the jarsigner
tool.
A JAR file is a compressed archive file that is created using the Java archive tool (jar
), which is similar to the PKZIP program developed by Phil Katz. It combines multiple files into a single archive file that is compressed using the ZLIB compression library. Although jar
is a general-purpose file archive and compression tool, its main purpose is to combine the files used by an applet, application, or API into a single compressed file for efficient loading by a Java-enabled Web browser.
Using JAR files with applets can greatly improve browser performance. Because all the files used by an applet are combined into a single file, a browser needs to establish only a single HTTP connection with a Web server. This reduces the communication-processing overhead on both the browser and the server. File compression reduces the time required to download an applet by 50% or more. This benefits both the applet's user and publisher.
A description of the ZLIB compression format is available at the URL http://www.cdrom.com/pub/infozip/zlib/.
Another feature of JAR files is that they support the capability to sign archived files. This enables browsers to differentiate between untrusted applets and those applets that can be trusted to perform sensitive processing in a secure manner (because they are signed by a reputable identity). The sensitive processing that is permitted to trusted applets is determined by the local Java security policy.
The jar
tool is easy to use. You invoke it using the following command line:
jar [options] [manifest] jar-file input-file(s)
The jar-file
is used as an archive. The .jar
extension should be supplied in the command line. The input-file(s)
are written as a space-separated list of files to be placed in the archive. Filename wildcard characters may be used (for example, *.class
).
The manifest
is a file that contains information about the archived files. It need not be supplied—jar
will create it automatically and store it as META-INFMANIFEST.INF
within the archive. Information about the manifest file can be found in the file docsguidejarmanifest.html
that is included with the JDK 1.2 API documentation.
The jar
options
are used to control the input and output of the jar
tool. They are described in Table G.1.
Table G.1. Table G.1 The jar
Tool Options
If any of the specified files is a directory, the jar
tool will process the directory recursively—that is, all class files in that package and subpackage will be included.
The @
character may be used in a jar
command, followed by a filename. When this occurs, command arguments are taken from the file (one argument per line) and inserted into the command at the position of the @
character.
Examples of using the jar
tool are provided in the following sections.
If you have ever used the UNIX tar
command or the DOS PKZIP program, you will find the jar
tool familiar and easy to use. In this section, you'll learn how to create a JAR file for the ReadFileApplet
applet shown in Listing G.1.
I'll use the ReadFileApplet
applet because it uses two .class
files, which makes it a good candidate for archival and compression. Go ahead and compile it to produce ReadFileApplet.class
and ReadFileApplet$ButtonHandler.class.
Example G.1. The ReadFileApplet
Applet
import java.applet.*; import java.awt.*; import java.awt.event.*; import java.io.*; public class ReadFileApplet extends Applet { TextArea text = new TextArea(); Button goButton = new Button("Read Local File"); Panel panel = new Panel(); String fileName = ""; public void init() { fileName = getParameter("fileName"); setLayout(new BorderLayout()); goButton.addActionListener(new ButtonHandler()); panel.add(goButton); add("North",panel); add("Center",text); } class ButtonHandler implements ActionListener { public void actionPerformed(ActionEvent e){ String s = e.getActionCommand(); if("Read Local File".equals(s)){ try { FileInputStream inStream = new FileInputStream(fileName); int inBytes = inStream.available(); byte inBuf[] = new byte[inBytes]; int bytesRead = inStream.read(inBuf,0,inBytes); text.setText(new String(inBuf)); } catch(Exception ex){ text.setText (ex.toString()); } } } } }
Let's use jar
to archive and compress the *.class
files into a file named rfa.jar
:
jar cf rfa.jar ReadFileApplet*.class
You can use the list option of the jar
command to see what's inside the rfa.jar
file:
jar tf rfa.jar META-INF/ META-INF/MANIFEST.MF ReadFileApplet$ButtonHandler.class ReadFileApplet.class
The only thing that looks out of place is the META-INF/MANIFEST.MF
entry. That's the file used to keep a manifest of the JAR file's contents. Go ahead and delete ReadFileApplet.class
and ReadFileApplet$ButtonHandler.class.
You'll recreate them later in this chapter.
You're probably wondering how you would include the rfa.jar
file in an applet. The answer is that you add the ARCHIVE="rfa.jar"
attribute to the applet tag. This attribute tells the browser to load the rfa.jar
archive file to find the ReadFileApplet.class
file and other related classes. Listing G.2 shows the file ReadFileApplet.htm
that is used to display the ReadFileApplet
applet.
Example G.2. The ReadFileApplet.htm
File
<HTML> <HEAD> <TITLE>An Applet that reads local files</TITLE> </HEAD> <BODY> <H1>An Applet that reads local files.</H1> <APPLET CODE="ReadFileApplet.class" ARCHIVE="rfa.jar" HEIGHT=300 WIDTH=600> <PARAM NAME="fileName" VALUE="C:AUTOEXEC.BAT"> Text displayed by browsers that are not Java-enabled. </APPLET> </BODY> </HTML>
You can view the ReadFileApplet
applet using the appletviewer
tool, as follows (see Figure G.1):
appletviewer ReadFileApplet.htm
The applet displays a text box and the Read Local File button. The applet is designed to read the AUTOEXEC.BAT
file on Windows systems. However, if you click the Read Local File button, you'll receive an error message, as shown in Figure G.2. That's because the applet is not permitted to read any files. Later in this chapter, you'll use the jarsigner
tool to sign the applet and modify your security policy to allow the signed applet to read the AUTOEXEC.BAT
file.
NonWindows Users
If you are running Java on a nonWindows system, simply substitute another filename for AUTOEXEC.BAT
in Listing G.2.
The x
option of the jar
tool lets you extract the file's contents. You can use it to re-create the .class
files that you deleted:
jar xf rfa.jar
Note that the META-INF
directory is also created. This directory contains a single manifest file named MANIFEST.MF.
Delete the .class
files and the META-INF
directory before going on to the next section.
The next thing that you're going to do is to digitally sign the rfa.jar
file. Before you can sign the JAR file, you need to create a public/private key pair and make it available to the jarsigner
tool, in the form of a keystore entry. You'll use the keytool
(see Appendix F,"Using the Keytool," ) to create a keystore with the public/private key pair.
You can generate a public/private key pair for yourself using the -genkey
command of keytool.
For example, the following command generates a key pair for the alias "Jamie" in the default keystore:
keytool -genkey -alias "Jamie"
The keytool
then prompts you to enter a password for the keystore:
Enter keystore password: 123456
When you enter a password, keytool
prompts you for the following additional information:
What is your first and last name? [Unknown]: Jamie Jaworski What is the name of your organizational unit? [Unknown]: Software Development What is the name of your organization? [Unknown]: Jaworski & Associates What is the name of your City or Locality? [Unknown]: San Diego What is the name of your State or Province? [Unknown]: California What is the two-letter country code for this unit? [Unknown]: US Is <CN=Jamie Jaworski, OU=Software Development, O=Jaworski & Associates, L=San Diego, ST=California, C=US> correct? [no]: yes
Finally, you are prompted to enter a password for your private key:
Enter key password for <Jamie> (RETURN if same as keystore password):
I showed you how I filled in this information. You would enter your own information, of course. This information is used to associate an X.500 distinguished name with the alias.
If the -keystore
option is not supplied, keytool
generates a keystore named .keystore
that is stored in the directory specified by the user.home
system property.
Now that you have created a keystore with your public and private keys, you can use the jarsigner
tool and your private key to sign a JAR file. The jarsigner
tool is used for both signature generation and signature verification. I'll cover signature generation in this section and signature verification in the next section.
To sign a JAR file, you enter a jarsigner
command in the following form:
jarsigner [-keystore keystore] [-storepass storePassword] -keypass keyPassword JARFileName alias
The parameters to this command are as follows:
Additional command parameters are available for the jarsigner
command. Use jarsigner -help
to obtain a description of these parameters:
jarsigner -help Usage: jarsigner [options] jar-file alias jarsigner -verify [options] jar-file [-keystore <url>] keystore location [-storepass <password>] password for keystore integrity [-storetype <type>] keystore type [-keypass <password>] password for private key (if different) [-sigfile <file>] name of .SF/.DSA file [-signedjar <file>] name of signed JAR file [-verify] verify a signed JAR file [-verbose] verbose output when signing/verifying [-certs] display certificates when verbose and verifying [-internalsf] include the .SF file inside the signature block [-sectionsonly] don't compute hash of entire manifest [-provider] name of cryptographic service provider's master class file
I used the following command to sign the rfa.jar
file:
jarsigner rfa.jar "Jamie" Enter Passphrase for keystore: 123456
If the -keystore
option is not specified, the default (.keystore
) keystore is used. If the keystore password is not supplied, you are prompted to enter this password.
Signing a JAR file causes the JAR file to be updated as follows:
A signature (.SF
) file is added to the META-INF
directory. The name of this signature file is the first eight characters of the alias used to sign the file. This name can be changed using the -sigFile
option.
A signature block file (.DSA
) file is added to the META-INF
directory. The name of the signature block file is generated in the same way as the signature file.
The signature file identifies each file in the JAR file, the digest algorithm used in the signing process, and a
digest value. The digest value is the digest computed from the file's entry in the manifest file. Listing G.3 provides an example signature file.
Example G.3. A Sample Signature File
Signature-Version: 1.0 SHA1-Digest-Manifest: LrVFCFftXCITdMRYZKie/E0GWBg= Created-By: 1.2.2 (Sun Microsystems Inc.) Name: ReadFileApplet$ButtonHandler.class SHA1-Digest: TTx0UYjUot7EujvpWi9Ug1UdKUQ= Name: ReadFileApplet.class SHA1-Digest: K8SfTC5qVpG0dxTEE5hQy4K1t40=
The signature block file contains the signature of the signature file and a certificate that authenticates the public key corresponding to the private key used in the signature generation. The signature block file is a binary file.
The jarsigner
tool is also used to verify the signature of a signed JAR file. This is accomplished using the -verify
option. The following jarsigner
command form is used:
jarsigner -verify JARFileName
For example, the following command verifies the signature of edit.jar
:
jarsigner -verify edit.jar
If the signature is valid, jarsigner
produces the following output:
jar verified.
If the signature is invalid, jarsigner
responds with an exception identifying why the failure occurred:
jarsigner: java.util.zip.ZipException: invalid entry size (expected 900 but got 876 bytes)
The jarsigner
signature verification process is optimized for performance. This process consists of the following:
Verifying that the signature block (.DSA
) file contains a valid signature for the signature (.SF
) file.
Verifying that the signature file entries are valid digests for each of the corresponding manifest (MANIFEST.MF
) file entries.
Verifying that the digests in the MANIFEST.MF
file are valid for each of the files in the JAR file.
Any error encountered in the verification process results in the generation of a security exception.
The signing of JAR files provides the basis for developing an applet security policy. JAR files that are received from trusted sources whose signatures can be verified may be given greater privileges than JAR files that are unsigned or come from an untrusted source. In this section, I'll show how to update the default applet security policy (based on digital signatures) to permit ReadFileApplet
to read your AUTOEXEC.BAT
file.
The default security policy is defined in the java.policy file located in the java.homelibsecurity directory, where java.home refers to the value of the java.home
system property. To grant permission for the ReadFileApplet
applet in rfa.jar
to access AUTOEXEC.BAT
, I added the following lines at the beginning of java.policy
:
keystore "file:/C:/Windows/.keystore"; grant { permission java.io.FilePermission "/AUTOEXEC.BAT", "read", signedBy "Jamie"; };
The first line specifies that my default keystore (located at C:Windows.keystore
) should be used. The grant statement specifies that permission to read C:AUTOEXEC.BAT
should be granted to code that is signed by Jamie.
Now use appletviewer
to run ReadFileApplet
with the new policy:
appletviewer ReadFileApplet.htm
Click the Read Local File button. The appletviewer
displays your AUTOEXEC.BAT
file, as shown in Figure G.3.
18.217.182.45