Monday, October 30, 2006

Writing a simple bean


In this section you will learn more about Beans and the
BeanBox by

  • Creating a simple Bean
  • Compiling and saving the Bean into a
    Java Archive (JAR) file
  • Loading the Bean into the ToolBox
  • Dropping a Bean instance into the BeanBox
  • Inspecting the Bean's properties, methods, and events
  • Generating an introspection report



Your Bean will be named SimpleBean.
Here are the steps to create it and view it in the BeanBox:


  1. Write the SimpleBean code. Put it in a file
    named SimpleBean.java, in the directory
    of your choice. Here's the code:
       
    import java.awt.*;
    import java.io.Serializable;

    public class SimpleBean extends Canvas
    implements Serializable
    {
    //Constructor sets inherited properties
    public SimpleBean(){
    setSize(60,40);
    setBackground(Color.red);
    }
    }


    SimpleBean extends the
    java.awt.Canvas component.

    SimpleBean also implements the
    java.io.Serializable interface,
    a requirement for all Beans. SimpleBean sets the background
    color and component size.


  2. Make sure the CLASSPATH
    environment variable is set
    to point to all
    needed .class (or .jar) files. Here
    are some URLs that will help you to set CLASSPATH correctly:



  3. Compile the Bean:

    javac SimpleBean.java

    This produces the class file SimpleBean.class


  4. Create a manifest file. Use your favorite text editor
    to create a file, we'll call it manifest.tmp,
    that contains the following text:


    Name: SimpleBean.class
    Java-Bean: True

  5. Create the JAR file. The JAR file will contain the
    manifest and the SimpleBean class file:

    jar cfm SimpleBean.jar manifest.tmp SimpleBean.class

    See the
    Packaging Programs in JAR Files trail, and the

    JDK JAR file documentation for complete information on JAR files.



  6. Load the JAR file into the ToolBox. Select
    the File|LoadJar... menu item. This will bring up a
    file browser. Navigate to the SimpleBean.jar location and
    select it. SimpleBean will appear at the bottom
    of the ToolBox. (Note that when the BeanBox is
    started, all Beans in JAR files in the
    beans/jars directory are automatically
    loaded into the ToolBox).



  7. Drop a SimpleBean instance into the BeanBox.
    Click on the word SimpleBean in the ToolBox. The cursor
    will change to a crosshair. Move the cursor to a spot within the
    BeanBox and click. SimpleBean will appear as a
    painted rectangle with a hatched border. This border means
    that SimpleBean is selected. The
    SimpleBean properties will appear in the
    Properties sheet.




You can resize SimpleBean, because it inherits from
Canvas, by dragging a corner. You will see the cursor
change to a right angle when over a corner. You can also reposition
SimpleBean within the BeanBox by dragging on any non-corner
portion of the hatched border. You will see the cursor change to crossed
arrows when in position to move the Bean.


SimpleBean Makefiles




Below are two makefiles (Unix and Windows) set up to
create SimpleBean.





# gnumake file

CLASSFILES= SimpleBean.class

JARFILE= SimpleBean.jar

all: $(JARFILE)

# Create a JAR file with a suitable manifest.
$(JARFILE): $(CLASSFILES) $(DATAFILES)
echo "Name: SimpleBean.class" >> manifest.tmp
echo "Java-Bean: True" >> manifest.tmp
jar cfm $(JARFILE) manifest.tmp *.class
@/bin/rm manifest.tmp

# Compile the sources
%.class: %.java
export CLASSPATH; CLASSPATH=. ; javac $<

# make clean
clean:
/bin/rm -f *.class
/bin/rm -f $(JARFILE)




Here is the Windows nmake version:




# nmake file
CLASSFILES= simplebean.class

JARFILE= simplebean.jar

all: $(JARFILE)

# Create a JAR file with a suitable manifest.

$(JARFILE): $(CLASSFILES) $(DATAFILES)
jar cfm $(JARFILE) <<manifest.tmp *.class
Name: SimpleBean.class
Java-Bean: True
<<

.SUFFIXES: .java .class

{sunw\demo\simple}.java{sunw\demo\simple}.class :
set CLASSPATH=.
javac $<

clean:
-del sunw\demo\simple\*.class
-del $(JARFILE)



You can use these makefiles as templates for creating your own
Bean makefiles. The example Bean makefiles, in the
beans/demo directory, also show you how to use
makefiles to build and maintain your Beans.




Inspecting SimpleBean Properties and Events





The Properties sheet displays the selected Bean's properties.
With SimpleBean selected, the Properties
sheet displays four propeties: foreground,
background, font, and name.
We declared no properties in SimpleBean
(see the Properties section to learn
how to declare properties), so these are properties inherited from

Canvas. Clicking on each property brings up a property
editor. The BeanBox provides default property editors
for the primitive types, plus Font and Color
types. You can find the sources for these property editors in
beans/apis/sun/beans/editors.


