HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

When a client recently requested secure communication among multiple platform boxes distributed across three continents, I decided to leverage the 100% Java-based security available via Java Secure Socket Extension.

JSSE requires trusted certificates for authentication services, but my client had no Public Key Infrastructure (PKI) in place for certificate generation and distribution. So I built a PKI implementation where my client acted as the certificate authority and then integrated this PKI with J2EE systems via JSSE to provide secure communication services. In this article, I'll demonstrate how you can do the same. (The source code is available below.)

PKI/JSSE Overview
If you already have a PKI in place or have other experience with key-based cryptography, you may want to skip this section. For those new to the subject, the following brief overview provides some of the key terms and acronyms used throughout this article. There's a lot to absorb here, but the actual application of these concepts in the following sections should make matters more clear.

One of the additions to the upcoming release of J2SDK 1.4 will be Java Secure Socket Extension 1.0.2. Currently available as an optional add-on, JSSE is a set of Java packages that enables secure Internet communications via Secure Sockets Layer (SSL) v3 and Transport Layer Security (TLS) 1.0 protocols.

Netscape developed SSL in 1994 and subsequently transferred control of the protocol to the Internet Engineering Task Force. The IETF renamed SSL to Transport Layer Security (TLS), and released their first specification in January 1999. TLS 1.0 is a modest upgrade to the most recent version of SSL, version 3.0, and the differences between the two are minor.

SSL and TLS use public key cryptography to provide authentication, secret key cryptography to provide privacy, and a message authentication code to provide data integrity. While in this article I focus on the use of a key pair for authentication purposes, all these cryptographic processes require only one.

One key in the pair is made public and the other is held strictly private. For authentication purposes, the public key in a key pair is associated with a certificate. A certificate in a PKI implementation is an electronic document used to identify a communicating entity by its association with a public key. Since certificates are used to address the problem of impersonation, their distribution must be governed by a trustworthy entity. These entities are known as certificate authorities (CAs).

When you participate in a client- authenticated TLS or SSL conversation, you receive your counterparticipant's certificate. The certificate specifies the identity of your counterparticipant and guarantees it by providing a certificate authority's signature. The CA in this case acts much like a notary. If you trust the notary, you can trust the certificate. CAs for the uncontrolled communication encouraged by the World Wide Web are typically independent third parties who charge hundreds of dollars for the issuance of a single certificate. This expense is not due to the cost of producing a certificate, but to the costs involved in ensuring that an entity requesting a certificate is in fact who it claims to be.

In an enterprise system where multiple communicating parties are controlled by a single entity, it makes little sense to incur this expense. You can save time and money while maintaining internal control of your PKI by establishing yourself as the CA in your secure communications. So let's get to it.

Becoming a CA
JSSE was not included in Java Development Kits prior to version 1.4, so you may need to install JSSE as an optional extension to your Java platform. Luckily, the JSSE distribution includes explicit installation instructions, making this step a breeze. Next, you'll need an SSL toolkit capable of issuing X.509 certificates. I recommend OpenSSL because it's open source, well documented, and free. There are several other options available including managed services, but I'll be using OpenSSL for demonstration purposes.

Once you have the necessary software installed, the next step is to create your certificate authority private key and certificate. I'll create mine with the single-line command:

openssl req -new -x509 -newkey
rsa:2048 -config openssl.cnf -keyout rootCAKey
-out rootCACert -days 3650 -rand
"install.log:sunnyday.gif"
The first option "req" signifies that we're performing an X.509 certificate management operation, followed by "new" and "x509" showing that we're creating a new certificate without a certificate request. The "newkey" parameter specifies the type of private key along with its size in bits. The "days" parameter specifies that this certificate will be valid for 10 years, and the "rand" parameter points to a couple of files used to help randomize my key generation.

Once you execute this command, you'll be prompted for a pass phrase that will be used to encrypt and decrypt your new private key. When choosing a pass phrase and restricting access to your CA private key, keep in mind that your private key is a cornerstone of your PKI and that its safekeeping is vital. After confirming your pass phrase, you'll be prompted for the attributes of your CA certificate as shown in Listing 1.

