IBMJCEHYBRID Provider Failover Function

A platform with cryptographic hardware and cryptographic processors can be volatile. Changes in the availability of cryptographic hardware and cryptographic processors can have the effect of disabling or enabling (in part or completely) a Java™ provider that exploits the cryptographic features in the platform. For example, on z/OS® cryptographic hardware and processors can be varied online and offline dynamically, that is, without restarting z/OS. This has the effect of enabling or disabling the IBM®JCECCA provider, in part or completely. The IBM JCE Hybrid Provider is designed to enable an application to take advantage of JCE providers with platform dependencies without the application needing to include complex error handling for when the platform's cryptographic features are not available.

During JVM initialization, the Java Security Framework loads each security provider listed in the java.security provider list. When a provider initializes itself, it registers with the Java Security Framework for each serviceType.algorithm that it can perform. If an application requests cryptographic services without specifying a security provider, the Java Security Framework selects the first provider in the security provider list that registered the requested service.

An application that uses services provided by security providers can specify the provider it wants to use. However, applications don't usually do this because it makes them less portable and less flexible. In addition, by using the installation-configured provider list, an application can take advantage of cryptographic features when running on a platform that includes them and also can run successfully on a platform that does not include cryptographic features.

Because a platform with cryptographic features (such as cryptographic hardware and cryptographic processors) can be volatile, a security provider might register for a serviceType.algorithm that it is unable to perform when requested. In this case, the security provider will throw an exception that is passed up to the application. If the application retries the operation, the Security Framework will pass the request to the same provider because it is still first in the list. Unless there is a change in the status of cryptographic features on the platform, the result will be the same. Thus the application will be unsuccessful, even if another provider registered for the serviceType.algorithm could successfully process the request.

The IBM JCE Hybrid Provider is designed to provide failover from one JCE security provider to another in a manner that is transparent to applications.

IBMJCEHYBRID Failover with JCE Providers

IBMJCEHYBRID does not perform any cryptographic operations, but routes requests to JCE providers that have registered with the Java Security Framework. When IBMJCEHYBRID is the first JCE provider in the active JVM provider list (initialized using the java.security provider list), IBMJCEHYBRID routes requests to and provides failover for JCE providers according to the security provider registrations done at JVM initialization. This enables an application to take advantage of cryptographic features when they are available on the platform and to use a provider that does not depend on these features when they are not available.

If IBMJCEHYBRID is not the first JCE provider in the active JVM provider list then a cryptographic request might be routed to a different JCE provider instead of IBMJCEHYBRID. If this happens, IBMJCEHYBRID does not get control and cannot provide routing or failover for the request. The IBMJCEHYBRID can be the first JCE provider in the java.security provider list but not be the first JCE provider in the active JVM provider list. This will be the case if an application uses the Security.insertProviderAt() API and inserts a provider ahead of IBMJCEHYBRID.

The list of serviceType.algorithm pairs for which IBMJCEHYBRID provides failover is the list of serviceType.algorithm pairs supported by the IBMJCECCA, OpenJCEPlus, and IBMZSecurity providers, with the exception of algorithms in the KeyStore service. Using this list, IBMJCEHYBRID provides failover from, and to, each provider in the java.security provider list, whether it is an IBM security provider, a security provider written by the customer, or a third party security provider.

The IBMSecureRandom algorithm is supported by the IBMJCECCA provider. For this algorithm, if the IBMJCECCA provider is not available, the IBMJCEHYBRID provider provides failover by routing the request to the Oracle SUN provider and the SecureRandom.SHA1PRNG algorithm.

KeyStore support is, in general, very specific to the implementing provider. In other words, if a provider can not satisfy a KeyStore request for a KeyStore that it implements then it is very unlikely that another provider can satisfy a request for that KeyStore. For this reason, IBMJCEHYBRID does not attempt failover for any KeyStore.algorithm. When the Java Security Framework receives a request for a serviceType.algorithm that IBMJCEHYBRID has not registered, then the Framework routes the request to the first security provider that has registered for it.

IBMJCEHYBRID routes requests to and provides failover for only those providers that are in the java.security provider list when the JVM initializes the Security Framework. If an application uses the Security.insertProviderAt() API to insert a JCE provider after IBMJCEHYBRID, IBMJCEHYBRID will continue to be the preferred provider and will continue to provide failover support. However, IBMJCEHYBRID will not route requests to or provide failover for the provider that was inserted. Consequently, unless an application specifies the inserted JCE provider on the getInstance() API, it will receive control only for serviceType.algorithm pairs that IBMJCEHYBRID did not register.

