TOC
BACK
FORWARD
HOME

Java 1.1 Unleashed

- 37 -
Code Signing and JAR Security

by Mike Fletcher

IN THIS CHAPTER

  • Introduction to Digital Signatures
  • The java.security APE
  • Signing Code with javakey

Several additions and changes have been made to Java's security facilities in JDK 1.1. One of the most anticipated new features is the ability to digitally sign Java code--and to allow code signed by trusted entities to be granted access outside the normal applet sandbox. This chapter introduces the new java.security API, shows you how to use the javakey utility to create and manage digital keys, and shows you how to distribute signed code in JAR files.

Introduction to Digital Signatures

Before delving into the details of signed applets, you may find it useful to know how digital signatures work. Digital signatures provide a way to indicate that some piece of information was generated by some entity (for Java digital signatures, this "entity" is usually either a programmer or a company) and that the information has not been altered. Methods for generating signatures are designed so that it is mathematically impossible to create two different documents with the same signature in any reasonable period of time.

Public key cryptography differs from what is referred to as conventional or secret key cryptography. In public key cryptography, you have one key to encrypt a message and a different key to decrypt the message. For a well-designed algorithm, it is mathematically impossible to determine the secret key given the encrypting key. The encrypting key (usually referred to as the public key) can be given to anyone who wants to send an encrypted message to the holder of the corresponding secret key (usually referred to as the private key). Anyone can use the public key to encrypt, but only the secret key can decrypt the message and recover the original text.

Some public-key encryption algorithms can also be used to create digital signatures. Instead of the sender using the public key to encrypt a message to the private key holder, the private key holder encrypts the message using his or her private key. Anyone who has the public key can decrypt this message and verify that it did in fact come from the private key holder (because that person should be the only person with access to the private key). The signature algorithm used by the default JDK security package is known as DSA (Digital Signature Algorithm). DSA was created by the U.S. government's National Institute of Standards and Technology (the standard is FIPS 186, if you are interested) and the National Security Agency. The DSA has public keys that use anywhere from 512-bit to 1024-bit prime numbers and a 160-bit private key. Rather than using DSA to generate a signature of the entire document (a possibly time-consuming operation), a one-way hash of the document is generated using the MD5 algorithm; this hash is signed. MD5 generates a 128-bit string that is unique for a given input document. To verify the signature, the one-way hash of the received document is generated and checked against the signed 128-bit string from the sender. If the two match, the document has not been tampered with.


NOTE: For more information on digital signatures and public key cryptography, check out Applied Cryptography, Second Edition, by Bruce Shneier (published by John Wiley & Sons, ISBN 0-471-11709-9). This book is a very good introduction to cryptography in general, as well as an excellent reference for the details on specific algorithms. On the Web, the NIST's Computer Security Resource Clearing house (http://csrc.ncsl.nist.gov/) provides copies of the Federal Information Processing Standards for DSA and SHA. The sci.crypt newsgroup and its Frequently Asked Questions posting is another good starting place for cryptography resources.

The java.security API

The java.security package implements the new Java Security API. This API is intended to give developers access to security functionality in a standard, cross-platform way. In addition to the digital signatures, key management, and access control lists provided in the 1.1 release, future releases of java.security will provide support for exchanging digital keys and data encryption. For more information on the java.security package, see Chapter 16, "The Security Package."

The Signature Class

The Signature class represents a digital signature 94gorithm. The constructor takes as its parameter a String representing the name of the signature algorithm desired. Once a Signature reference has been obtained, it must be initialized with either the private key (for signing) or the public key (for verifying a signature). To generate a signature, call the update() method with the contents of the document to be signed. The update() method takes either a single byte argument or a byte[] array with an optional offset and length. After the contents of the document have been given to Signature(), the sign() method can be called to obtain a byte[] representing the signature. Verifying a signature is very similar to creating one: After calling the initVerify() method with the PublicKey, the contents of the document are passed to update(). Once the entire contents have been given, the verify() method is called with the byte[] representing what the signature should be. The verify() method returns a boolean specifying whether the signature was valid; the Signature() method is reset and ready to verify another signature by the same PublicKey.