OpenSSL generates base64 encoded certificates between "-----BEGIN-----" and "-----END-----" lines by default. This format is commonly but mistakenly referred to as PEM format. True Privacy Enhanced Mail format is actually used by some SSL servers like old Lotus Domino and 4D WebSTAR Server, so I'll refer to the OpenSSL format as OSSL. The JSSE integration tools expect OSSL-formatted certificates. Regardless of which SSL toolkit you used to complete this step, your final product should be an OSSL certificate and a private key. These two components, along with your SSL toolkit, provide all you need. Congratulations, you've successfully become a certificate authority.

JVM Integration
Your next step is to tell your JVM that you're a trusted CA so it will inherently trust any certificates you issue. This is accomplished by adding your CA certificate to your JVM's CA certificates keystore. The default CA certificates keystore is found in your runtime environment's security directory, found underneath the lib directory. It's intuitively named "cacerts". We'll be modifying the cacerts file, so make a backup copy before continuing.

The keytool utility distributed with J2SDK allows us to perform operations on any JVM keystores, so let's use it to examine the default cacerts.

keytool -list -keystore cacerts

When you execute this command, you'll be prompted for the keystore password. The default cacerts password is "changeit".

As you can see in Listing 2, the default cacerts contains certificates from VeriSign and Thawte, which together issue the vast majority of Web site certificates. Our JVM recognizes most Web-based e-commerce certificates already. Now let's add our CA certificate to the keystore.

keytool -import -alias newCA -file
rootCACert -keystore cacerts

When asked if you wish to trust this certificate, answer "yes". If you examine the cacerts keystore again, you'll find that your CA certificate is listed underneath the alias you provided. You're now registered as a CA in your JVM. Let's use our new power as a CA to facilitate an SSL conversation between two parties.

SSL Demonstration
To demonstrate that your JVM will trust certificates that you issue, we'll set up an SSL-enabled conversation between Alice and Bob. Alice and Bob represent two servers in an enterprise system that need to communicate securely. For this demonstration you can use, but do not need, two separate boxes. To keep things simple, we can just launch two JVMs on the same box and share the same local cacerts file (see Figure 1). In this figure, configuration A shows the setup for the demo running on separate boxes. Configuration B shows the setup for the demo running on one machine.

Figure 1

Regardless of your hardware setup, both Alice and Bob will need access to a cacerts that we inserted our CA certificate in. Each communicating entity also needs a personal keystore. Let's make two copies of our cacerts file and place them in a working directory. Name the first copy aliceStore and the second bobStore. Next, we'll generate a public and private key pair for Alice and store the pair in her personal keystore. A screenshot of this process is shown in Listing 3.

Alice now has a 1024-bit RSA key, which will be valid for 365 days. This key pair allows Alice to participate as an unauthenticated client in an SSL conversation. However, in our demonstration system, we want to guarantee the identity of all conversation participants. Since Alice needs a certificate to participate as an authenticated client, she'll need to generate a certificate request to send to her certificate authority.

keytool -certreq -alias alice -sigalg
MD5withRSA -file aliceCSR -keystore
aliceStore
Enter keystore password: changeit
Note that my keytool utility balks on this step if the key generated in the last step has spaces in any Distinguished Name attributes. So, I used "Tallán" for my organization name since "Tallán, Inc." threw an exception. If you complete this step successfully, you'll have a certificate request for Alice. Now we can put our CA hat back on and generate a certificate according to Alice's request.

openssl x509 -req -CAcreateserial -
CAkey rootCAKey -days 365 -CA
rootCACert -in aliceCSR -out aliceReply
Loading 'screen' into random state - done
Signature ok
subject=/C=US/ST=Connecticut/L=Glaston
bury/O=Tallan/OU=Server/CN=Alice
Getting CA Private Key
Enter PEM pass phrase: [passphrase]
The resulting aliceReply is a certificate that's valid for 365 days. We return this certificate to Alice, which needs to store this certificate alongside her key pair in her personal keystore.

