Sealing Packages in JARs
In a JAR archive, you can seal a package within the JAR. Doing this informs the JVM that classes defined in the package must be found in the same JAR file. The advantage is that a basic security measure is introduced. A SecurityException is thrown by the JVM if you try to load a class in a sealed package from a source other than the housing JAR of the sealed package.
To seal a package, a Name header is used, followed by the package's relative name. The Name header is followed by the Sealed header with a value of true, to state that the package specified should be sealed. The following is an example of the appropriate headers needed to seal a package:
Name: com/yourcompanyname/thePackageName/ Sealed: true
As before, you would have these headers in a text file and then use the JAR tool to take the header and incorporate into manifest file and finally into the JAR.
The extension mechanism of the JAR format allows you to specify auxiliary JAR files that a given JAR file requires for operation. Instead of having to manipulate the system CLASSPATH and add these auxiliary JARS to it, you can leverage Class-Path headers in the manifest file.
This might best be described by example. Let's say that one.jar depends on two.jar. Given that these two JAR files are in the same directory, we could use the following header in one.jar's manifest file:
Using this header, we are stating that the classes of two.jar are extension classes of the classes of one.jar. As you can see, this facility allows us to use the manifest file instead of having to manipulate system CLASSPATH variables, thereby making our code more portable. The JVM, in essence, will add JARs in the Class-Path header to the class path for us.
The JDK now ships with a tool called jarsigner, which allows you to digitally sign JARs. When a JAR is digitally signed, the manifest file is updated with security information, and a signature and block file are added to the META-INF directory.
JAR files use a public/private key security scheme tied together with a certificate authority to verify authenticity of a public key.
It is beyond the scope of this article to delve into the details of these security concepts. You can learn more about these topics by visiting the links in the references section of this article.
The signing of a JAR file requires a private key. This private key, as well as the associated public key and certificate, is stored in a password protected database called a keystore. These so-called keystores can hold the keys of many signers. The keys in the key store is associated with an alias. This alias is typically the name of the key holder. For example, Bob Jones's key might be named BobJones.
So where do we find this keystore? Well, they have to be created. You can do this by creating a keystore entry. If a keystore does not exist, it will be created. We can do just that with the keytool command:
keytool genkey alias BobJones keypass BobJonesPassword validity 80 keystore ourKeyStore storepass ourKeyStorePasword
in the syntax above, we specified that we want a keystore named ourKeyStore created with a password of ourKeyStorePassword. Inside this keystore, we want a key generated for an alias of BobJones, having a password of BobJonesPassword.
After issuing the command, you will be asked to answer various questions as shown in the example interaction with the keytool utility below:
C:\jarsstudy>keytool -genkey -alias BobJones -keypass BobJonesPassword -validity 80 -keystore ourKeyStore -storepass ourKeyStorePassword What is your first and last name? [Unknown]: Bob Jones What is the name of your organizational unit? [Unknown]: IBM Software Services for WebSphere What is the name of your organization? [Unknown]: IBM What is the name of your City or Locality? [Unknown]: Austin What is the name of your State or Province? [Unknown]: TX What is the two-letter country code for this unit? [Unknown]: US Is CN=Bob Jones, OU=IBM Software Services for WebSphere, O=IBM, L=Austin, ST=TX, C=US correct? [no]: yes
In our interaction, we use a self-signed certificate. In a production environment, you would want to use a certificate authority, such as VeriSign. You can learn more about how to do this by looking at the references section.
Now that we have a keystore that contains the needed keys, we can go about signing our JAR. As mentioned earlier, we'll use the jarsigner tool to do this. Take a look at the example syntax below:
jarsigner keystore ourKeyStore storepass ourKeyStorePassword keypass BobJonesPassword signedjar SignedJARTargetName.jar SignedJARSourceName.jar BobJones
I intentionally used color in the example to better explain what is going on. Blue is used for values that we specified earlier when we used keytool to generate our keys. As you can gather from the syntax above, we provide the jarsigner tool with some information that we established when we generated our keys:
the name of our keystore (ourKeyStore) following the keystore option
the password we set for our keystore (ourKeyStorePassword) following the storepass option
the password for our key following the keypass option
at the end of the syntax we state the name of our alias (BobJones)
We also use the signed option followed by the name of signed JAR we want to create (SignedJARTargetName.jar) trailed by the name of the JAR we want to sign (SignedJARSourceName.jar).
The consumer of a signed JAR file can verify if the JAR has been signed. This is done using the jarsigner tool with the syntax:
jarsigner verify SignedJARTargetName.jar
If the JAR being scrutinized is verified, you will see receive a response from the JAR signer tool of:
On the other hand, if the JAR file you are dealing with is not verified, you will receive a message:
jar is unverified (signatures missing or not parsable)
or if verification fails, an appropriate message will be relayed to the console.