The KeyPairGenerator and KeyPair Classes

These classes are used to generate a pair of public and private keys for use with other security packages. The KeyPairGenerator class's static method getInstance() returns a reference to an object, which in turn may be used to generate public and private keys for the algorithm specified. The initialize() method sets up the generator to provide a key of a specific strength (that is, a key of a certain length, such as 512 bits or 1,024 bits). The generateKeyPair() method returns a KeyPair object. The KeyPair class provides two methods, getPrivateKey() and getPublicKey(), which return the corresponding key references.

The PrivateKey and PublicKey Interfaces

These two interfaces represent key material for various algorithms. Each algorithm returns objects implementing these interfaces, which then behave as appropriate for the algorithm. For example, the DSA algorithm has the DSAPrivateKey and DSAPublicKey interfaces. In general (unless you are implementing an algorithm), you do not manipulate keys directly, only give them as parameters.

The Identity, IdentityScope, and Certificate Classes

The Identity class represents an entity that can be authenticated by a public key. The entity represented can be a person, a company, or even a particular computer. Identity objects have a name associated with them; this name should be unique within a given scope. An IdentityScope represents a scope for an Identity, giving the context in which the Identity object exists. Both Identity and IdentityScope objects can have one or more Certificate objects associated with them. A Certificate represents a guarantee by some entity that the Identity and its associated public key actually belong to the owner represented by the Identity.

For example, a programmer can be represented by an Identity object, which he or she uses to sign code he or she produces. The IdentityScope for this Identity object could be set to Acme Software, the company for which the programmer works. The programmer's Identity would have a Certificate signed by Acme Software. The IdentityScope for the company might have a Certificate signed by an entity providing certification of signatures (such as VeriSign or the U.S. Post Office). The Certification object can then be used to verify that the Identity is valid and belongs to the programmer.

Signing Code with javakey

The javakey utility included with the JDK provides facilities for managing identities and certificates, and for signing code. Along with the jar utility used to generate JAR files, javakey allows you to sign code and place the class files (and other resources used by an applet) into a single archive. Identities are stored in a database file named identitydb.obj, which is stored in a location specified in the java.security properties file in the JDK lib/security directory. When the applet is run in a properly configured browser, the signed code is granted privileges beyond those given to unsigned code. For example, a department can develop a signed applet for its intranet that stores its preferences in a local file on the user's computer. All the members of the department then set their browsers to allow code signed by the department to read and write files from their hard drives.

Creating an Identity and Key Pair

The first step in signing applets is to generate an identity and a public/private key pair for the identity. This is done with the following command:

% javakey -cs "MySigner" true

NOTE: In this section, all the examples that show javakey commands use the % character to represent the command or shell prompt.

The -cs "MySigner" part of the preceding command tells javakey that we want to create an identity in our identitydb.obj database for a signer with the name MySigner. The true parameter indicates that we will trust code signed by this particular signer. If the last argument is omitted, signatures from this signer can be verified but the code signed is not granted extra privileges. Now that we have an identity in our database, we must have javakey generate a key pair for our identity.

The following command is used to have javakey create a key pair:

% javakey -gk "MySigner" DSA 512 MySigner.public MySigner.private

This command tells javakey to generate a key (-gk) for the signer named MySigner. The next two arguments specify that we want a key for the DSA algorithm that is 512 bits long. The last two arguments are optional; they specify that we want javakey to store a copy of the public and private keys in the files named MySigner.public and MySigner.private, respectively.


CAUTION: Be careful with your private keys. Anyone who can get a copy of a private key can generate signatures for the corresponding identity.

Generating an X.509 Certificate

Before you can sign code, javakey must generate a certificate for your identity. To do this, you have to create a text file containing the parameters for the certificate, such as the identity to create the certificate for and what period of time the certificate is valid for. For this example, the last line of the text file specifies that we want a copy of the certificate saved into the file named MySigner.x509. This certificate file can be distributed to people who want to verify signatures from our sample identity. You can embed comments in the directive file by preceding the comment with a # character. Listing 37.1 shows the contents of the directive file for our example.