keytool -import -alias Alice -trust
cacerts -file aliceReply -keystore
aliceStore
Enter keystore password: changeit
Certificate reply was installed in keystore
Great, Alice is all set. Now just repeat the same procedure for Bob. Once you have Bob's certificate stored in bobStore, it's time to work with some code.

There are four classes that we'll use in this demonstration. The first, SSLDemoException, is a simple wrapper around the Exception class. There's nothing to it. The other common class is the abstract base class SSLDemo, which contains some common features of the client and the server. The first item of interest in SSLDemo is the static initializer, where I dynamically add the Cryptographic Service Provider "SunJSSE" to my list of security providers, as described in the JSSE installation instructions. I also override the default keystore used by the TrustManager. This step designates the keystore that holds all my trusted CA certificates.

To improve performance for multiple connection conversations, my constructor preseeds a pseudorandom number generator that will be used to generate each SSLContext. I also load my personal keystore upon construction. My personal keystore holds the certificate chain needed to validate my own certificate. As an example, Alice's personal keystore must hold Alice's certificate and our CA certificate.

Since a good portion of the JSSE-specific logic is encapsulated in my base class, my client and server classes are kept relatively clean of JSSE-specific code. Each must define its personal keystore and use SSL-specific socket factories. In addition, the BobServer conditionally sets client authentication on its SSL-enabled server socket.

Let's put the code into action and step through an SSL conversation. First start the BobServer with client authentication enabled.

java BobServer true
Bob is listening on port: 4242

Then invoke AliceClient
Java AliceClient "Hello Bob, this is Alice"
Sending message to Bob: Hello Bob
Bob's Reply: RE: Hello Bob - Hello Alice, this is Bob.
Done...

The result seems a bit anticlimactic from the outside, but Figure 2 details the more impressive internal workings.

Figure 2

As you can see, client authentication simply requires that the client in the client/server conversation also presents a valid certificate. Since Alice has a valid certificate, AliceClient can talk to BobServer with client authentication enabled or disabled. However, if Alice only had a public/private key pair in aliceStore with no certificate, then Alice would only be able to converse with Bob with client authentication disabled. That demonstration is left as an exercise for the reader. So Alice accepted Bob's certificate and Bob accepted Alice's. They both trusted certificates that we issued as the CA in our PKI.

Conclusion
We've provided you with the ability to act as a CA in a minimalist PKI implementation, and demonstrated how you can integrate your self-certified certificates with J2EE systems via JSSE. Before you rush off to develop SSL-enabled enterprise systems, be aware that I've only exposed you to some fairly complex material. There's a lot more to developing enterprise PKI than simple certificate generation and distribution. I've detailed enough to make you dangerous, but security is only as good as its weakest link. Careful consideration must be given to all areas of a system's security to avoid negating any that SSL might provide.

