Adding Classes to the JAR File’s Classpath

Adding Classes to the JAR File’s Classpath

You may need to reference classes in other JAR files from within a JAR file.

For example, in a typical situation an applet is bundled in a JAR file whose manifest references a different JAR file (or several different JAR files) that serves as utilities for the purposes of that applet.


You specify classes to include in the Class-Path header field in the manifest file of an applet or application. The Class-Path header takes the following form:


Class-Path: jar1-name jar2-name directory-name/jar3-name
By using the Class-Path header in the manifest, you can avoid having to specify a long -classpath flag when invoking Java to run the your application.






Note : The Class-Path header points to classes or JAR files on the local network, not JAR files within the JAR file or classes accessible over internet protocols. To load classes in JAR files within a JAR file into the class path, you must write custom code to load those classes. For example, if MyJar.jar contains another JAR file called MyUtils.jar, you cannot use the Class-Path header in MyJar.jar’s manifest to load classes in MyUtils.jar into the class path.




An Example


We want to load classes in MyUtils.jar into the class path for use in MyJar.jar. These two JAR files are in the same directory.

We first create a text file named Manifest.txt with the following contents:


Class-Path: MyUtils.jar





Warning : The text file must end with a new line or carriage return. The last line will not be parsed properly if it does not end with a new line or carriage return.



We then create a JAR file named MyJar.jar by entering the following command:


