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.
|