Leveraging Security in the Native Platform Using Java SE 6 Technology

By Valerie Peng, October 2006

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.

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
KeyPairGenerator RSA Generates RSA key pairs needed by other cryptographic services such as Signature and Cipher.
Signature SHA1withRSA MD5withRSA MD2withRSA Creates and validates signatures using various message digest and encryption algorithm as specified in the service name.
Cipher RSA RSA/ECB/PKCS1Padding Performs RSA encryption and decryption.
KeyStore 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.
SecureRandom 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, <jre>/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 <client name>" where 
// <client name> 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<String> 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

For More Information

About the Author

Valerie Peng is a member of the Java Security team at Sun. Her current focuses includes Java Generic Security Services (Java GSS-API), Kerberos, and cryptography.