If a JCE provider in the active JVM provider list has dependencies on cryptographic features that are offline then repeated calls to that provider will impose a performance penalty. To reduce the effect of this performance penalty, if a provider fails to process a request for a serviceType.algorithm it registered, that provider is marked 'inactive' for that serviceType.algorithm. Because the cryptographic features might become available, inactive providers are periodically restored to 'active' status based on a number of factors, including how often there is a getInstance() for the serviceType.algorithm and the state of the active providers list when request failovers are processed. If a request cannot be processed by any active provider, all inactive providers are restored to active status and IBMJCEHYBRID attempts to failover to each of them in turn.

Examples of IBMJCEHYBRID Failover with JCE Providers

The following examples illustrate the failover service provided by IBMJCEHYBRID:

Example 1
JCE providers in the JVM security provider list are as follows:
  1. IBMJCEHYBRID
  2. IBMJCECCA
  3. IBMZSecurity
  4. OpenJCEPlus
Situation: An application requests a serviceType.algorithm supported by IBMJCECCA, IBMZSecurity, and OpenJCEPlus. The application does not specify a provider on getInstance().
Processing flow:
  • IBMJCEHYBRID gets control and routes the request to IBMJCECCA.
  • If IBMJCECCA is unable to process the request it throws an exception, IBMJCEHYBRID catches the exception and attempts to failover to IBMZSecurity.
  • If IBMZSecurity is unable to process the request it throws an exception, IBMJCEHYBRID catches the exception and attempts to failover to OpenJCEPlus.
Example 2
JCE providers in the JVM security provider list are as follows:
  1. IBMJCEHYBRID
  2. IBMJCECCA
  3. OpenJCEPlus
Situation: An application requests a serviceType.algorithm supported by OpenJCEPlus but not supported by IBMJCECCA. The application does not specify a provider on getInstance().
Processing flow:
  • IBMJCEHYBRID gets control and routes the request to OpenJCEPlus
  • If OpenJCEPlus is unable to process the request it throws an exception, IBMJCEHYBRID catches the exception, wraps it in an IBMJCEHybridException and throws it to the application.
Example 3
JCE providers in the JVM security provider list are as follows:
  1. IBMJCEHYBRID
  2. IBMJCECCA
  3. OpenJCEPlus
Situation: An application requests a serviceType.algorithm supported by both IBMJCECCA and OpenJCEPlus. The application does not specify a provider on getInstance().
Processing flow:
  • IBMJCEHYBRID gets control and routes the request to IBMJCECCA.
  • If IBMJCECCA is unable to process the request it throws an exception, IBMJCEHYBRID catches the exception and attempts to failover to OpenJCEPlus.
  • If OpenJCEPlus is unable to process the request it throws an exception, IBMJCEHYBRID catches the exception, wraps both the exception thrown by IBMJCECCA and the exception thrown by OpenJCEPlus in an IBMJCEHybridException and throws it to the application.
Example 4
System properties used in SunJSSE are set upon loading of the ZERTJSSE provider. Any change in these system properties between being set in ZERTJSSE and SunJSSE could result in unexpected behavior.
Example 5
JCE providers in the JVM security provider list are as follows:
  1. IBMJCECCA
  2. OpenJCEPlus
Situation:
  • An application invokes Security.insertProviderAt(new com.ibm.crypto.ibmjcehybrid.provider.IBMJCEHYBRID, 1)
  • The application requests a serviceType.algorithm supported by both IBMJCECCA and OpenJCEPlus. The application does not specify a provider on getInstance().
Processing flow:
  • IBMJCEHYBRID gets control and routes the request to IBMJCECCA.
  • If IBMJCECCA is unable to process the request it throws an exception, IBMJCEHYBRID catches the exception and attempts to failover to OpenJCEPlus.
Example 6
JCE providers in the JVM security provider list are as follows:
  1. IBMJCEHYBRID
  2. IBMJCECCA
  3. OpenJCEPlus
Situation:
  • An application invokes Security.insertProviderAt(new mypkg.MyProvider, 1)
  • The application requests a serviceType.algorithm supported by MyProvider, by IBMJCECCA, and by OpenJCEPlus. The application does not specify a provider on getInstance().
Processing flow:
  • MyProvider gets control.
  • MyProvider is unable to process the request and throws an exception.
  • The exception is passed back to the application. (No failover is done because IBMJCEHYBRID does not get control.)
Example 7
JCE providers in the JVM security provider list are as follows:
  1. IBMJCEHYBRID
  2. IBMJCECCA
  3. OpenJCEPlus
Situation:
  • An application invokes Security.insertProviderAt(new mypkg.MyProvider, 3)
  • The application requests a serviceType.algorithm supported by MyProvider, by IBMJCECCA, and by OpenJCEPlus. The application does not specify a provider on getInstance().
