Sun Java Solaris Communities My SDN Account Join SDN
 
Article

Exploring the Security Changes of the 1.4 Release of the Java 2 Standard Edition

 
 

Articles Index

2 Platform Standard Edition (J2SE )

Security is an important aspect of programming these days. As applications get distributed around the Net piecemeal, those application pieces need to protect the parts of their underlying framework that were once assumed to be built into the main application. Along with these changes, the underlying Java 2 platform release has evolved to incorporate more and more features into the J2SE release 1.4 to provide a secure environment to execute mobile code.

With this latest 1.4 release, you'll find many enhancements in the security architecture. Several features that were previously available separately are now part of the core API set. These include support for encryption and decryption with the Java Cryptography Extension (JCE), support for Secure Sockets Layer (SSL) and Transport Layer Security (TLS) protocols with the Java Secure Socket Extension (JSSE), and support for user-based authentication and access controls with the Java Authentication and Authorization Service (JAAS). In addition to the inclusion of these previously optional packages, you'll find new support for building and verifying certificate chains with the Java Certification Path API and support for the Kerberos V5 mechanism under Java GSS-API and JAAS. Additional enhancements were made in improving the security policy-managing tool, policytool, and in adding support for dynamically loading security policies.

The following sections introduce all these features and examine them in more detail.

Java Cryptography Extension

Within the libraries of the Java Cryptography Extension (JCE), you'll find support for encryption, decryption, key agreement, Message Authentication Code (MAC), and some other cryptographic services. Due to import control restrictions of some countries, the JCE jurisdiction policy files shipped with the Java 2 SDK, release 1.4 allow "strong" but limited cryptography to be used. An "unlimited strength" version of these files indicating no restrictions on cryptographic strengths is available for those living in eligible countries (most countries). You can download this version and replace the string cryptography versions supplied with the Java 2 SDK, release 1.4 with the unlimited ones.

Found in the javax.crypto package, the JCE libraries convert plain text to cipher text and back. The key class here is Cipher, which determines the crypto algorithm used for encryption and decryption. Through the convenience of the CipherOutputStream and CipherInputStream classes, these I/O filtering streams can do encrypting or decrypting. Pass in an appropriate stream to the constructor, and they do their task when you write to or read from the stream. The only thing you really have to worry about is key management and what Cipher algorithm to use.

To demonstrate the JCE API, the following program encrypts a series of objects and decrypts them back. The example uses the Data Encryption Standard (DES) as the encryption algorithm. For a complete list of supported algorithms, see the Java Cryptography Extension (JCE) Reference Guide.

Code Sample 1: Demonstrating the JCE API by encrypting and decrypting a series of objects

import java.io.*; 
import javax.crypto.*; 
import javax.crypto.spec.*; 
import java.security.*; 
import java.security.spec.*; 
import java.util.*; 
 
public class EncryptTest { 
 
