IBM JavaTM Generic Security Service API (JGSS) 1.0.1

Application Developer’s Guide


Contents


Introduction

IBM JGSS 1.0.1 is a Java™ Generic Security Service Application Programming Interface (GSSAPI) framework with Kerberos V5 as the underlying default security mechanism. GSSAPI is a standardized abstract interface under which can be plugged different security mechanisms based on private-key, public-key and other security technologies. GSSAPI shields secure applications from the complexities and peculiarities of the different underlying security mechanisms. GSSAPI provides identity and message origin authentication, message integrity and message confidentiality.

IBM JGSS 1.0.1 also features optional Java™ Authentication And Authorization Service (JAAS) Kerberos login interface and authorization checks. JAAS augments the access control features of Java™ 2 which is based on CodeSource with access controls based on authenticated principal identities.

 

Additional Documentation

Readers of this guide are assumed to conversant with the high-level GSSAPI specification and the Java™ bindings specification. IBM JGSS 1.0.1 is primarily based on and conforms to these specifications. Readers are also assumed to have read the README and the User’s Guide accompanying IBM JGSS 1.0.1. These documents are listed below:

·        RFC 2743: Generic Security Service Application Programming Interface Version 2, Update 1

·        RFC 2853: Generic Security Service API Version 2: Java Bindings

·        IBM Java™ Generic Security Service API (JGSS) 1.0.1 README

·        IBM Java™ Generic Security Service API (JGSS) 1.0.1 User's Guide

 

Application Programming Interfaces (APIs)

The User’s Guide lists several publicly accessible packages contained in the product. However, application developers should use only the APIs from the standardized org.ietf.jgss package. This will make their applications conform to the specifications and ensure their optimum interoperability.

 

Transporting Tokens

Some of the important JGSS operations generate tokens in the form of Java™ byte arrays. It is the responsibility of the application to forward the tokens from one JGSS peer to the other. The protocol used by the application for transporting tokens is not constrained by JGSS in any way and JGSS tokens may be transported together with other application (non-JGSS) data. But only JGSS-specific tokens may be fed into JGSS operations.

 

Summary Of Application Programming Steps

            A GSSAPI application follows the GSSAPI operational model and consists of GSSAPI constructs in the following order:

1.      Creation of a GSSManager: an instance of GSSManager acts as a factory for creating other JGSS object instances

2.      Creation of a GSSName: a GSSName represents the identity of a JGSS principal. Some JGSS operations are capable of locating and using a default principal when a null GSSName is specified.

3.      Creation of a GSSCredential: a GSSCredential embodies the mechanism-specific credentials of the principal

4.      Creation of a GSSContext: a GSSContext is used for context establishment and subsequent per-message services

5.      Selection of optional services on the context: services such as mutual authentication are optional and must be explicitly requested for

6.      Context establishment: the initiator authenticates itself to the acceptor; optionally, when mutual authentication is requested, the acceptor in turn authenticates itself to the initiator

7.      Use of per-message services: the initiator and the acceptor exchange secure messages over the established context

8.      Deletion of context: the context is deleted when it is no longer needed.

These steps apply to both the initiator and the acceptor and are covered in detail in the sections that follow. The code segments below illustrate the use of the high-level JGSS APIs and assume the importation of the org.ietf.jgss package. Many of the high-level APIs are overloaded but only the most commonly used forms of those methods are illustrated. Application developers are encouraged to use whichever versions of the APIs best suit their needs.

 

GSSManager Creation

GSSManager is an abstract class that serves as factory for the creation of GSSName, GSSCredential and GSSContext. It also has methods for determining the supported security mechanisms and name types. The IBM JGSS framework includes an implementation of GSSManager. An instance of this default GSSManager can be created by using the GSSManager getInstance static method:

GSSManager manager = GSSManager.getInstance();

 

GSSName Creation

A GSSName represents the identity of a GSSAPI principal. GSSManager has several overloaded methods for creating a GSSName. These methods create a GSSName either from a string or a contiguous array of bytes. The methods interpret the name string or byte array according a name type that must be specified. Finally, each name creation method has a variety for creating a mechanism name (MN) for a given mechanism. The byte-array methods are typically used to reconstitute an exported name; the name is typically a mechanism name and of type GSSName.NT_EXPORT_NAME.

To create a GSSName for the user “foo”

            GSSName fooName = manager.createName(“foo”, GSSName.NT_USER_NAME);

To create a Kerberos V5 mechanism name for the same user,

            Oid krb5Mech = Oid.getInstance("1.2.840.113554.1.2.2");

GSSName fooName = manager.createName(“foo”, GSSName.NT_USER_NAME, krb5Mech);

                A mechanism name may be created from a non-mechanism name by using the canonicalize method of a GSSName:

                        GSSName fooName = manager.createName(“foo”, GSSName.NT_USER_NAME);

                                GSSName fooKrb5Name = fooName.canonicalize(krb5Mech);