Processing flow:
  • IBMJCEHYBRID gets control and routes the request to IBMJCECCA.
  • If IBMJCECCA is unable to process the request it throws an exception, IBMJCEHYBRID catches the exception and attempts to failover to OpenJCEPlus.
  • If OpenJCEPlus is unable to process the request it throws an exception, IBMJCEHYBRID catches the exception, wraps both the exception thrown by IBMJCECCA and the exception thrown by OpenJCEPlus in an IBMJCEHybridException and throws it to the application. (There is no failover to MyProvider because it was not in the provider list at JVM initialization.)

IBMJCEHYBRID Failover and Security Object State

As described in the previous section, the ability of IBMJCEHYBRID to provide failover depends on the JCE security providers that have registered with the Java Security Framework. The ability of IBMJCEHYBRID to provide failover also depends on the state of the security object, specifically on the type of data that has been passed to the security object.

In general,

  • Passing specification information, such as chaining mode or padding scheme, will not prevent failover to another provider.
  • Passing data, such as an encryption key or bytes of data to be encrypted, will prevent failover after the first time. That is, if there is a failure during the first call that passes data, IBMJCEHYBRID will attempt failover. If the first such call is successful then failover is disabled for the object until after a reset operation, even if the subsequent failure is in a method that does not itself prevent failover.
  • A reset, explicit or implicit, will reenable failover. An explicit reset occurs when an implementation SPI has a reset() method and it is called by an application. An implicit reset occurs when an application calls a method that includes a reset operation, as described in the Java Specification. Examples of methods that include reset are the Cipher SPI doFinal() method and the Signature SPI sign() and verify() methods.

If Failover is unsuccessful: IBMJCEHybridException

As described in the preceding sections, IBMJCEHYBRID provides failover when JCE providers are unable to complete cryptographic operations. Depending on the circumstances of the request and the platform environment, failover may not be successful. For example, failover could be unsuccessful due to the state of the operation when failover was attempted or due to an incorrectly formed request.

If failover is successful, it is transparent to the application. In this case, no error is reported and no exception is thrown.

If failover is not successful, IBMJCEHYBRID throws an IBMJCEHybridException containing the exception (and stack trace) thrown by each JCE provider that attempted the operation. These embedded exceptions are included in the output from printStackTrace(). The embedded exceptions can also be retrieved programmatically.

The following is an example of the output from ex.printStackTrace() where ex is an IBMJCEHybridException. In this example, IBMJCECCA was first in the provider list for the RSA Cipher and OpenJCEPlus was second (and last). IBMJCECCA failed the request with a ShortBufferException. OpenJCEPlus failed the request because the key was an IBMJCECCA hardware key, a format not recognized by OpenJCEPlus. (Note that both IBMJCECCA and OpenJCEPlus recognize the format of an OpenJCEPlus key (PKCS#8). If the key had been in this format, failover would have resulted in two ShortBufferExceptions.)
IBMJCEHybridException: Failover exhausted, all registered providers attempted and failed.

Exception#0 javax.crypto.ShortBufferException: Output buffer too short: 25 bytes given, 30 bytes needed
Stack Trace:
        at com.ibm.crypto.hdwrCCA.provider.RSA.engineDoFinal(RSA.java:807)
        at javax.crypto.Cipher.doFinal(Unknown Source)
        at com.ibm.crypto.ibmjcehybrid.provider.HybridCipher.doFinal(HybridCipher.java:2312)
        .
        .
        .

Exception#1 java.security.InvalidKeyException: Bad key encoding
Stack Trace:
        at com.ibm.crypto.plus.provider.RSA.engineInit(Unknown Source)
        at javax.crypto.Cipher.init(Unknown Source)
        at com.ibm.crypto.ibmjcehybrid.provider.HybridCipher.init(HybridCipher.java:952)
        .
        .
        .

The following illustrates how to retrieve the embedded exceptions from the IBMJCEHybridException programatically.

import com.ibm.crypto.ibmjcehybrid.provider.IBMJCEHybridException;
        .
        .
        .
try {
        .
        .
        .
} catch (Exception ex) {
   if (ex instanceof IBMJCEHybridException) {

      Vector<Exception> exVector = ex.getEmbeddedExceptionVector();
      if (null != exVector) {
         int exCount = exVector.size();
         Exception[] exceptions = exVector.toArray(new Exception[exCount]);
         for (int x=0; x<exCount; x++) {

            // process the exception exceptions[x]

         } // end for
      } // end if

   } else { // not an IBMJCEHybridException

      // process the exception ex

   } // end else

   Throwable cause = ex.getCause();
   if (null != cause) {

      // process the exception cause

   } // end if

} // end catch