Resources

  • Java Secure Socket Extension: http://java.sun.com/products/jsse/
  • The OpenSSL Project: www.openssl.org/
  • Netscape's Secure Sockets Layer: www.netscape.com/security/techbriefs/ssl.html

    Author Bio
    Eric Simmerman is a senior consultant in the development division of Tallán, Inc., where he designs and implements numerous enterprise systems in the U.S. and abroad. He's a Java 2 Sun Certified programmer and a Cisco Certified Network Associate and has been developing professionally for seven years.. He holds a BS in computer engineering from Virginia Tech. [email protected]

    	
    
    
    Listing 1: Screen capture of the Certificate Authority key and certificate generation process
    
    openssl req -new -x509 -newkey rsa:2048 -config openssl.cnf -keyout rootCAKey 
    	-out rootCACert -days 3650 -rand "install.log:sunnyday.gif"
    Loading 'screen' into random state - done
    Generating a 2048 bit RSA private key
    .....................+++............+++
    writing new private key to 'rootCAKey'
    Enter PEM pass phrase: [I entered a pass phrase here]
    Verifying password - Enter PEM pass phrase: [I confirmed my pass phrase here]
    -----
    You are about to be asked to enter information that will be incorporated into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [US]:
    State or Province Name (full name) [Connecticut]:
    Locality Name (eg, city) [Glastonbury]:
    Organization Name (eg, company) [Tallán, Inc.]:
    Organizational Unit Name (eg, section) [Development]:
    Common Name (eg, YOUR name) [Eric Simmerman]:
    Email Address [[email protected]]:
    
    Listing 2: Screen capture of a listing of the default cacerts keystore
    
    Enter keystore password:  changeit
    Keystore type: jks
    Keystore provider: SUN
    Your keystore contains 10 entries:
    
    thawtepersonalfreemailca, Fri Feb 12 15:12:16 EST 1999, trustedCertEntry,
    Certificate fingerprint (MD5): 1E:74:C3:86:3C:0C:35:C5:3E:C2:7F:EF:3C:AA:3C:D9
    thawtepersonalbasicca, Fri Feb 12 15:11:01 EST 1999, trustedCertEntry,
    Certificate fingerprint (MD5): E6:0B:D2:C9:CA:2D:88:DB:1A:71:0E:4B:78:EB:02:41
    verisignclass3ca, Mon Jun 29 13:05:51 EDT 1998, trustedCertEntry,
    Certificate fingerprint (MD5): 78:2A:02:DF:DB:2E:14:D5:A7:5F:0A:DF:B6:8E:9C:5D
    thawteserverca, Fri Feb 12 15:14:33 EST 1999, trustedCertEntry,
    Certificate fingerprint (MD5): C5:70:C4:A2:ED:53:78:0C:C8:10:53:81:64:CB:D0:1D
    thawtepersonalpremiumca, Fri Feb 12 15:13:21 EST 1999, trustedCertEntry,
    Certificate fingerprint (MD5): 3A:B2:DE:22:9A:20:93:49:F9:ED:C8:D2:8A:E7:68:0D
    verisignclass4ca, Mon Jun 29 13:06:57 EDT 1998, trusstedCertEntry,
    Certificate fingerprint (MD5): 1B:D1:AD:17:8B:7F:22:13:24:F5:26:E2:5D:4E:B9:10
    verisignclass1ca, Mon Jun 29 13:06:17 EDT 1998, trustedCertEntry,
    Certificate fingerprint (MD5): 51:86:E8:1F:BC:B1:C3:71:B5:18:10:DB:5F:DC:F6:20
    verisignserverca, Mon Jun 29 13:07:34 EDT 1998, trustedCertEntry,
    Certificate fingerprint (MD5): 74:7B:82:03:43:F0:00:9E:6B:B3:EC:47:BF:85:A5:93
    thawtepremiumserverca, Fri Feb 12 15:15:26 EST 1999, trustedCertEntry,
    Certificate fingerprint (MD5): 06:9F:69:79:16:66:90:02:1B:8C:8C:A2:C3:07:6F:3A
    verisignclass2ca, Mon Jun 29 13:06:39 EDT 1998, trustedCertEntry,
    Certificate fingerprint (MD5): EC:40:7D:2B:76:52:67:05:2C:EA:F2:3A:4F:65:F0:D8
    
    Listing 3: Screen capture of a personal key pair generation with the JDK's keytool utility
    
    keytool -genkey -alias Alice -keyalg RSA -keysize 1024 -keystore aliceStore 
    	-validity 365 -storepass changeit
    What is your first and last name?
      [Unknown]:  Alice
    What is the name of your organizational unit?
      [Unknown]:  Client
    What is the name of your organization?
      [Unknown]:  Tallán
    What is the name of your City or Locality?
      [Unknown]:  Glastonbury
    What is the name of your State or Province?
      [Unknown]: Connecticut
    What is the two-letter country code for this unit?
      [Unknown]: US
    Is <CN=Alice, OU=Client, O=Tallán , L=Glastonbury, ST= Connecticut, C=US> 
    	correct?
      [no]:  yes
    
    Enter key password for <Alice>
            (RETURN if same as keystore password): [Hit RETURN to keep things simple]
    
    

    Author's Additional Source Code For this article (~ 6.33 KB ~Zip File Format)

    All Rights Reserved
    Copyright ©  2004 SYS-CON Media, Inc.
      E-mail: [email protected]

    Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.