Kerberos service name strings must be specified as either <service> or <service@host> where <service> is the name of the service and <host> is the hostname of the machine on which the service runs. The hostname may or may not be fully qualified. Where the “@<host>” portion is omitted, the local hostname is used.

 

GSSCredential Creation

GSSManager has two credential creation methods. The only difference between the two methods is that one returns credentials for a single mechanism whereas the other returns credentials for an array of mechanisms. Specifying a null mechanism will return credentials for the default mechanism. Specifying a null array of mechanisms will result in credentials for the default set of mechanisms. The only IBM JGSS default mechanism is the Kerberos V5 mechanism.

Only one of three credentials types (initiate, accept, initiate and accept) may be created at a time. A context initiator creates initiate credentials, the acceptor creates accept credentials, and an acceptor that will also behave as initiator creates initiate and accept credentials.

To obtain Kerberos V5 credentials for the initiator “foo” with the default validity period,

GSSCredential fooCreds = manager.createCredential(fooName, GSSCredential.DEFAULT_LIFETIME, krb5Mech,GSSCredential.INITIATE);

To obtain an all-default acceptor credential,

GSSCredential serverCreds = manager.createCredential(null, GSSCredential.DEFAULT_LIFETIME, (Oid)null, GSSCredential.ACCEPT);

 

GSSContext Creation

GSSManager has three methods for creating a context, one for use by the context initiator, one by the acceptor, and one for recreating a previously exported context. An initiator context cannot be used for context acceptance and vice-versa. Each of the first two methods requires a credential as input, but null may be specified for the default credential to be used.

To create a context, valid for the default period, with which “foo” can initiate a context with its peer “superSecureServer” running on the host “securityCentral,”

GSSName serverName = manager.createName(“superSecureServer@securityCentral”, GSSName.NT_HOSTBASED_SERVICE, krb5Mech);

GSSContext fooContext = manager.createContext(serverName, krb5Mech, fooCreds, GSSCredential.DEFAULT_LIFETIME);

                To create a context for “superSecureServer” to accept contexts initiated by any peer,

                        GSSContext serverAcceptorContext = manager.createContext(serverCreds);

Note the name of the acceptor context created for the server. It indicates that a server may simultaneously possess and use both an acceptor and an initiator context.

 

Selection Of Optional Security Services

A number of security services – delegation, mutual authentication, replay detection, and out-of-sequence detection – are optional and must be requested explicitly. An optional service is requested by using the applicable requestX method on the context, where X is the service being requested. For example, “foo” uses the following calls to request that mutual authentication and delegation services be enabled on fooContext:

            fooContext.requestMutualAuth(true);

                fooContext.requestCredDeleg(true);

Only an initiator can request these optional services and the request must be made before context establishment begins.

 

Context Establishment

The two communicating peers must establish a security context over which they can use per-message services. The initiator calls initSecContext on its context which returns a token to the application. The initiator’s application transports the context token to the acceptor’s application. The acceptor’s application calls acceptSecContext on the acceptor’s context, specifying the context token received from the initiator. Depending on the underlying mechanism and the optional services selected by the initiator, the acceptSecContext may produce a token which the acceptor’s application has to forward to the initiator’s application; the initiator’s application then calls initSecContext one more time with the received token.

Indeed, multiple calls may be made to both initSecContext and acceptSecContext and multiple tokens exchanged between the two peers during context establishment. Hence, context establishment is typically accomplished in a programming construct in which initSecContext or acceptSecContext is called in a loop until the context is established.

Being the initiator, foo’s side of the context establishment may be coded as

                        byte array[] inToken = null; // The input token is null for the first call

                                int inTokenLen = 0;

do {

                                                byte array[] outToken = fooContext.initSecContext(inToken, 0, inTokenLen);

                                                if (outToken != null) send(outToken); // transport token to acceptor

                                                inToken = receive(); // receive token from acceptor

                inTokenLen = inToken.length;

                                } while (!fooContext.isEstablished());

                The acceptor code for establishing context may be

do {

                byte array[] inToken = receive(); // receive token from initiator

                                                byte array[] outToken = serverAcceptorContext.acceptSecContext(inToken, 0, inToken.length);

                                                if (outToken != null) send(outToken); // transport token to initiator

                                } while (!isEstablished());

 

Per-message Services

Having established a security context, the two communicating peers can now exchange secure messages over the established context. Either of the two parties can be the originator of a secure message irrespective of their role (initiator or acceptor) in the context establishment process. A message is made secure by computing a cryptographic message integrity code (MIC) over the message. The message may also be encrypted for privacy.

JGSS provides two sets of methods, the wrap and the getMIC methods, for securing messages. A wrap method computes a MIC and optionally encrypts the message. It returns a token that contains both the MIC and ciphertext (if the message was encrypted) or the original plaintext (if the message was not encrypted). The caller specifies via the MessageProp input whether or not the message is to be encrypted. A getMIC method, on the other hand, only computes a MIC over the message. The token it returns is made up entirely of the computed MIC and does not include the original message. Therefore, in addition to transporting the MIC token to the peer, the peer must somehow be made aware of the original message so that it can verify the MIC.