Beans communicate with other Beans by sending and
receiving event notifications.
To see which events SimpleBean can send, choose
the Edit|Events BeanBox menu item. A list of events,
grouped by the Java interface in which the event method is
declared, will be displayed. Under each interface
group is a list of event methods. These are all
inherited from Canvas.


You will learn more about

properties and
events in
upcoming sections.



Generating Bean Introspection Reports




Introspection is the process of discovering a
Bean's design-time features by one of two
methods:


  • Low-level reflection, which uses design
    patterns to discover your Bean's features
  • By examining an associated
    bean information

    class that explicitly describes your Bean's features.



You can generate a Bean introspection report
by choosing the Edit|Report menu item. The
report lists Bean events, properties, and methods,
and their characteristics.


By default Bean reports are sent
to the java interpreter's standard output, which is the window
where you started the BeanBox. You can redirect the
report to a file by changing the java interpreter
command in beanbox/run.sh or
run.bat to:


java sun.beanbox.BeanBoxFrame > beanreport.txt


Writing a Simple Bean

In this section you will learn more about Beans and the BeanBox by
Creating a simple Bean
Compiling and saving the Bean into a Java Archive (JAR) file
Loading the Bean into the ToolBox
Dropping a Bean instance into the BeanBox
Inspecting the Bean's properties, methods, and events
Generating an introspection report
Your Bean will be named SimpleBean. Here are the steps to create it and view it in the BeanBox:
Write the SimpleBean code. Put it in a file named SimpleBean.java, in the directory of your choice. Here's the code:

import java.awt.*;
import java.io.Serializable;

public class SimpleBean extends Canvas
implements Serializable
{
//Constructor sets inherited properties
public SimpleBean(){
setSize(60,40);
setBackground(Color.red);
}
}
SimpleBean extends the java.awt.Canvas component. SimpleBean also implements the java.io.Serializable interface, a requirement for all Beans. SimpleBean sets the background color and component size.
Make sure the CLASSPATH environment variable is set to point to all needed .class (or .jar) files. Here are some URLs that will help you to set CLASSPATH correctly:
The Managing Source and Class Files lesson gives good advice on how and when to set your CLASSPATH.
The JDK Tool Reference Page provides complete CLASSPATH information for both Windows and Solaris platforms.
Compile the Bean: javac SimpleBean.java
This produces the class file SimpleBean.class
Create a manifest file. Use your favorite text editor to create a file, we'll call it manifest.tmp, that contains the following text: Name: SimpleBean.class
Java-Bean: True

Create the JAR file. The JAR file will contain the manifest and the SimpleBean class file: jar cfm SimpleBean.jar manifest.tmp SimpleBean.class
See the Packaging Programs in JAR Files trail, and the JDK JAR file documentation for complete information on JAR files.
Load the JAR file into the ToolBox. Select the FileLoadJar... menu item. This will bring up a file browser. Navigate to the SimpleBean.jar location and select it. SimpleBean will appear at the bottom of the ToolBox. (Note that when the BeanBox is started, all Beans in JAR files in the beans/jars directory are automatically loaded into the ToolBox).
Drop a SimpleBean instance into the BeanBox. Click on the word SimpleBean in the ToolBox. The cursor will change to a crosshair. Move the cursor to a spot within the BeanBox and click. SimpleBean will appear as a painted rectangle with a hatched border. This border means that SimpleBean is selected. The SimpleBean properties will appear in the Properties sheet.
You can resize SimpleBean, because it inherits from Canvas, by dragging a corner. You will see the cursor change to a right angle when over a corner. You can also reposition SimpleBean within the BeanBox by dragging on any non-corner portion of the hatched border. You will see the cursor change to crossed arrows when in position to move the Bean.
SimpleBean Makefiles
Below are two makefiles (Unix and Windows) set up to create SimpleBean.
# gnumake file
CLASSFILES= SimpleBean.class
JARFILE= SimpleBean.jar
all: $(JARFILE)
# Create a JAR file with a suitable manifest.
$(JARFILE): $(CLASSFILES) $(DATAFILES)
echo "Name: SimpleBean.class" >> manifest.tmp
echo "Java-Bean: True" >> manifest.tmp
jar cfm $(JARFILE) manifest.tmp *.class
@/bin/rm manifest.tmp
# Compile the sources
%.class: %.java
export CLASSPATH; CLASSPATH=. ; javac $<
# make clean
clean:
/bin/rm -f *.class
/bin/rm -f $(JARFILE)
Here is the Windows nmake version:
# nmake file
CLASSFILES= simplebean.class
JARFILE= simplebean.jar
all: $(JARFILE)
# Create a JAR file with a suitable manifest.
$(JARFILE): $(CLASSFILES) $(DATAFILES)
jar cfm $(JARFILE) <Name: SimpleBean.class
Java-Bean: True
<<
.SUFFIXES: .java .class
{sunw\demo\simple}.java{sunw\demo\simple}.class :
set CLASSPATH=.
javac $<
clean:
-del sunw\demo\simple\*.class
-del $(JARFILE)
You can use these makefiles as templates for creating your own Bean makefiles. The example Bean makefiles, in the beans/demo directory, also show you how to use makefiles to build and maintain your Beans.
Inspecting SimpleBean Properties and Events
The Properties sheet displays the selected Bean's properties. With SimpleBean selected, the Properties sheet displays four propeties: foreground, background, font, and name. We declared no properties in SimpleBean (see the Properties section to learn how to declare properties), so these are properties inherited from Canvas. Clicking on each property brings up a property editor. The BeanBox provides default property editors for the primitive types, plus Font and Color types. You can find the sources for these property editors in beans/apis/sun/beans/editors.
Beans communicate with other Beans by sending and receiving event notifications. To see which events SimpleBean can send, choose the EditEvents BeanBox menu item. A list of events, grouped by the Java interface in which the event method is declared, will be displayed. Under each interface group is a list of event methods. These are all inherited from Canvas.
You will learn more about properties and events in upcoming sections.
Generating Bean Introspection Reports
Introspection is the process of discovering a Bean's design-time features by one of two methods:
Low-level reflection, which uses design patterns to discover your Bean's features
By examining an associated bean information class that explicitly describes your Bean's features.
You can generate a Bean introspection report by choosing the EditReport menu item. The report lists Bean events, properties, and methods, and their characteristics.
By default Bean reports are sent to the java interpreter's standard output, which is the window where you started the BeanBox. You can redirect the report to a file by changing the java interpreter command in beanbox/run.sh or run.bat to:
java sun.beanbox.BeanBoxFrame > beanreport.txt