Listing 37.1. The certificate directive file.

# This is a comment
issuer.name=MySigner

issuer.cert=1

subject.name=MySigner

subject.real.name=Example Signer
subject.org.unit=Bogus Organization
subject.org=Bogus Corporation
subject.country=US

start.date=15 Feb 1997
end.date=15 Feb 1998
serial.number=2000
out.file=MySigner.x509

Once we have the certificate directive in a file, we can use the javakey -gc
options to generate the actual certificate. The following command assumes that the certificate directive in
List- ing 37.1 was placed in a file named cdirective:

% javakey -gc cdirective

Signing the JAR File

Now we are ready to sign a JAR file with our MySigner identity. Assume that a JAR file named example.jar has already been created, and that this JAR file contains an applet (see Chap- ter 36, "JAR Basics," for more information on creating JAR files). The next step is to create a signing directive file that tells javakey what identity to use to sign the file, what certificate to use, and what to name the signature file. The signer parameter in the directive file specifies which identity we want to use to create the signature. The cert directive specifies which certificate the identity is to use (for this example, we use 1 because our signer has only one certificate). The next parameter, chain, is not used in JDK 1.1 and should be set to zero. The final parameter gives the name of the signature file that will be generated and included in the JAR file. Listing 37.2 shows the complete signing directive file.

Listing 37.2. The signature directive file.

# This is a comment
signer=MySigner

cert=1

chain=0

signature.file=MySig

The last step is to have javakey sign the JAR file. The signed version of the JAR file has .sig \
appended to its name. Here is the command line to use to have javakey sign our example JAR file:

% javakey -gs sdirective example.jar

Distributing Signed Code

You now should have a JAR file named example.jar.sig which contains your applet resources and a signature by the MySigner identity. This JAR file can be manipulated with the jar utility in the same way as any other file. If you extract the contents of the JAR file, the META-INF directory contains the signature file just created. To grant trusted status to signed code, you must make available to users the X.509 certificate file created when the certificate was generated (this file is called MySigner.x509 in the preceding example). Once a user has a copy of the certificate file, he or she can use javakey to add the identity to his or her own database.

The first step in verifying a signature is similar to creating the identity--but instead of using the -cs flags, you use only the -c flag, as shown here:

% javakey -c MySigner true

After creating the identity, you must import the actual information about the identity from the certificate file. This is done using the javakey -ic options, which take the identity name and the filename containing the certificate as parameters:

% javakey -ic MySigner MySigner.x509

Now any code signed by the MySigner identity that is loaded over the network is given full access, just as if it had been loaded from a local disk.

Other javakey Operations

The javakey utility controls your database of identities and certificates. It can be used to list or remove identities as well as to create them. The -l option allows you to list a summary of all of the identities contained in identitydb.obj. You can use the -ld option to list detailed information for all entities in the database; use -li to limit the detailed display to a specific identity. Listing 37.3 shows what an identity listing looks like.

Listing 37.3. An identity listing.

% javakey -ld

Scope: sun.security.IdentityDatabase, source file: \fletch\identitydb.obj

MySigner[identitydb.obj][trusted]
        public key initialized
        certificates:
        certificate 1   for  : CN=Example Signer, OU=Bogus Organization, O=Bogus
 Corporation, C=US
                        from : CN=Example Signer, OU=Bogus Organization, O=Bogus
 Corporation, C=US


        No further information available.

If you want to remove an identity from the database, you can use the -r
option with the name of the identity to delete:

% javakey -r MySigner

Summary

You should now have an idea how the new code-signing facilities in the JDK 1.1 extend the capabilities of applets. The new java.security API provides a framework for manipulating digital signatures in general, as well as for creating signed code. You now understand how to use javakey to create and manage identities and certificates for distributing and verifying signed code.

TOCBACKFORWARDHOME


©Copyright, Macmillan Computer Publishing. All rights reserved.