Here is how foo may wrap a message for delivery to superSecureServer:

            byte array[] message = “Ready to roll!”.getBytes();

                MessageProp mprop = new MessageProp(true); // foo wants the message encrypted, too

byte array[] wrappedMessage = fooContext.wrap(message, 0, message.length, mprop);

send(wrappedMessage); // transfer the wrapped message to superSecureServer

Here is how superSecureServer may obtain a MIC for delivery to foo:

byte array[] message = “You bet!”.getBytes();

MessageProp mprop = null; // superSecureServer is content with the default quality of  protection

 byte array[] mic = serverAcceptorContext.getMIC(message, 0, message.length, mprop);

send(mic); // send the MIC to foo. foo will also require the original message to verify the MIC

The receiver of a wrapped message uses the unwrap method to decode the message. The method verifies the cryptographic MIC embedded in the message and returns the original message over which the MIC was computed by the sender. If the message was encrypted, the unwrap method decrypts the message before verifying the MIC and returning the original plaintext message. The receiver of a MIC token uses the verifyMIC method to verify the MIC over a given a message.

The peer applications use their own protocol to deliver JGSS context and message tokens to each other. They should also define a protocol for determining the type of a given message token, that is, whether the token is a MIC or a wrapped message. For example, part of such a protocol may be as simple (and rigid) as that used by Simple Authentication And Security Layer (SASL) GSSAPI applications in which the context acceptor is always the first to send a per-message (wrapped) token following context establishment.

superSecureServer unwraps the wrapped token received from foo:

            MessageProp mprop = new MessageProp(false);

byte array[] plaintextFromFoo = serverAcceptorContext.unwrap(wrappedTokenFromFoo, 0, wrappedTokenFromFoo.length, mprop);

// superSecureServer can now examine mprop to determine the message properties (such as whether the message was encrypted) applied by foo.

                foo verifies the MIC received from superSecureServer thus:

                        MessageProp mprop = new MessageProp(false);

fooContext.verifyMIC(micFromFoo, 0, micFromFoo.length, messageFromFoo, 0, messageFromFoo.length, mprop);

// foo can now examine mprop to determine the message properties applied by superSecureServer. In particular, it can assert that the message was not encrypted since getMIC should never encrypt a message.

 

Context Deletion

A context object should be deleted when the context is no longer needed. In JGSS, each peer unilaterally decides when to delete a context and does not need to inform its peer – JGSS does not define a “delete context” token. A context is deleted by calling its dispose method to free up any resources used by the context. Unless is set to null by the application, a disposed context may still be accessible but any attempt to use it will result in an exception.

 

Enabling The JAAS Login Facility

IBM JGSS includes an optional JAAS login facility which saves principal credentials and secret keys in the Subject of the application’s JAAS login context. JGSS retrieves credentials and secret keys from the Subject by default. However, this feature may be disabled by setting the Java™ property javax.security.auth.useSubjectCredsOnly to false.

To use the JAAS login facility, an application must follow the JAAS programming model. It must create a JAAS login context and operate within the confines of a JAAS Subject doAs construct as illustrated in the following code segment:

            static class JGSSOperations implements PrivilegedExceptionAction {

                                public JGSSOperations() {}

public Object run () throws GSSException {

                                                // JGSS application code goes/runs here

                                }

                }

                                public static void main(String args[]) throws Exception {

                                                // Create a login context that will use the callback handler com.ibm.security.auth.callback.Krb5CallbackHandler

                                                // There must be a JAAS configuration for “JGSSClient”

LoginContext loginContext = new LoginContext(“JGSSClient”, new Krb5CallbackHandler());

// Run the entire JGSS application in JAAS privileged mode

Subject.doAsPrivileged(Subject.getSubject(), new JGSSOperations(), null);

                                }

 

Debugging

The IBM JGSS framework includes a debug class with APIs that applications can use. The class categorizes debugging and only outputs information when the requested debug category is in effect. Its default constructor reads the Java™ property com.ibm.security.jgss.debug to determine which categories to turn on.

To request debug information  for the application category,

            import com.ibm.security.jgss.debug;

                Debug debug = new Debug(); // gets categories from Java™ property

                // Lots of work required to set up someBuffer. Test that the category is on before setting up for debugging

 if (debug.on(Debug.OPTS_CAT_APPLICATION)) {

                                 // Jump hoops to set up someBuffer

debug.out(Debug.OPTS_CAT_APPLICATION, someBuffer); // someBuffer may be  a byte array or a String.

                                }

 

Appendix A: Sample Programs

            The source code for the following sample programs are provided:

·        Sample Client Program

·        Sample Server Program

·        Sample JAAS-Enabled Client Program

·        Sample JAAS-Enabled Server Program