Sunday, October 22, 2006

Cryptography and security on java se 6

The Java Platform, Standard Edition (Java SE) provides application developers with a large set of security APIs, tools, and implementations of commonly used security algorithms, mechanisms, and protocols. These security APIs span a wide range of areas, including cryptography, public key infrastructure, secure communication, authentication, and access control. In addition, the security tools facilitate the ability of users or administrators to securely deploy and manage Java platform applications.

As technology evolves, native platforms undergo many security improvements, for example, cryptographic accelerators, secure key management, more built-in security services, and so on. Leveraging the security offered by the native platform provides several significant benefits to the Java platform: They include but are not limited to the performance boost that cryptographic accelerators provide, a consistent behavior that matches what native applications have when they use the same native library, and the seamless sharing of users' native credentials.

This article will discuss important enhancements on the native security integration using JDK 6. Note: Any API additions or other enhancements to the Java SE platform specification are subject to review and approval by the JSR 270 Expert Group.

After an overview, this article will cover each feature in turn and illustrate the common usage scenarios with examples and sample code. To better understand the examples, you should familiarize yourself with existing security APIs and security provider frameworks. If you are new to Java security, see the Java Security Overview. Additional links are available in the For More Information section at the end of this article.

Note that the enhancements that this article discusses may not be available for all native platforms. The Appendix provides more details, including the first JDK release in which each feature was introduced as well as the native platforms that each feature supports.

Contents

- Access Microsoft CryptoAPI and Its Cryptographic Services
- Access PKCS#11 Cryptographic Services
- Access Native GSS-API
- Import and Export PKCS#12 Keystores
- Conclusion
- Appendix
- For More Information

Access Microsoft CryptoAPI and Its Cryptographic Services

On the Microsoft (MS) Windows operating system, the MS CryptoAPI (CAPI) defines a standard interface for performing cryptographic operations as well as accessing the user keys and certificates that Windows manages. The SunMSCAPI provider is layered on top of CAPI and helps Java platform applications access CAPI cryptographic services using existing Java technology security and cryptography APIs. This means that Java platform applications can now use the SunMSCAPI provider to do the following:

  • Access private keys and certificates stored in CAPI
  • Use CAPI's cryptographic algorithm implementations

Table 1 shows the complete list of cryptographic services that the SunMSCAPI provider supports.

Table 1. Cryptographic Services Supported by the SunMSCAPI Provider

Service Type
Service Name
Service Description

RSA

Generates RSA key pairs needed by other cryptographic services such as Signature and Cipher.

SHA1withRSA
MD5withRSA
MD2withRSA

Creates and validates signatures using various message digest and encryption algorithm as specified in the service name.

RSA
RSA/ECB/PKCS1Padding

Performs RSA encryption and decryption.

Windows-MY
Windows-ROOT

Provides direct read-write access to MS Window's keystores. The Windows-MY keystore contains the user's private keys and the associated certificate chains. The Windows-ROOT keystore contains all root CA certificates trusted by the machine.

Windows-PRNG

Generates random numbers for the random data that other cryptographic services need.


