Professional Java.JDK.5.Edition (Wrox)
.pdfChapter 14
Option Description
c |
This option is simply used to create a new archive. |
tThis option will list the table of contents for the archive file. This is a great way to inspect the contents of the JAR file right after you have created it to make sure it was created successfully and the way you anticipated.
Note: The f option is usually combined with the t option to reduce the amount of typing you have to do.
x |
This option is used to extract the specified files or all the files from the JAR file. |
uThis option allows you to update a JAR file with specified new or changed files. It is more likely that you will use a tool that knows how to update a zip file format or an IDE that can update JAR files for you because this task can be quite cumbersome if you have a lot of files to update.
vThe verbose option allows you to get more feedback from the JAR tool as it creates the JAR. It is very helpful when debugging issues.
f |
This option specifies that the JAR file to update is on the command line. |
mThis option signifies that you are supplying the JAR tool with a manifest file that is to be included in the JAR.
0The zero option tells the JAR tool to not compress the files and just package them into the archive.
MThis option prevents the default manifest file from being created. Manifest files are optional in JAR files.
iOne of the new features in Java 5, this option is used to generate index information for the JAR file into its META-INF directory under the file named INDEX.LIST.
C [DIR] |
This option instructs the JAR tool to change the directory to the one specified and to |
|
JAR the files that are being referenced. |
Now it is time to show you just how easy it is to create a JAR file. This example will contain two Java files and an images directory. Normally, the Java files would be compiled into classes, and the source code would be removed, but this example simply demonstrates how almost any type of file can be contained in a JAR file. Figure 14-1 shows the directory structure prior to issuing a JAR command.
626
Packaging and Deploying Your Java Applications
|
images |
chess |
board.bmp |
|
W# Chess.java
W# ChessGUI.java
Figure 14-1
Once you know the files and directories you want to archive, you can issue a JAR tool command with the options cvf from the root directory and literally compress the entire chess directory as well as any subdirectories under it. The c option is used to create the archive, the v option specifies verbose, and the f option signifies that you will be supplying the name of the JAR file to create on the command line. Here is an example of the JAR tool in action:
C:\>jar -cvf chess.jar chess added manifest
adding: chess/(in = 0) (out= 0)(stored 0%)
adding: chess/Chess.java(in = 0) (out= 0)(stored 0%) adding: chess/ChessGUI.java(in = 0) (out= 0)(stored 0%) adding: chess/images/(in = 0) (out= 0)(stored 0%)
adding: chess/images/board.bmp(in = 0) (out= 0)(stored 0%)
The chess.jar file is now created and contains all the files under the C:\chess directory. There is a default manifest file that was automatically generated by the JAR tool in the META-INF directory of the JAR file. It contains nothing more than a version string. Figure 14-2 shows the new JAR structure.
|
|
images |
chess |
|
board.bmp |
|
|
|
W# |
Chess.java |
|
W# |
ChessGUI.java |
meta-inf |
Manifest.mf
Figure 14-2
627
Chapter 14
You can also use the JAR tool to see the contents of the chess.jar file by specifying the t option on the file. Here is an example of how to view the table of contents of a JAR file:
C:\>jar -tf chess.jar META-INF/ META-INF/MANIFEST.MF chess/
chess/Chess.java
chess/ChessGUI.java
chess/images/
chess/images/board.bmp
Besides viewing the contents of a JAR file, you can also extract the contents of the JAR file. This may be necessary if you ever get into a situation when you need to unpack the JAR to patch or edit files in the JAR file. To extract a JAR file, you will need to specify the x option. In this example, the xvf options are used. Refer to the option table in this section for more information on options and their uses:
C:\>jar -xvf chess.jar created: META-INF/
inflated: META-INF/MANIFEST.MF created: chess/
extracted: chess/Chess.java extracted: chess/ChessGUI.java
created: chess/images/ extracted: chess/images/board.bmp
The command simply extracts the JAR file to the current working directory. Now you can edit the files and repackage them if need be.
Examining the Basic Manifest File
The manifest file can be thought of as a file that contains meta data information about the JAR file it belongs to. By using the manifest file, you can version control, digitally sign, and seal the JAR files, packages, and extensions. When you first create your JAR file, if you didn’t specify the -M option, a default manifest will be created for you. The M option prevents the default manifest file from being created. The default manifest file looks something like this, depending on the version of Java you are using:
Manifest-Version: 1.0
Created-By: 1.5.0 (Sun Microsystems Inc.)
The manifest file is broken up into two general parts: a main section and an individuals section where information about different files or packages can be listed. You don’t have to list every file you have in the JAR file in the manifest file. In fact, you don’t have to list any unless you plan to sign particular files in the JAR file. If you do, then those files must be listed.
628
Packaging and Deploying Your Java Applications
Information in the manifest is broken up by name-value pair entries. The colon (:) character is used to separate the name from the value. This is similar to property files except for, in property files, the delimiter is an equals (=) sign. Any attributes that Java can’t understand are ignored, but the attributes can still be used by the application. Therefore, these attributes are sometimes referred to as application-specific attributes. The following table describes several of the most common main attributes you will run across and gives a brief description of each.
Attribute |
Description |
|
|
Manifest-Version |
The value of this attribute is the manifest file version. |
Created-By |
Generated by the JAR tool, this is the version of Java that was used to cre- |
|
ate the JAR. It also includes the name of the vendor who created the Java |
|
implementation. |
Signature-Version |
The value of this attribute contains the signature version of the JAR file and |
|
must contain a valid version number string with this specific format: |
|
digit+{.digit+}* |
Class-Path |
The class loader uses this value to create an internal search path that will |
|
look for extensions or libraries that this application needs. URLs are sepa- |
|
rated by spaces. |
Main-Class |
This attribute is needed if you are creating a self-executing JAR file. You |
|
need to specify the name of the class file that contains the main method. |
|
When you specify the name, do not include the .class extension, or your |
|
JAR will not execute. |
Sealed |
This attribute has only two possible values: true or false. If true, all the |
|
packages in the JAR file are sealed unless they are defined individually to |
|
be different. |
|
|
Though the manifest is not a very exciting file to read about, it definitely is worth exploring so that you have a general understanding of the power and flexibility it provides JAR files with.
Examining Applets and JARs
One of the most common uses for JAR files is to bundle applet code inside of JAR files and make them accessible, like any other applet via a Web browser. Because of this feature, a special attribute called an extension in the manifest can be used to incorporate other packages in your applets. For more information on applets, see the “Analyzing Applets” section within this chapter.
Here is a list of the extension attributes that can be used to optimize your applets.
629
Chapter 14
Attribute |
Description |
|
|
Extension-List |
This attribute is where you list the optional packages |
|
that you would like to include in your applets. The |
|
package names should be separated by a single |
|
space. |
(extension)-Extension-Name |
The unique name of the package that the Java plug- |
|
in will use to determine if the package is installed is |
|
stored in this attribute. |
(extension)-Specification-Version |
This attribute lets the Java plug-in know which is the |
|
minimum version required of the package to use. |
(extension)-Implementation-Version |
This attribute lets the Java plug-in know which is the |
|
minimal version of the package that is required. If |
|
the version is too old, the plug-in will attempt to |
|
download a newer version of the package. |
(extension)-Implementation-Vendor-Id |
This attribute is used to assign a vendor ID to the |
|
optional package. Again, the Java plug-in will com- |
|
pare the vendor IDs to make sure it is getting the |
|
correct optional package. |
(extension)-Implementation-URL |
In order for the Java plug-in to know where to get |
|
the latest version of the package, this attribute |
|
would have to be set with the URL that tells the |
|
Java plug-in where to download the latest optional |
|
package. |
|
|
Signing JAR Files
Signing JAR files is important for security-aware applications. It ensures that the JAR file has not been tampered with and the file is from the original author. JAR files are signed using a special utility tool called jarsigner, which can be found in your JAVA_HOME/BIN directory. JAR files can also be signed by using the java.security API via code. The jarsigner tool signs the JAR files by accessing a keystore that has been created by the keytool utility that is used to create public and private keys, issue certificate requests, import certificate replies, and determine if public keys belonging to third parties are trusted. The private key is used to sign the JAR file by the jarsigner tool, and only people who know the private key’s password can sign the JAR file with it.
When a JAR file is signed by the jarsigner tool, all of the entries in the META-INF directory are signed. Even nonsignature-related files will be signed. Generally speaking, signature-related files end in the following extensions: *.RSA, *.SF, *.DSA, and SIG-*.
You can sign the JAR file using the Java.security API; however, compared to using the jarsigner tool, there will be a lot more work for you to do. When a JAR file is successfully signed, it must contain an updated manifest file, signature file, and signature block file. Entries for each file signed are created in the manifest file and look like the following example:
Name: com/wrox/SampleSigned.class
SHA1-Digest: fcavHwerE23Ff4355fdsMdS=
630
Packaging and Deploying Your Java Applications
Now that you know the theory about JAR signing, it is time to show you a concrete example of how to sign a JAR and use all the wonderful tools that the Java SDK provides you with. Note that all these tests will not be with valid certificates or keystores; rather, it will be example keystores that you will create for testing purposes. This is great when you need to develop applications that require you to sign JAR files but don’t have access to a certificate or keystore. The following example will show you how to use the keytool to generate a keystore and create a self-signed test certificate that you can use with the jartool to sign the chess.jar file that you created earlier in this chapter.
The first thing you want to do is create a keystore that you can use for creating a self-signed certificate. The following are the steps involved in generating the key:
1.Execute the keytool as shown. This will create a myKeystore file that will contain your key:
C:\>keytool -genkey -keystore myKeystore -alias myself
2.It will prompt you to enter a password for the keystore. Simply enter password:
Enter keystore password: password
3.Next, you will be asked to fill in several lines of data about yourself. Here is what you enter to generate the key:
What is your first and last name? [Unknown]: John Doe
What is the name of your organizational unit? [Unknown]: IT
What is the name of your organization? [Unknown]: Wrox
What is the name of your City or Locality?
[Unknown]: Springfield
What is the name of your State or Province? [Unknown]: Ohio
What is the two-letter country code for this unit? [Unknown]: US
Is CN=John Doe, OU=IT, O=Wrox, L=Springfield, ST=Ohio, C=US correct? [no]: Yes
4.The last step is to enter a password for the private key. Here, you’ll see the word password entered again:
Enter key password for <myself>
(RETURN if same as keystore password): password
Your new myKeystore file should be generated. You can open it up and view it in a text editor if you want, but the majority of the contents are encrypted. Even though you have a keystore, you still cannot sign a JAR file until you have a certificate that you can use for signing. Fortunately, the keytool is able to generate a self-signed certificate for you. This is simply done by issuing the following command:
C:\>keytool -selfcert -alias myself -keystore myKeystore
631
Chapter 14
This command will prompt you for your keystore password. When you created the keystore, you made it using the word password as your password so that is what you should enter. This command can sometimes take a minute or two to complete, depending on your system:
Enter keystore password: password
You now have a certificate and are ready to sign the JAR file. However, how do you know for sure that the certificate and the keystore are okay? The easiest way is to issue a keytool command with the option -list on the command line. This will display the contents of the keystore. Here is the output of the command:
C:\>keytool -list -keystore myKeystore
Enter keystore password: password
Again, you have to enter your password to access the information in the keystore. The output after entering your password is shown in the following example:
Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry
myself, Jul 21, 2004, keyEntry,
Certificate fingerprint (MD5): 96:0B:2C:20:EA:DB:87:7A:64:DA:9F:68:21:85:B6:9A
The output shows the type of keystore you are using, the provider, and the certificate fingerprint. If you get the above printout, you are ready to sign the JAR file. In order to sign the JAR file, you must now use the jarsigner tool. Taking the keystore you generated earlier, issue the following command at a command prompt:
C:\>jarsigner -keystore myKeystore chess.jar myself
Enter Passphrase for keystore: password
Warning: The signer certificate will expire within six months.
You have now successfully signed your first JAR file! To verify that the jarsigning tool successfully signed the JAR file that you specified, extract the JAR file and review its contents. You should now see two new files in the JAR file: one called Myself.dsa and the other called Myself.sf. The .dsa (digital signature) file is unreadable, but the .sf file can be read. The contents of it are shown in the following example:
Signature-Version: 1.0
Created-By: 1.5.0 (Sun Microsystems Inc.)
SHA1-Digest-Manifest-Main-Attributes: XpKykodQ7e3bKKW8wqLFO8VocOU=
SHA1-Digest-Manifest: eL4xJ2eU5oyO7h4VVYW0hs1pEj0=
Name: chess/images/board.bmp
SHA1-Digest: wvxwx9Dqd+jbKoe8e7raVxSfNzI=
Name: chess/ChessGUI.java
SHA1-Digest: JlWKkQ9l5/82bHxMdf4nzrmphH0=
Name: chess/Chess.java
SHA1-Digest: Y4jUlkFH64RojRERTRBEIZRC+uc=
632
Packaging and Deploying Your Java Applications
These three new entries show the signature for each of the files that were signed by the jarsigner. These entries are now also shown in the manifest.mf file:
Manifest-Version: 1.0
Created-By: 1.5.0(Sun Microsystems Inc.)
Name: chess/images/board.bmp
SHA1-Digest: 2jmj7l5rSw0yVb/vlWAYkK/YBwk=
Name: chess/ChessGUI.java
SHA1-Digest: 2jmj7l5rSw0yVb/vlWAYkK/YBwk=
Name: chess/Chess.java
SHA1-Digest: 2jmj7l5rSw0yVb/vlWAYkK/YBwk=
Another way to verify that the jarsigner signed the JAR file correctly is to run the jarsigner tool with the -verify option on the JAR file you want to verify. So, go ahead and issue the following command on the JAR file you just signed:
C:\>jarsigner -verbose -verify chess.jar
You should see the following output if it was successful:
|
289 |
Wed July |
21 |
21:28:58 EDT |
2004 |
META-INF/MANIFEST.MF |
|
|
410 |
Wed July |
21 |
21:28:58 EDT |
2004 |
META-INF/MYSELF.SF |
|
|
1008 |
Wed July |
21 |
21:28:58 EDT |
2004 |
META-INF/MYSELF.DSA |
|
|
0 |
Wed July |
21 |
13:36:18 EDT |
2004 |
META-INF/ |
|
|
0 |
Wed July |
21 |
13:27:02 |
EDT 2004 chess/ |
||
sm |
0 |
Wed July |
21 |
13:26:32 |
EDT 2004 chess/Chess.java |
||
sm |
0 |
Wed July |
21 |
13:26:42 |
EDT 2004 chess/ChessGUI.java |
||
|
0 |
Wed July |
21 |
13:27:14 EDT |
2004 |
chess/images/ |
|
sm |
0 |
Wed July |
21 |
13:27:08 EDT |
2004 |
chess/images/board.bmp |
|
|
s = signature was verified |
|
|
|
|||
|
m = entry is listed |
in manifest |
|
|
|
||
|
k = at least one certificate was |
found in keystore |
|||||
|
i = at least one certificate was |
found in identity scope |
jar verified.
If the validation failed, the jarsigner tool would either throw a security exception, or, if the JAR file was not signed at all, it would send a message back stating that the JAR file is unsigned (signature missing or not parsable).
If you have made it through all of these steps, congratulations! You now know how to sign your own JAR files. This is critical when you need to ensure security on a JAR file. JAR files are generally signed when using Java Web Start applications and especially applets, but signing can definitely be done for all the JAR files you create.
JAR files can also be signed by multiple people. What will happen is the signatures for each of the people who ran the jarsigner tool will be stored in the META-INF directory just as is the case when one person signs it. You can even sign the JAR file with different versions of the JDK so that there are a lot of
633
Chapter 14
security options you can do using the tools that have been mentioned for signing JAR files and creating keystores. Before moving on, take a closer look at the options that can be used with the jarsigner tool.
Option |
Description |
|
|
keystore <url> |
This option is required when signing a JAR file and will default |
|
to the .keystore file in your user.home directory if you do not specify |
|
the keystore file to use. You can specify a full path and filename |
|
of the keystore file for the URL parameter. |
storepass <password> |
This is used to supply the password that is required to access the |
|
keystore you plan to use when signing your JAR file. |
storetype <storetype> |
This is used to specify the keystore type to be used. The security |
|
.properties file has an entry called keystore.type, and the jarsigner |
|
tool will default to that value if no storetype is provided. |
keypass <password> |
This is your password for your private key if it is different from the |
|
store password. If you don’t supply this option, you will be |
|
prompted for the password, if necessary. |
sigfile <filename> |
This specifies the base of the filename to use for generating the .sf |
|
and .dsa files. This option allows you to override the default values |
|
generated by the jarsigner tool. |
signedjar <filename> |
You can specify another name for the JAR file that will be signed. If |
|
you don’t specify a name, the JAR file you are issuing the command |
|
on is overwritten. For example, you could use chess_secure.jar for the |
|
name if you want to have signed and unsigned copies of chess.jar. |
verify <jarfile> |
This is an option for verifying that the JAR file is signed properly. |
verbose |
Verbose tells the jarsigner tool to output more information during the |
|
signing process to help with debugging issues. |
certs |
This option should be used with verbose and verify together. It will |
|
display certificate information for each signer of the JAR file. |
tsa <url> |
This allows you to specify the location of the Time-Stamping |
|
Authority. |
|
|
Examining the JAR Index Option
Downloading JAR files that are required by applets can be slow and painful, and searching them for the appropriate classes they contain used to be very linear. Linear searching of a JAR file for its class can result in slow performance, wasted bandwidth, and waiting too long to initiate a download of a JAR file the applet may be missing. With the JARIndex algorithm, all the JAR files in an applet can be stored into an index file, which thus makes class loading times much faster — especially in determining what needs to be downloaded.
634
Packaging and Deploying Your Java Applications
The jar tool has a new option, -i, which means index. This option will generate index information about the classes, packages, and resources that exist inside the JAR file. This makes access times much
quicker. The information is stored in a small text file under the META-INF directory called INDEX.LIST. When the JAR is accessed by the class loader, it reads the INDEX.LIST file into a hash map that will contain all the files and package names in the hash map. Instead of searching linearly in the JAR file for the class file or resource that the class loader needs, it can now query the hash map, resulting in quicker access times. The INDEX.LIST file is always trusted by the class loader, so manipulating it manually is not wise. If you make a mistake and the class loader can’t locate a resource or file, it will throw an InvalidJarIndexException so that you can capture the error and correct it. You can generate an index of the JAR file chess.jar that you created in previous examples by issuing the following command:
C:\>jar -iv chess.jar
The contents of the JAR file now contain an INDEX.LIST file in the META-INF directory:
C:\>jar -tf chess.jar
META-INF/INDEX.LIST
META-INF/ META-INF/MANIFEST.MF chess/ chess/Chess.java chess/ChessGUI.java chess/images/ chess/images/board.bmp
The INDEX.LIST file contains the following information:
JarIndex-Version: 1.0
chess.jar chess chess/images
The INDEX.LIST file is simply text and is compressed inside the JAR file, so the memory footprint of the INDEX.LIST file is very light, to say the least.
Creating an Executable JAR
Java supports the ability to make JAR files executable. If a JAR file is executable, it can be run from a console or command prompt by typing:
java –jar jar-file-name
Also, if you are in Windows and your application is GUI-driven, simply double-click an executable JAR, and it will automatically run.
635