  public static void main(String args[]) { 
 
    File desFile = new File("out.des"); 
 
    // Create data to encrypt 
    Map map = new TreeMap(System.getProperties()); 
    int number = map.size(); 
 
    try { 
 
      // Create Key 
      KeyGenerator kg = KeyGenerator.getInstance("DES"); 
      SecretKey secretKey = kg.generateKey(); 
 
      // Create Cipher 
      Cipher desCipher = 
        Cipher.getInstance("DES/ECB/PKCS5Padding"); 
      desCipher.init(Cipher.ENCRYPT_MODE, secretKey); 
 
      // Create stream 
      FileOutputStream fos = new FileOutputStream(desFile); 
      BufferedOutputStream bos = new BufferedOutputStream(fos); 
      CipherOutputStream cos = new CipherOutputStream(bos, 
        desCipher); 
      ObjectOutputStream oos = new ObjectOutputStream(cos); 
 
      // Write objects 
      oos.writeObject(map); 
      oos.writeInt(number); 
      oos.flush(); 
      oos.close(); 
 
      // Change cipher mode 
      desCipher.init(Cipher.DECRYPT_MODE, secretKey); 
 
      // Create stream 
      FileInputStream fis = new FileInputStream(desFile); 
      BufferedInputStream bis = new BufferedInputStream(fis); 
      CipherInputStream cis = new CipherInputStream(bis, 
        desCipher); 
      ObjectInputStream ois = new ObjectInputStream(cis); 
 
      // Read objects 
      Map map2 = (Map)ois.readObject(); 
      int number2 = ois.readInt(); 
      ois.close(); 
 
      // Compare original with what was read back 
      if (map.equals(map2) && (map.size() == number2)) { 
        System.out.println("Everything read back out okay."); 
      } else { 
        System.out.println("Problems during 
          encryption/decryption process."); 
      } 
    } catch (NoSuchPaddingException e) { 
      System.err.println("Padding problem: " + e); 
    } catch (NoSuchAlgorithmException e) { 
      System.err.println("Invalid algorithm: " + e); 
    } catch (InvalidKeyException e) { 
      System.err.println("Invalid key: " + e); 
    } catch (IOException e) { 
      System.err.println("I/O Problem: " + e); 
    } catch (ClassNotFoundException e) { 
      System.err.println("Class loading Problem: " + e); 
    } finally { 
      if (desFile.exists()) { 
        desFile.delete(); 
      }  
    } 
  } 
}

Java Secure Socket Extension

Next up comes the Java Secure Socket Extension (JSSE) library. Here, you'll find support for communicating using the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) protocols. Where the JCE operates on specific local data structures, the JSSE uses a different abstraction, applying encryption/decryption to network socket traffic. It adds server authentication, message integrity, and optional client authentication. Most people think of SSL and TLS as the secure HTTP protocol, better known as HTTPS.

The JSSE library lives in the javax.net and javax.net.ssl packages. To use SSL for your socket communications, instead of creating a Socket from its constructor, you must go through a secondary mechanism. First you get a SocketFactory from the SSLSocketFactory, and then you create the Socket from the factory. Once you have a secure connection, data is encrypted or decrypted simply by writing to or reading from the socket. Other higher-level protocols can be built on top of this mechanism, for example HTTPS.

SSL (and thus HTTPS) permits encrypted traffic to be exchanged between the client and server. After an SSL client initiates a conversation with an SSL server, the server sends an X.509 certificate back to the client for authentication. The client then checks the validity of the certificate. Assuming the server is verified, the client generates a premaster secret key, encrypts it with the server's public key from the certificate, and sends the encrypted key back to the server. From this premaster key, the client and server generate a master key for the session. After some basic handshaking, the encrypted exchange can commence.

The JSSE library hides these inner workings of the SSL protocol from you. Just work with the Socket created from the factory like a normal socket.

The following example demonstrates the use of the JSSE library. It reads a web page using SSL. Even though the GET command sent to the server says to use the HTTP protocol, because the Socket was created from the SSLSocketFactory, SSL is used to communicate with the server to send the page request and get the response.

Code Sample 2: Demonstrating the use of the JSSE library by reading a Web page through port 443, the HTTPS port

import java.io.*; 
import java.net.*; 
import javax.net.*; 
import javax.net.ssl.*; 
 
public class JSSE { 
   static final int HTTPS_PORT = 443; 
   public static void main(String args[]) { 
       String hostname; 
 
       // Get hostname or use VeriSign 
       if (args.length == 0) { 
           hostname = "www.verisign.com"; 
       } else { 
           hostname = args[0]; 
       } 
 
       try { 
 
           // Get Socket factory 
           SocketFactory factory = SSLSocketFactory.getDefault(); 
 
           // Get Socket from factory 
           Socket s = factory.createSocket(hostname, HTTPS_PORT); 
 
           // Send request 
           OutputStream os = s.getOutputStream(); 
           PrintWriter pw = new PrintWriter(os); 
 
           // Setup command 
           String command = "GET / HTTP/1.0\r\n\r\n";
 
           pw.print(command); 
           pw.flush(); 
 
           // Get response 
           InputStream is = s.getInputStream(); 
           InputStreamReader isr = new InputStreamReader(is); 
           BufferedReader br = new BufferedReader(isr); 
 
           String line; 
 
           while ((line = br.readLine()) != null) { 
               System.out.println(line); 
           } 
 
           pw.close(); 
           br.close(); 
           s.close(); 
 
       } catch (IOException e) { 
           System.err.println("Error reading: " + e); 
       } 
   } 
}

In the case of creating a server instead of a client, you would get a ServerSocket from the SSLServerSocketFactory.

Also note that the JSSE libraries found in the J2SE version 1.4 release are not the same as those still available as the JSSE 1.0.2 release. For instance, the com.sun.net.ssl package is now the javax.net.ssl package, and there are both new and modified interfaces and classes. With Sun's J2SE version 1.4 release, wrapper classes allow interactions with the JSSE 1.02 release for backward compatibility.

Java Authentication and Authorization Service

Third up is Java Authentication and Authorization Service (JAAS). Starting in javax.security.auth and working with several subpackages, JAAS provides for the authentication of users and the authorization of tasks based upon that authentication. This is an enhancement to the prior standard security model capabilities of enabling a specific set of tasks based on authentication. Previously, anyone authenticated had access to the same security restrictions. Now, you can control what tasks are available for a specific authenticated user.

A complete example for the JAAS is a little more involved than the other APIs due to the need to modify security policies. You can find a detailed tutorial and sample program in the JAAS reference guide.

Essentially, here is how everything works. Authentication is done through a LoginContext. You register a CallbackHandler with the context. The context reads the Configuration and works with a LoginModule for a particular application. Based on the authentication information required by the LoginModule, various Callback implementors will be notified. For instance, when the username and password are requested by a LoginModule, the CallbackHandler is invoked with a NameCallback and PasswordCallback. The item that is authenticated is called the Subject. This Subject holds various Principal and Credential objects that describe credentials the Subject has access to. A Principal represents the individual identity for a user, while a Credential represents the security-related attributes owned by a user.

JAAS also supports authorization. A systemwide access control policy, represented by the Policy object, can be configured to restrict user access to sensitive resources. To give users access to these resources, permissions must be granted to those users in the policy configuration.

Java GSS-API

The Java GSS-API (Generic Security Service) adds Kerberos V5 support to the Java platform. If you're not familiar with Kerberos, this is something that originated at the Massachusetts Institute of Technology (MIT) as project Athena back in 1987. Essentially, Kerberos is a network authentication protocol. Defined in RFC 1510 from 1993, the authentication service's biggest draw is not having to send passwords over the net. It offers single sign-on within one domain -- if everything within the domain has been Kerberos-enabled. Support is also provided for single sign-on across different security realms over a network. Used in conjunction with JAAS, once a user's identity is established, future authentication requests are no longer necessary.

Using Kerberos on your desktop requires a Kerberos Key distribution server to be available. If you don't have a Kerberos realm available, you cannot use this aspect of the Java 2 platform, version 1.4 security API. Found in the javax.security.auth.kerberos, its usage is closely tied to the JAAS API.

Java Certification Path API

Last is the fifth of the now standard libraries, and the second completely new library. The Java Certification Path API provides classes for building and validating certificate chains, an important requirement of a Public Key Infrastructure (PKI). These certificates provide for the storage of security keys for users. By trusting the issuer of a certificate that holds the keys, and trusting the issuer of the certificate that trusts the original certificate, you establish chains of trust. By following this certificate path chain, you eventually either end up with a certificate issued by a Certification Authority (CA) that you trust or a certificate issued by a CA that you don't trust. Thus, the relying party can ensure a subject's public key is genuine and trusted based on the trustworthiness of the underlying certificate chain.

Found in the java.security.cert package, you'll find classes and interfaces to generate, validate, and hold certificates, certification paths, and their parameters. Again, due to the complexity of the API, I'll refer you to the Java Certification Path API Guide for an example that demonstrates the use of the API rather than showing you an oversimplified one here. Building and validating certification paths is an important part of many standard security protocols, such as SSL/TLS, Secure/MIME (S/MIME), and IP Security (IPsec). Now there is a standard Java API for accessing standard algorithms for creating, building, and validating certification paths in an implementation-independent manner.

And the Rest

Not all security-related changes are as big as the five previously mentioned libraries. The biggest changes here have to do with the policytool program that comes with the SDK and the querying of security policies. In the case of the policytool program, you can now grant a Permission to a specific Principal. With regards to security policies, you'll find a welcome change of support for dynamic security policies.

Conclusion

J2SE version 1.4 adds many security-related capabilities to the standard Java 2 platform release. With these newly incorporated features, the execution of mobile code is more secure as it becomes unnecessary to require users to install the previously optional services. You no longer have to worry about adding in additional libraries for users to communicate securely. In addition, with new features like the crypto-chain validation, verification of paths is no longer implementation specific. One can only wonder what's in store for version 1.5.

For More Information

About the Author

John Zukowski conducts strategic Java consulting with JZ Ventures, Inc. His latest books are Learn Java with JBuilder 6 from Apress and Mastering Java 2, J2SE v. 1.4 from Sybex. Contact John at jaz@zukowski.net.