Note that JDK 6 is preconfigured with multiple providers that are listed in order of preference -- with position 1 being most preferred -- as defined in the Java technology security properties file, /lib/security/java.security. More than one provider supports RSA cryptographic services: The SunRsaSign provider offers the RSA KeyPairGenerator and Signature services and the SunJCE provider offers the RSA Cipher service. By default, the SunMSCAPI provider is installed with a preference lower than both to ensure maximum compatibility. A Java platform application that does not indicate which provider to use will get the implementation from the most preferred provider that supports the requested algorithm. You can find more details on provider lookup and management in the section "How Provider Implementations Are Requested and Supplied" of the Java Cryptography Architecture document.

Keys and certificates stored in MS Windows key containers and certificate stores, known as keystores, can be accessed by using the java.security.KeyStore class and the SunMSCAPI provider. The same set of KeyStore APIs are used for accessing MS Windows keystores and other types of keystores, such as JKS or PKCS12. However, because MS Windows keystores do not use passwords and cannot be imported or exported, values for password and input-output stream arguments should be null. By default, the SunMSCAPI provider silently ignores non-null values. In addition, changes are reflected immediately when making modifications to the keystore, such as KeyStore.setKeyEntry(...), KeyStore.deleteEntry(...).

For example, here is one way to sign data by using the RSA private key stored in the MS Windows keystore under the alias myRSA and then to verify the generated signature:

        KeyStore ks = KeyStore.getInstance("Windows-MY");
// Note: When a security manager is installed,
// the following call requires SecurityPermission
// "authProvider.SunMSCAPI".
ks.load(null, null);

byte[] data = ...
String alias = "myRSA";

PrivateKey privKey = (PrivateKey) ks.getKey(alias, null);
Certificate cert = ks.getCertificate(alias);

Provider p = ks.getProvider();
Signature sig = Signature.getInstance("SHA1withRSA", p);
sig.initSign(privKey);
sig.update(data);
byte[] signature = sig.sign();
System.out.println("\tGenerated signature...");
sig.initVerify(cert);
sig.update(data);
if (sig.verify(signature)) {
System.out.println("\tSignature verified!");
}

Note that keys produced by the SunMSCAPI provider are wrapper objects for the native handles. Thus, they may not be accepted by other providers and may behave somewhat differently than keys produced by pure-Java providers, such as SunJCE. In particular, the RSA private keys generated by the SunMSCAPI provider cannot be serialized and implement the java.security.PrivateKey interface instead of the java.security.interfaces.RSAPrivateKey interface.

If you are writing a Java platform application and want to use the keys and certificates from MS Windows keystores with Java Secure Socket Extension (JSSE), refer to the JSSE Reference Guide for instructions on how to customize the default key and trust stores.

Access PKCS#11 Cryptographic Services

PKCS#11, the Cryptographic Token Interface Standard, defines native programming interfaces to cryptographic tokens such as hardware cryptographic accelerators and smart cards. To help Java platform applications access native PKCS#11 tokens, a new provider was introduced in JDK 5.0 to act as a bridge between the native PKCS#11 tokens and the applications.

This means that Java platform applications can now use existing security and cryptography APIs in the Java platform to take advantage of benefits offered by the underlying PKCS#11 implementations, such as the following:

  • Cryptographic smart cards for added security
  • Hardware cryptographic accelerators for better performance
  • Software implementations for more algorithms or for meeting certification requirements

Note that this provider does not come with its own PKCS#11 implementation and simply uses what it is configured with. On the Solaris 10 operating system, it is preconfigured to use the Solaris Cryptographic Framework. Thus, when the particular machine has cryptographic accelerators built in, all existing Java platform applications benefit automatically without requiring any changes to the configuration or code. To use other PKCS#11 tokens or implementations, the PKCS#11 provider requires a configuration file that supplies information on the PKCS#11 library, which most vendors provide along with their cryptographic devices, as well as a unique name identifier for differentiating this provider from other providers.

The configuration file is a text file that contains mappings of options and their values. Most of the options are for regular PKCS#11 libraries, except for the small number of options specific to Network Security Services (NSS). NSS is an open-source FIPS-140 certified cryptographic implementation used in a variety of products including Mozilla Firefox, AOL Communicator, and Sun Java Enterprise System (JES). NSS cryptographic APIs are based on PKCS#11, but they have special features outside of the PKCS#11 standard and thus require these special configuration options.

NSS is often used in one of the following two modes: as a cryptographic provider for its optimized cryptographic algorithm implementations or as an FIPS-140 compliant cryptographic token.

Assuming that NSS libraries are under the /opt/nss/lib directory and that its key database files -- with the suffix .db -- are under the /opt/nss/fipsdb directory, the sample configurations for using NSS are as follows:

        # Use NSS as a pure cryptography provider "SunPKCS11-NSScrypto".