jar cfm MyJar.jar Manifest.txt MyPackage/*.class
This creates the JAR file with a manifest with the following contents:
Manifest-Version: 1.0
Class-Path: MyUtils.jar
Created-By: 1.6.0 (Sun Microsystems Inc.)
The classes in MyUtils.jar are now loaded into the class path when you run MyJar.jar.

Setting an Application’s Entry Point

Setting an Application’s Entry Point

If you have an application bundled in a JAR file, you need some way to indicate which class within the JAR file is your application’s entry point. You provide this information with the Main-Class header in the manifest, which has the general form:
Main-Class: classname
The value classname is the name of the class that is your application’s entry point.

Recall that the entry point is a class having a method with signature public static void main(String[] args).


After you have set the Main-Class header in the manifest, you then run the JAR file using the following form of the java command:


java -jar JAR-name
The main method of the class specified in the Main-Class header is executed.


An Example


We want to execute the main method in the class MyClass in the package MyPackage when we run the JAR file.

We first create a text file named Manifest.txt with the following contents:


Main-Class: MyPackage.MyClass





Warning: The text file must end with a new line or carriage return. The last line will not be parsed properly if it does not end with a new line or carriage return.


We then create a JAR file named MyJar.jar by entering the following command:
jar cfm MyJar.jar Manifest.txt MyPackage/*.class
This creates the JAR file with a manifest with the following contents:
Manifest-Version: 1.0
Created-By: 1.6.0 (Sun Microsystems Inc.)
Main-Class: MyPackage.MyClass
When you run the JAR file with the following command, the main method of MyClass executes:
java -jar MyJar.jar

Setting an Entry Point with the JAR Tool


The ‘e’ flag (for ‘entrypoint’), introduced in JDK 6, creates or overrides the manifest’s Main-Class attribute. It can be used while creating or updating a jar file. Use it to specify the application entry point without editing or creating the manifest file.
For example, this command creates app.jar where the Main-Class attribute value in the manifest is set to MyApp:
jar cfe app.jar MyApp MyApp.class

You can directly invoke this application by running the following command:


java -jar app.jar

If the entrypoint class name is in a package it may use a ‘.’ (dot) character as the delimiter. For example, if Main.class is in a package called foo the entry point can be specified in the following ways:


jar cfe Main.jar foo.Main foo/Main.class

Modifying a Manifest File

Modifying a Manifest File

You use the m command-line option to add custom information to the manifest during creation of a JAR file. This section describes the m option.

The Jar tool automatically puts a default manifest with the pathname META-INF/MANIFEST.MF into any JAR file you create. You can enable special JAR file functionality, such as package sealing, by modifying the default manifest. Typically, modifying the default manifest involves adding special-purpose headers to the manifest that allow the JAR file to perform a particular desired function.


To modify the manifest, you must first prepare a text file containing the information you wish to add to the manifest. You then use the Jar tool’s m option to add the information in your file to the manifest.





Warning :  The text file from which you are creating the manifest must end with a new line or carriage return. The last line will not be parsed properly if it does not end with a new line or carriage return.




The basic command has this format:


jar cfm jar-file manifest-addition input-file(s)

Let’s look at the options and arguments used in this command:

The m and f options must be in the same order as the corresponding arguments.






Note : The contents of the manifest must be encoded in UTF8.




The remaining sections of this lesson demonstrate specific modifications you may want to make to the manifest file.


Sealing Packages within a JAR File

Sealing Packages within a JAR File

Packages within JAR files can be optionally sealed, which means that all classes defined in that package must be archived in the same JAR file. You might want to seal a package, for example, to ensure version consistency among the classes in your software.

You seal a package in a JAR file by adding the Sealed header in the manifest, which has the general form:


Name: myCompany/myPackage/
Sealed: true
The value myCompany/myPackage/ is the name of the package to seal.


Note that the package name must end with a “/”.


An Example


We want to seal two packages firstPackage and secondPackage in the JAR file MyJar.jar.

We first create a text file named Manifest.txt with the following contents:


Name: myCompany/firstPackage/
Sealed: true

Name: myCompany/secondPackage/
Sealed: true





Warning : 

The text file must end with a new line or carriage return. The last line will not be parsed properly if it does not end with a new line or carriage return.


We then create a JAR file named MyJar.jar by entering the following command:
jar cmf MyJar.jar Manifest.txt MyPackage/*.class
This creates the JAR file with a manifest with the following contents:
Manifest-Version: 1.0
Created-By: 1.6.0 (Sun Microsystems Inc.)
Name: myCompany/firstPackage/
Sealed: true
Name: myCompany/secondPackage/
Sealed: true

Sealing JAR Files



If you want to guarantee that all classes in a package come from the same code source, use JAR sealing. A sealed JAR specifies that all packages defined by that JAR are sealed unless overridden on a per-package basis.


To seal a jar file, use the Sealed manifest header with the value true. For example,


Sealed: true
specifies that all packages in this archive are sealed unless explicitly overridden for particular packages with the Sealed attribute in a manifest entry.

Understanding the Default Manifest

Understanding the Default Manifest

When you create a JAR file, it automatically receives a default manifest file. There can be only one manifest file in an archive, and it always has the pathname
META-INF/MANIFEST.MF

When you create a JAR file, the default manifest file simply contains the following:


Manifest-Version: 1.0Created-By: 1.6.0 (Sun Microsystems Inc.)

These lines show that a manifest`s entries take the form of “header: value” pairs. The name of a header is separated from its value by a colon. The default manifest conforms to version 1.0 of the manifest specification and was created by the 1.6.0 version of the JDK.


The manifest can also contain information about the other files that are packaged in the archive. Exactly what file information should be recorded in the manifest depends on how you intend to use the JAR file. The default manifest makes no assumptions about what information it should record about other files.


Digest information is not included in the default manifest. To learn more about digests and signing, see the Signing and Verifying JAR Files lesson.


Signing and Verifying JAR Files


Signing and Verifying JAR Files

You can optionally sign a JAR file with your electronic “signature.” Users who verify your signature can grant your JAR-bundled software security privileges that it wouldn’t ordinarily have. Conversely, you can verify the signatures of signed JAR files that you want to use.

This lesson shows you how to use the tools provided in the JavaTM Development Kit to sign and verify JAR files:


Understanding Signing and Verification


If you’re not familiar with the concepts of signing and verification, this section will help to bring you up to speed. It contains definitions of the relevant terms, explanations of some of the benefits provided by signing, and an outline of the signing mechanism used by the Java platform as it relates to JAR files.

Signing JAR Files


In this section, you’ll learn how to use the JDKTM tools to digitally sign your JAR files.

Verifying Signed JAR Files


This section shows you how to use the JDK tool set to verify signed JAR files.

Verifying Signed JAR Files

Verifying Signed JAR Files

Typically, verification of signed JAR files will be the responsibility of your JavaTM Runtime Environment. Your browser will verify signed applets that it downloads. Signed applications invoked with the -jar option of the interpreter will be verified by the runtime environment.

However, you can verify signed JAR files yourself by using the Jarsigner tool. You might want to do this, for example, to test a signed JAR file that you’ve prepared.


The basic command to use for verifying a signed JAR file is:


jarsigner -verify jar-file

This command will verify the JAR file’s signature and ensure that the files in the archive haven’t changed since it was signed. You’ll see the following message if the verification is successful:


jar verified.

If you try to verify an unsigned JAR file, the following message results:


jar is unsigned. (signatures missing or not parsable)

If the verification fails, an appropriate message is displayed. For example, if the contents of a JAR file have changed since the JAR file was signed, a message similar to the following will result if you try to verify the file:


jarsigner: java.lang.SecurityException: invalid SHA1
signature file digest for test/classes/Manifest.class

Signing JAR Files


Signing JAR Files

You use the JAR Signing and Verification Tool to sign JAR files. You invoke the JAR Signing and Verification Tool by using the jarsigner command, so we’ll refer to it as “Jarsigner” for short.

To sign a JAR file, you must first have a private key. Private keys and their associated public-key certificates are stored in password-protected databases called keystores. A keystore can hold the keys of many potential signers. Each key in the keystore can be identified by an alias which is typically the name of the signer who owns the key. The key belonging to Rita Jones might have the alias “rita”, for example.


The basic form of the command for signing a JAR file is


jarsigner jar-file alias
In this command:

  • jar-file is the pathname of the JAR file that’s to be signed.

  • alias is the alias identifying the private key that’s to be used to sign the JAR file, and the key’s associated certificate.

The Jarsigner tool will prompt you for the passwords for the keystore and alias.


This basic form of the command assumes that the keystore to be used is in a file named .keystore in your home directory. It will create signature and signature block files with names x.SF and x.DSA respectively, where x is the first eight letters of the alias, all converted to upper case. This basic command will overwrite the original JAR file with the signed JAR file.


In practice, you may want to use this command in conjunction with one or more of these options, which must precede the jar-file pathname:






















Jarsigner Command Options
Option Description
-keystore url Specifies a keystore to be used if you don’t want to use the .keystore default database.
-storepass password Allows you to enter the keystore’s password on the command line rather than be prompted for it.
-keypass password Allows you to enter your alias’s password on the command line rather than be prompted for it.
-sigfile file Specifies the base name for the .SF and .DSA files if you don’t want the base name to be taken from your alias. file must be composed only of upper case letters (A-Z), numerals (0-9), hyphen (-), and underscore (_).
-signedjar file Specifies the name of the signed JAR file to be generated if you don’t want the original unsigned file to be overwritten with the signed file.


Example


Let’s look at a couple of examples of signing a JAR file with the Jarsigner tool. In these examples we will assume:

  • your alias is “johndoe”.

  • the keystore you want to use is in a file named “mykeys” in the current working directory.

  • the keystore’s password is “abc123”.

  • the password for your alias is “mypass”.
Under these assumptions, you could use this command to sign a JAR file named app.jar:
jarsigner -keystore mykeys -storepass abc123
-keypass mypass app.jar johndoe

Because this command doesn’t make use of the -sigfile option, the .SF and .DSA files it creates would be named JOHNDOE.SF and JOHNDOE.DSA. Because the command doesn’t use the -signedjar option, the resulting signed file will overwrite the original version of app.jar.


Let’s look at what would happen if you used a different combination of options:


jarsigner -keystore mykeys -sigfile SIG
-signedjar SignedApp.jar app.jar johndoe

This time, you would be prompted to enter the passwords for both the keystore and your alias because the passwords aren’t specified on the command line. The signature and signature block files would be named SIG.SF and SIG.DSA, respectively, and the signed JAR file SignedApp.jar would be placed in the current directory. The original unsigned JAR file would remain unchanged.

Understanding Signing and Verification

Understanding Signing and Verification

The JavaTM platform enables you to digitally sign JAR files. You digitally sign a file for the same reason you might sign a paper document with pen and ink — to let readers know that you wrote the document, or at least that the document has your approval.

When you sign a letter, for example, everyone who recognizes your signature can confirm that you wrote the letter. Similarly when you digitally sign a file, anyone who “recognizes” your digital signature knows that the file came from you. The process of “recognizing” electronic signatures is called verification.


The ability to sign and verify files is an important part of the Java platform’s security architecture. Security is controlled by the security policy that’s in force at runtime. You can configure the policy to grant security privileges to applets and to applications. For example, you could grant permission to an applet to perform normally forbidden operations such as reading and writing local files or running local executable programs. If you have downloaded some code that’s signed by a trusted entity, you can use that fact as a criterion in deciding which security permissions to assign to the code.


Once you (or your browser) have verified that an applet is from a trusted source, you can have the platform relax security restrictions to let the applet perform operations that would ordinarily be forbidden. A trusted applet can have freedoms as specified by the policy file in force.


The Java platform enables signing and verification by using special numbers called public and private keys. Public keys and private keys come in pairs, and they play complementary roles.


The private key is the electronic “pen” with which you can sign a file. As its name implies, your private key is known only to you so that no one else can “forge” your signature. A file signed with your private key can be verified only by the corresponding public key.


Public and private keys alone, however, aren’t enough to truly verify a signature. Even if you’ve verified that a signed file contains a matching key pair, you still need some way to confirm that the public key actually comes from the signer that it purports to come from.


One more element, therefore, is required to make signing and verification work. That additional element is the certificate that the signer includes in a signed JAR file. A certificate is a digitally signed statement from a recognized certification authority that indicates who owns a particular public key. A certification authority are entities (typically firms specializing in digital security) that are trusted throughout the industry to sign and issue certificates for keys and their owners. In the case of signed JAR files, the certificate indicates who owns the public key contained in the JAR file.


When you sign a JAR file your public key is placed inside the archive along with an associated certificate so that it’s easily available for use by anyone wanting to verify your signature.


To summarize digital signing:



  • The signer signs the JAR file using a private key.

  • The corresponding public key is placed in the JAR file, together with its certificate, so that it is available for use by anyone who wants to verify the signature.

Digests and the Signature File


When you sign a JAR file, each file in the archive is given a digest entry in the archive’s manifest. Here’s an example of what such an entry might look like:
Name: test/classes/ClassOne.class
SHA1-Digest: TD1GZt8G11dXY2p4olSZPc5Rj64=
The digest values are hashes or encoded representations of the contents of the files as they were at the time of signing. A file’s digest will change if and only if the file itself changes.

When a JAR file is signed, a signature file is automatically generated and placed in the JAR file’s META-INF directory, the same directory that contains the archive’s manifest. Signature files have filenames with an .SF extension. Here is an example of the contents of a signature file:


Signature-Version: 1.0
SHA1-Digest-Manifest: h1yS+K9T7DyHtZrtI+LxvgqaMYM=
Created-By: 1.6.0 (Sun Microsystems Inc.)

Name: test/classes/ClassOne.class
SHA1-Digest: fcav7ShIG6i86xPepmitOVo4vWY=

Name: test/classes/ClassTwo.class
SHA1-Digest: xrQem9snnPhLySDiZyclMlsFdtM=

Name: test/images/ImageOne.gif
SHA1-Digest: kdHbE7kL9ZHLgK7akHttYV4XIa0=

Name: test/images/ImageTwo.gif
SHA1-Digest: mF0D5zpk68R4oaxEqoS9Q7nhm60=


As you can see, the signature file contains digest entries for the archive’s files that look similar to the digest-value entries in the manifest. However, while the digest values in the manifest are computed from the files themselves, the digest values in the signature file are computed from the corresponding entries in the manifest. Signature files also contain a digest value for the entire manifest (see the SHA1-Digest-Manifest header in the above example).


When a signed JAR file is being verified, the digests of each of its files are re-computed and compared with the digests recorded in the manifest to ensure that the contents of the JAR file haven’t changed since it was signed. As an additional check, digest values for the manifest file itself are re-computed and compared against the values recorded in the signature file.


You can read additional information about signature files on the Manifest Format page of the JDKTM documentation.


The Signature Block File


In addition to the signature file, a signature block file is automatically placed in the META-INF directory when a JAR file is signed. Unlike the manifest file or the signature file, signature block files are not human-readable.

The signature block file contains two elements essential for verification:



  • The digital signature for the JAR file that was generated with the signer’s private key

  • The certificate containing the signer’s public key, to be used by anyone wanting to verify the signed JAR file

Signature block filenames typically will have a .DSA extension indicating that they were created by the default Digital Signature Algorithm. Other filename extensions are possible if keys associated with some other standard algorithm are used for signing.


Setting Package Version Information

Setting Package Version Information

You may need to include package version information in a JAR file’s manifest. You provide this information with the following headers in the manifest:




























Headers in a manifest
Header Definition
Name The name of the specification.
Specification-Title The title of the specification.
Specification-Version The version of the specification.
Specification-Vendor The vendor of the specification.
Implementation-Title The title of the implementation.
Implementation-Version The build number of the implementation.
Implementation-Vendor The vendor of the implementation.


One set of such headers can be assigned to each package. The versioning headers should appear directly beneath the Name header for the package. This example shows all the versioning headers:


Name: java/util/
Specification-Title: Java Utility Classes
Specification-Version: 1.2
Specification-Vendor: Sun Microsystems, Inc.
Implementation-Title: java.util
Implementation-Version: build57
Implementation-Vendor: Sun Microsystems, Inc.


For more information about package version headers, see the Package Versioning specification .



An Example


We want to include the headers in the example above in the manifest of MyJar.jar.

We first create a text file named Manifest.txt with the following contents:


Name: java/util/
Specification-Title: Java Utility Classes
Specification-Version: 1.2
Specification-Vendor: Sun Microsystems, Inc.
Implementation-Title: java.util
Implementation-Version: build57
Implementation-Vendor: Sun Microsystems, Inc.




Warning : The text file must end with a new line or carriage return. The last line will not be parsed properly if it does not end with a new line or carriage return.


We then create a JAR file named MyJar.jar by entering the following command:
jar cmf MyJar.jar Manifest.txt MyPackage/*.class
This creates the JAR file with a manifest with the following contents:
Manifest-Version: 1.0
Created-By: 1.6.0 (Sun Microsystems Inc.)
Name: java/util/
Specification-Title: Java Utility Classes
Specification-Version: 1.2
Specification-Vendor: Sun Microsystems, Inc.
Implementation-Title: java.util
Implementation-Version: build57
Implementation-Vendor: Sun Microsystems, Inc.