name = NSScrypto
nssLibraryDirectory = /opt/nss/lib
nssDbMode = noDb
attributes = compatibility

# Use NSS as a FIPS-140 compliant cryptographic token from
# provider "SunPKCS11-NSSfips."
name = NSSfips
nssLibraryDirectory = /opt/nss/lib
nssSecmodDirectory = /opt/nss/fipsdb
nssModule = fips

The configuration of non-NSS PKCS#11 libraries contains at least two options: a string that is concatenated with the prefix SunPKCS11- to produce the name of the PKCS#11 provider as well as the full path to the native PKCS#11 libraries. The sample configuration for naming the PKCS#11 provider to SunPKCS11-Foo using the PKCS#11 library at /opt/foo/lib/libpkcs11.sois as follows:

        name = Foo
library = /opt/foo/lib/libpkcs11.so

You can use other configuration options to further customize the provider. You can also use more than one PKCS#11 token or use multiple slots of the same PKCS#11 token by creating different PKCS#11 providers. Refer to the Java PKCS#11 Reference Guide for the supported options and their use.

Just like other providers, a PKCS#11 provider can be installed dynamically at runtime or statically in the Java technology security properties file, $JAVA_HOME/lib/security/java.security. You can use the following code to programmatically create and install the PKCS#11 provider at runtime:

        String configFileName = "/opt/foo/sunpkcs11-Foo.cfg";

Provider myPKCS11Prov =
new sun.security.pkcs11.SunPKCS11(configFileName);
Security.insertProviderAt(myPKCS11Prov, 1);

To statically install the PKCS#11 provider, add the following provider preference entry to the Java technology security properties file:

        security.provider.1=sun.security.pkcs11.SunPKCS11        /opt/foo/sunpkcs11-Foo.cfg

You can find more details on provider lookup and management in the section "How Provider Implementations Are Requested and Supplied" of the Java Cryptography Architecture document.

With this new PKCS#11 provider, Java platform applications can access their PKCS#11 tokens and perform general cryptographic operations such as signature generation and verification through existing security APIs. For certain PKCS#11 features such as dynamically changing smart cards, JDK 6 contains a number of enhancements to better support those features, including added new APIs, updated tools, and so on.

For example, to access private keys on a PKCS#11 token and prompts for a personal identification number (PIN) at runtime, use this code:

// TextCallbackHandler prompts and reads the command line for
// name and password information.
CallbackHandler cmdLineHdlr =
new com.sun.security.auth.callback.TextCallbackHandler();
KeyStore.Builder ksBuilder = KeyStore.Builder.getInstance(
"PKCS11",
null,
new KeyStore.CallbackHandlerProtection(cmdLineHdlr));

KeyStore ks = ksBuilder.getKeyStore();

// Specify "null" as the password here and use the supplied
// CallBackHandler "cmdLineHdlr" to get the password if needed.
Key key = ks.getKey(alias, null);

For PKCS#11 tokens that require a PIN even for operations not related to a key, Sun's PKCS#11 provider extends the java.security.AuthProvider class, which allows Java platform applications to supply PINs when needed using the registered callback handler. Note that the callback handler must be able to handle objects of type javax.security.auth.callback.PasswordCallback:

AuthProvider myPKCS11Prov =
(AuthProvider) Security.getProvider("SunPKCS11-Foo");

myPKCS11Prov.setCallbackHandler(cmdLineHdlr);

myPKCS11Prov.login(null, null);

// Now logged in, applications can proceed to use the PKCS#11
// tokens as usual. When done, call AuthProvider.logout().
...

To learn more about using JSSE with PKCS#11 cryptographic services, read the section "JCE and Hardware Acceleration/Smartcard Support" in the JSSE Reference Guide.

Security tools such as keytool, jarsigner, and policytool are updated in JDK 6 to support PKCS#11 keystores as well. For example, to list the PKCS#11 keystore content using keytool, use this code:

// When "SunPKCS11-Foo" provider is statically installed
// by way of Java technology security property file
keytool -list -keystore NONE -storetype pkcs11 -providerName SunPKCS11-Foo

// When "SunPKCS11-Foo" provider is NOT statically installed
keytool -list -keystore NONE -storetype pkcs11 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg /opt/foo/sunpkcs11-Foo.cfg

Note that keytool will prompt users to enter the PIN information using the command line because the code in the previous sample has not supplied one using the option -storepass. If such behavior is not desired in the application, for example, if the PKCS#11 token has its own dedicated PIN pad, you must specify the option -protected to disable the prompting.

The jarsigner tool supports PKCS#11 keystores with the same set of options as in the keytool example and is quite straightforward. JDK 6 has enhanced the syntax of the keystore entry in the default policy implementation to better support PKCS#11 keystores:

keystore "some_ks_url", "ks_type"[, "ks_provider"];
[keystorePasswordURL "some_password_url";]

The elements inside the square brackets ([ ]) are optional. Using the PKCS11-Foo provider from the previous examples and assuming its PIN is stored in a file named /opt/foo/sunpkcs11-Foo.passwd, specify the following entry in the policy file:

keystore "NONE", "PKCS11", "SunPKCS11-Foo";
keystorePasswordURL file:/opt/foo/sunpkcs11-Foo.passwd;

Note that the SunPKCS11-Foo provider must be installed statically in order for policytool to validate this keystore entry after it is entered.

Access Native GSS-API

The Generic Security Services API (GSS-API) defines a generic security API atop a variety of underlying cryptographic mechanisms including Kerberos version 5. With GSS-API, applications can authenticate a principal, delegate its rights to a peer, and apply security services such as confidentiality and integrity on a per-message basis. Request for Comment (RFC) 2744 and RFC 2853 specify the GSS-API language bindings for C and the Java programming language, respectively.

To help Java platform applications achieve seamless integration with native applications, JDK 6 enhances Java GSS-API to use native GSS-API instead of its own implementation of cryptographic mechanisms when configured to do so. When using the native GSS-API and its underlying native cryptographic mechanisms, the native credentials and settings in users' environment will be picked up automatically. This is different from the default case in which Java GSS-API uses its own implementation of cryptographic mechanisms. When using Kerberos, Java platform applications have to supply Kerberos configuration information using the designated Kerberos system properties in order for Java GSS-API to function. Existing Java GSS documentation covers the default case in great detail, so this section will focus on how to enable or configure Java GSS-API to use native GSS-API. At the end of this section, you will find sample programs that illustrate the point.

Before you enable Java GSS-API to use native GSS-API, it is important to ensure that native GSS-API and its underlying cryptographic mechanism are available and functioning with user settings. For example, you must ensure that native GSS libraries are installed at the appropriate directories with proper configurations, and the same applies to the Kerberos library and configurations. Note that native GSS-API assumes that before an application calls its APIs, it has already obtained and stored the mechanism-specific credentials in a location that the native mechanism implementation is aware of. Thus, when an application uses native GSS-API with Kerberos, it must already have obtained appropriate native credentials, such as Kerberos tickets and keys, using the kinit tool, for example.

To make Java GSS-API use native GSS-API, Java platform applications must explicitly enable this behavior by setting one or more of the following system properties:

  • sun.security.jgss.native (required): Set this to true to enable Java GSS-API to use native GSS-API.

  • sun.security.jgss.lib (optional): Set to the full path of the native GSS library. If this is not set, Java GSS-API will look for the native GSS library using the default Java library path. The default name varies by operating system: For the Solaris OS, use libgss.so; for Linux, use libgssapi.so.

Note: These two system properties are ignored when applications run on operating systems that do not yet support this feature, for example, MS Windows.

As mentioned previously, native GSS-API requires that the application has obtained these credentials and that they are accessible. Java platform applications can access these native credentials through Java GSS-API and use them for establishing GSS-API security contexts with peers. Note that when a Subject is present, for example,

javax.security.auth.Subject.getSubject(AccessController.getContext()) != null

Java GSS-API mandates that the credentials be obtained from the private or public credential sets of the current Subject and that the Java GSS-API call must fail if the desired credential cannot be found. Thus, Java platform applications that execute the Java GSS-API calls inside a

Subject.doAs/doAsPrivileged(...)

call should either populate the Subject's credential sets with appropriate Java GSSCredential objects that encapsulate the native credentials or explicitly set the system property javax.security.auth.useSubjectCredsOnly to false so that Java GSS-API can obtain credentials from other locations, for example, from native credential caches, in addition to the Subject's credential sets.

When delegated to establish a GSS-API security context on behalf of others, Java platform applications can either specify the delegated credential, as returned by GSSContext.getDelegCred(), explicitly in Java GSS-API calls or create a Subject object with this delegated credential and execute the Java GSS-API calls inside the Subject.doAs/doAsPrivileged(...) calls.

Lastly, once the native GSS-API is enabled, Java platform applications that indirectly call Java GSS-API through mechanisms or protocols such as Simple Authentication and Security Layer (SASL) will also use user's native settings and credentials.

Here is some sample code that helps demonstrate how to use Java GSS-API to establish GSS-API security contexts and securely exchange data between three parties: SampleClient contacts FooServer, which in turn contacts FooServer2 on behalf of SampleClient. Note:

  • The sample code should be invoked with native GSS-API enabled. The Principal names host@foo.sample.com and host@foo2.sample.com are placeholders and should be replaced with actual principal names in your Kerberos database.

  • When a security manager is installed, some Java GSS-API calls require that permissions be granted. Check the Java platform documentation of the following classes for more details:

  • To simplify the example, token exchanges between peers are represented by two pseudo methods: SEND_TOKEN(byte[]) and READ_TOKEN(). Their actual implementation are application specific and thus not shown here.

  • To reduce code duplication, context establishment code is referred by a pseudo method, ESTABLISH_CONTEXT(GSSContext), in the code segments for SampleClient, FooServer, and FooServer2.

Following is the implementation using Java GSS-API.

/**
* ESTABLISH_CONTEXT(GSSContext ctxt): establishes a context
* with data confidentiality and mutual authentication.
*/
ctxt.requestConf(true);
ctxt.requestMutualAuth(true);

byte[] inToken = new byte[0];
byte[] outToken = null;

if (ctxt.isInitiator()) {
while (!ctxt.isEstablished()) {
// Note: initSecContext(...) always ignores the arguments
// for the first call because there is no incoming token.
outToken = ctxt.initSecContext(inToken, 0, inToken.length);

// Send the output token if generated.
if (outToken != null) SEND_TOKEN(outToken); // to acceptor

// Check whether more incoming tokens are expected.
if (!ctxt.isEstablished()) {
inToken = READ_TOKEN(); // from acceptor
}
}
} else {
while (!ctxt.isEstablished()) {
inToken = READ_TOKEN(); // from initiator
outToken =
ctxt.acceptSecContext(inToken, 0, inToken.length);

// Send the output token if generated.
if (outToken != null) SEND_TOKEN(outToken); // to initiator
}
}

Following are the code segments for SampleClient, FooServer, and FooServer2:

//================================================================ 
// SampleClient: it contacts FooServer and delegates the server to
// act on its behalf. If all goes well, it should get back a
// personalized hello message produced by FooServer2.
//================================================================
GSSManager gssMgr = GSSManager.getInstance();
GSSName serverName = gssMgr.createName(
"host@foo.sample.com", GSSName.NT_HOSTBASED_SERVICE);
GSSContext context = gssMgr.createContext(
serverName, null /* default mechanism, which is Kerberos*/,
null /* default initiator cred */,
GSSContext.DEFAULT_LIFETIME);
context.requestCredDelegState(true);

ESTABLISH_CONTEXT(context);

// Make sure credential delegation is available.
if (!context.getCredDeleg()) {
context.dispose();
throw new Exception("credential delegation is denied");
}

byte[] token = READ_TOKEN(); // from "FooServer"
byte[] data =
context.unwrap(token, 0, token.length, new MessageProp(true));
context.dispose();

// Should print "Hello from FooServer2 to " where
// is the name of the default initiator.
System.out.println(new String(data));

//===============================================================
// FooServer: it contacts FooServer2 as SampleClient and
// forwards the received reply to SampleClient.
//===============================================================
GSSManager gssMgr = GSSManager.getInstance();
GSSName myName = gssMgr.createName(
"host@foo.sample.com", GSSName.NT_HOSTBASED_SERVICE);
GSSCredential myCred = gssMgr.createCredential(
acceptorName, GSSCredential.INDEFINITE_LIFETIME,
(Oid[]) null /* default set of mechanisms */,
GSSCredential.ACCEPT_ONLY);
GSSContext acontext = gssMgr.createContext(myCred);

ESTABLISH_ACC_CONTEXT(acontext);

GSSCredential delegCred = acontext.getDelegCred();
if (delegCred != null) {
byte[] data, token;
// Establish a context on client's behalf using the delegated
// credential.
GSSName serverName = gssMgr.createName(
"host@foo2.sample.com", GSSName.NT_HOSTBASED_SERVICE);
GSSContext icontext = gssMgr.createContext(
serverName, null /* default mechanism Kerberos */,
delegCred /* act on SampleClient's behalf */,
GSSContext.DEFAULT_LIFETIME);

ESTABLISH_CONTEXT(icontext);

token = READ_TOKEN(); // from "FooServer2"

MessageProp msgProp = new MessageProp(true);

// Forward the reply from FooServer2 to SampleClient.
data = icontext.unwrap(token, 0, token.length, msgProp);
token = acontext.wrap(data, 0, data.length, msgProp);
SEND_TOKEN(token); // to "SampleClient"
icontext.dispose();
}
acontext.dispose();

//===============================================================
// FooServer2: it always replies with a hello message personalized
// to the name of the initiator of the established context.
//===============================================================
GSSManager gssMgr = GSSManager.getInstance();
GSSName myName = gssMgr.createName(
"host@foo2.sample.com", GSSName.NT_HOSTBASED_SERVICE);
GSSCredential myCred = gssMgr.createCredential(
myName, GSSCredential.INDEFINITE_LIFETIME,
(Oid[]) null /* default set of mechanisms */,
GSSCredential.ACCEPT_ONLY);
GSSContext context = gssMgr.createContext(myCred);

ESTABLISH_CONTEXT(context);

byte[] data = new String("Hello from FooServer2 to " +
context.getSrcName()).getBytes();
byte[] token =
context.wrap(data, 0, data.length, new MessageProp(true));

SEND_TOKEN(token); // to "FooServer"

context.dispose();

Import and Export PKCS#12 Keystores

PKCS#12, the Personal Information Exchange Syntax Standard, defines a portable format for storing or transporting personal identity information, including private keys, certificates, and so on. This enables users to import, export, and thus effectively share their personal identity information among applications that support this standard. In particular, user credentials that browsers such as Microsoft IE or Mozilla Firefox generate can be exported in PKCS#12 format -- as files with the .pfx or .p12 suffix -- and then accessed and used by Java platform applications.

The PKCS12 keystore implementation from the SunJSSE provider follows the syntax defined in PKCS#12. All entries are privacy protected, and the whole keystore is then integrity protected using a user-supplied password as defined in PKCS#12 in the Password privacy and Password integrity modes. To ensure maximum interoperability with other vendors' PKCS#12 keystore implementation, the JDK 6 PKCS12 keystore implementation only allows the storing of PrivateKey and its corresponding certificate chain, because other types of entries such as SecretKey or trusted certificate are generally not supported. In addition, although the PKCS12 implementation in JDK 6 is quite flexible and allows the use of different passwords for each private key entry and the integrity of the keystore, the resulting PKCS#12 keystore may not be imported into applications that use only a single password for the keystore and all its key entries.

For example, to import the PKCS12 keystore sample.p12 created by other applications using the password testpass and listing its content, you have two options:

  • You can invoke the command line keytool:

          keytool -list -v -keystore sample.p12 -storepass testpass          -storetype PKCS12

  • You can do this programmatically through the java.security.KeyStore APIs:

          KeyStore ks = KeyStore.getInstance("PKCS12");
    FileInputStream fis = new FileInputStream("sample.p12");
    char[] passwd = { 't', 'e', 's', 't', 'p', 'a', 's', 's' };
    ks.load(fis, passwd);

    // Retrieve the PrivateKey and its certificate chain using
    // the java.security.KeyStore API.
    Enumeration aliases = ks.aliases();
    while (aliases.hasMoreElements()) {
    String name = aliases.nextElement();
    Key privKey = ks.getKey(name, passwd);
    java.security.cert.Certificate[] certs =
    ks.getCertificateChain(name);

    // Print out the desired information using 'name',
    // 'privKey', and 'certs'.
    ...
    }

As for creating a PKCS12 keystore and exporting it to other applications, the most straightforward approach would probably be running the command line keytool. For example, to create a PKCS12 keystore sample.p12 that contains a 1024-bit RSA key pair using the password testpass, you could use the following:

          keytool -genkeypair -alias myRSAKey -keyalg RSA -keysize 1024                    -keystore sample.p12 -storepass testpass -storetype pkcs12

Once this command is executed, the file named sample.p12 contains a 1024-bit RSA private key accompanied with a self-signed certificate. For this exercise, users can now import this PKCS12 file into a browser. For real-world use, the self-signed certificate should be replaced with a certificate chain issued by a public certification authority (CA). There are keytool options, for example, -certreq and -import, to generate the certificate request as well as to import the PKCS#7 reply from the CA. The keytool documentation provides a complete list of options and their use. Lastly, you can repeat the previously given keytool command with a different alias to add more PrivateKey entries into the PKCS12 file if needed.

Conclusion

The Java SE platform provides developers a large set of security APIs, tools, and implementations of commonly used security algorithms, mechanisms, and protocols. The ability to leverage the security in the native platform offers several significant benefits: the performance boost that cryptographic accelerators provide, a consistent behavior that matches what native applications have, and the seamless sharing of users' native credentials and settings.

With these enhancements, Java platform applications can now access Microsoft CryptoAPI and its cryptographic services, PKCS#11 cryptographic tokens, and native GSS-API and its mechanisms including Kerberos, as well as sharing credentials such as PrivateKey and Certificates with native applications such as browsers. Furthermore, these enhancements are often implemented as providers that implement a set of services through existing security APIs. Thus, developers of Java platform applications do not have to learn new APIs and can simply reuse most of the existing code.

Appendix

Table 2 lists information about the native security features this article has discussed and their availability in various operating systems.

Table 2. Native Security Features and Their Availability

Feature
Starting JDK Release: Available OS
Note

Access MS CryptoAPI

JDK 6: 32-bit MS Windows


Access PKCS#11 cryptographic services

JDK 5.0: 32-bit and 64-bit Solaris (SPARC, x86), 32-bit Linux, 32-bit MS Windows

JDK 6: All except 64-bit MS Windows

Requires PKCS#11 v. 2.0 or later

Requires NSS v. 3.11.1 or later (JDK 6)

Access Native GSS-API

JDK 6: Solaris, Linux


Import and export PKCS#12 keystores

JDK 1.4: All

Interoperable with MS IE, Netscape, NSS, and OpenSSL