Chapter 17: Securing Messages with the Java GSS-API

  

Introduction

The Generic Security Services Application Programming Interface (GSS-API) provides a generic security API for generalized security services. The GSS-API uses generalized security services that can be used for authentication, encryption, decryption, and message integrity. The authentication mechanism is generally Kerberos, which uses a secret key exchange.

Other authentication schemes could be done through public key exchange mechanisms such as Simple Public Key GSS-API Mechanism (SPKM). Another mechanism that provides both secret key and public key mechanisms is the Secure European System for Application in Multi-vendor Environment (SESAME). The service provider hides the detailed implementation of the selected authentication mechanism. The GSSManager class is an engine class used to implement the service provider. Like all service providers, it supports the Provider and Security classes and must have a provider implementation specified in a security file.

Cross-Reference  

See Chapter 7 for information on service providers.

The GSS-API is similar to the JSSE in that it is used to transmit and receive secure messages; however, the GSS-API is not limited to TCP/IP. The GSS-API can encrypt and decrypt any message through a byte array and Java input streams. The JSSE does not use cipher suites that GSS-API supports, like Kerberos. The GSS-API has the only Java class that is shipped with the JDK 1.4 that supports Kerberos directly. Kerberos is one of the pluggable authentication modules supported by JAAS for pluggable authentication. The GSS-API provides the implementation for the Kerberos authentication and message confidentiality.

Cross-Reference  

See Chapter 23 for information on JSSE.

The Java GSS-API is a token-based API that relies on the application to do the communication. This means that the application can use TCP sockets, UDP datagrams, or any other channel that will allow it to transport GSS-API-generated tokens. If the application has varying protocol needs, then Java GSS-API might be more appropriate than JSSE because JSSE is limited to TCP/IP and UDP/IP. The GSS-API can read and write its tokens using input and output streams. Because the messages are selectively encrypted and decrypted per message, using the GSS-API can allow an application to encrypt some messages but not all that would allow both plaintext and ciphertext messages.

Overview of GSS-API

The GSS-API classes and methods are found in the org.ietf.jgss package. The GSS-API provides a generic service for encapsulating messages and tokens in a security context. Unlike the JSSE implementation, the socket calls themselves for network communications are kept separate from the GSS-API. For that reason, the GSS-API does not have to be a mechanism established on top of TCP/IP; however, GSS-API passes messages though a stream or byte array as long as the client and server share the same security context.

Because the GSS-API does not have to be a client/server application program, the terms that are used to describe the different peers are initiator and acceptor. The initiator is similar to a client in TCP/IP in that it is the process that is initiating the communication. The communication mechanism in the GSS-API is the security context. The acceptor is similar to the server in the TCP/IP paradigm, in that it is accepting or rejecting the communication from the initiator.

Implementing the interaction

Implementing the interaction between the initiator and acceptor is a four-stage process. The four stages are:

  • Credentials acquisition

  • Context establishment

  • The per-message service

  • Context completion

The credentials acquisition is the initiator acquiring the principals and credentials of a user who wants to authenticate or access a resource through a Kerberos service, or any supported authentication of GSS-API.

The credential is dependent on the authentication mechanism that is currently loaded in the GSS-API. The credential entry can contain multiple credential elements, each representing one of the authentication mechanisms. The GSS-API can support multiple authentication mechanisms for use of the JAAS mechanisms that may be executing in front of the GSS-API initiator.

After the initiator establishes the credentials, possibly from JAAS, it must pass the principals and credentials to the acceptor. The mechanism for passing messages could easily be through TCP/IP using Java sockets. The purpose of sending the principal and credentials to the acceptor is so that the acceptor can authenticate the initiator. The initiator may request an authentication from the acceptor to validate the acceptor's identity. When the acceptor must also validate itself to the initiator, it is a mutual authentication. When only the initiator must authenticate itself to the acceptor, it is a one-way authentication.

After the acceptor, and possibly the initiator, accepts the other's principal and credential, they each create a security context. The security context is a pair of GSS-API data structures that contain shared information and individual state information. These data structures are used in order that per-message security services may be provided between the initiator and acceptor. The shared state in the security context may be cryptographic keys and message sequence numbers . For the security context to establish and maintain the shared state, the security context returns a token structure. The token structure is an opaque data type that may contain cryptographically protected data.

Token communication

The initiator and acceptor are responsible for the transferring of the token, or token communication. When one of the communication peers receives the token, the peer application is responsible for passing the token to the correct GSS-API routine that will decode the token, extract the information, and update the security context. There are two types of tokens: context and message. A context token is exchanged during context establishment. A message token is used over the security context to provide protection for each message. The first token is for establishing the authentication mechanism that will contain the OID name of the authentication mechanism. All other token formats are authentication-mechanism specific.

After the security context is established between the initiator and the acceptor, messages can be encrypted, decrypted, authenticated, and validated through message integrity. The security context may detect messages that were not sent in order using the unwrap and verifyMIC methods. The out-of-sequence protection is added during the security context's wrap and getMIC methods.

The getMIC method calculates the encrypted message's checksum and passes the checksum in the token. The sender must pass the encrypted message and token to the receiver of the message. The receiver can then use the verifyMIC message to ensure that the checksum is correct. The encrypted message is encrypted with the security context's wrap method. The wrap method can also calculate the checksum of the encrypted message and pass the checksum and message in the same token. The application sends the token to the receiver, which decrypts the message and checks the checksum using the unwrap method. If there is a duplication of messages or the messages are out of sequence, then either method may detect it. The MessageProp class is used to detect if there were any inconsistencies with the encrypted messages. Message protection operations can occur in both directions concurrently.

After all the messages are completed between the initiator and the acceptor, the security context is no longer needed. In Java, there is no explicit delete function; however, any communication and connections must be closed when they are no longer needed, and the dispose method is used from the security context to release any system resources such as the cryptographic keys. Figure 17-1 provides a GSS-API overview.

click to expand
Figure 17-1: GSS-API overview

Benefits of GSS

The GSS-API provides the security services API for initiator and acceptors to act as secure agents through tokens to each other using an underlying authentication mechanism like Kerberos. The GSS-API provides an API for authentication, encryption and decryption of messages, and message integrity. The GSS-API has several authentication protocols and keying mechanisms such as Kerberos, SPKM, SESAME, and SASL that it can implement while hiding the complexity of the authentication mechanisms themselves. The authentication mechanisms are pluggable between the two peers, the initiator and the acceptor.

Cross-Reference  

See Chapter 16 for information on Kerberos.

Another feature of the GSS-API is the capability to delegate the principal's rights and credentials to be applied to another application. Delegation gives the acceptor the capability to act on behalf of the initiator by using the initiator's principals and credentials. The acceptor can impersonate the initiator and any permission needed to access resources. The GSS-API is limited to the functionality provided by the underlying authentication mechanisms because many authentication mechanisms do not provide support for the anonymous authentication.

For those authentication mechanisms that allow it, the GSS-API will be able to use it through its API set. The anonymous authentication gives access to anonymous principals that do not wish to give a name. A reason could be that they want to check out a catalog before registering at a Web site. The security context may check to see if it is an anonymous identity by using the isAnonymous method.

Several other benefits are guaranteed by using the GSS-API for a secure message mechanism. The messages that are sent between the peers' security contexts can check the integrity of the message to see if has been tampered with, check to see if the messages were sent out of sequence, ensure that duplicate messages were not resent , and encrypt/decrypt the messages through keys that were exchanged.

The GSS-API is tightly integrated to the underlying security mechanism that the security context is initialized to support. The GSS-API was developed to generalize the supported authentication mechanisms. The token format is dependent on the initialized authentication module, as well as the type of Quality of Protection (QOP) that is supported by the authentication module. The QOP offers the strength and level of protection that can be offered to each message for a specific authentication module.

GSS API component model

The GSS-API is made up of several components. The components can be categorized into four components :

  • Management components

  • Naming components

  • The security context

  • The message components

The management component initializes the other classes through the use of naming an authentication service provider. The naming component names the principals, host name, service name, anonymous, and authentication mechanism name. The security context is responsible for establishing the security state of the application and any shared cryptographic information between peers. The last of the components are for message manipulation that encrypt/decrypt messages and validate the integrity of the messages.

Management components

The GSS-API uses the org.irtf.jgss.GSSManager as the management class. The GSSManager serves as a factory to create other GSS-API classes such as GSSName, GSSCredential, and GSSContext . The GSSManager provides methods for querying the available authentication mechanisms. The GSSManager creates a default manager when a getInstance method is executed. From the instance of the GSSManager object that is created, the security context is created using the createContext method. The createContext method can set the authentication module by naming the OID of the authentication type or by adding the provider through the manager. The GSSManager class is responsible for finding the service provider through the lookup based on the service provider named mechanism.

Tip  

When you add a provider through the manager, you can add it at the beginning or the end of the list of authentication modules, to be used if no other authentication module is explicitly named.

A service provider lists its support for a mechanism by defining a mapping from the mechanism to a Provider class that implements that mechanism. A provider can support more than one mechanism. For an application to use a provider, the Provider class must be defined in the java.security file. An application can update and manipulate the ordering of the runtime provider list through the GSSManager interface. At runtime, GSS-API searches the list of providers for the first provider that supports the mechanism to be used.

One way to choose a mechanism is to start out with the Simple And Protected GSS-API Negotiation Mechanism (SPNEGO). SPNEGO is a pseudo-mechanism that negotiates an actual mechanism between the two peers. Some other ways the two peers can decide on a mechanism can be found at http://www.ietf.org/rfc/rfc2744.txt . Listing 17-1 demonstrates the lookup of the service provider. The service provider is looked up by passing the OID in the createContext method.

Listing 17-1: The RichGSSService class: An example in creating the security context
start example
 package com.richware.chap17;     import java.security.*; import java.io.*; import java.net.*; import org.ietf.jgss.*;     /**  * Class RichGSSService  * Description: A custom demonstration of  * the acceptor/initiator of the GSS-API.  *  * Copyright:    Copyright (c) 2002 Wiley Publishing, Inc.  * @author Rich Helton <rhelton@richware.com>  * @version 1.0    * DISCLAIMER: Please refer to the disclaimer at the beginning of this book.  */ public class RichGSSService {   /*    * Port number for connection    */   public final static int localPort = 6000;       /*    * true if acceptor, false if initiator    * this will distinguish the two in code    */   public boolean isAcceptor;       /*    * the Server name to connect    */   public final static String hostname = "localhost";       /**    * Method main    * Description: The main driver to run the methods.    *    *    * @param args (no arguments presently).    *    */   public static void main(String args[]) {     DataInputStream  inStream    = null;     DataOutputStream outStream   = null;     Socket           localsocket = null;         try {       RichGSSService service = new RichGSSService();       if(args[0] != null){          if(args[0].equalsIgnoreCase("Server")){          service.isAcceptor = true;          System.out.println("Starting Server");        }         }           /*        * Establish the socket connection        * For the server, the application is just collecting the        * first socket connection        */       if (service.isAcceptor) {         ServerSocket ss = new ServerSocket(service.localPort);         localsocket = ss.accept();       } else {         localsocket = new Socket(service.hostname,                                  service.localPort);       }       /*        * Establish the streams from the socket connection        */       inStream  =         new DataInputStream(localsocket.getInputStream());       outStream =         new DataOutputStream(localsocket.getOutputStream());       System.out.println("Connected to server "                          + localsocket.getInetAddress());       /*        * Create the GSS Manager instance        */       GSSManager manager = GSSManager.getInstance();       /*        * Create the security context        */       System.out.println("Creating Security Context....");       /*        * Create the context from the manager        */       GSSContext context =         service.createContext(manager, service.hostname,                               service.isAcceptor);       if (context == null) {         System.out.println("..creation failed");       }       /*        * Loop until a security context is established         * through tokens        */       service.contextLoop(context, service.isAcceptor,                           inStream, outStream);  /*   * If mutual authentication did not take place, then only the   * client was authenticated to the server. Otherwise, both   * client and server were authenticated to each other.    */ if (context.getMutualAuthState()){      System.out.println("Mutual authentication took place!");  }           /*        * In this example, the initiator writes the message        * and the acceptor reads the message        */       if(service.isAcceptor){        String message = service.readMessage(context,inStream);        System.out.println("Message Read :" + message);        }else{        String message = "GSS Rules";        System.out.println("Writing Message :" + message);        service.writeMessage(context,message,outStream);        }       /*        * Cleanup        */      context.dispose();      localsocket.close();       /*        * Catches        */     } catch (IOException e) {       e.printStackTrace();     } catch (Exception e) {       e.printStackTrace();     }   }       /**    * Method createContext    * Purpose: to start the security context by     * defining the authentication mechanism    * principals and credentials.    *    *    * @param manager the GSSManager    * @param hostname the hostname to connect     * @param isAcceptor is an acceptor or not    *    * @return the security context created    *    */   public GSSContext createContext(GSSManager manager,                                   String hostname,                                   boolean isAcceptor) {         GSSContext context = null;     try {       Oid krb5Mechanism         =         new Oid("1.2.840.113554.1.2.2");       Oid krb5PrincipalNameType =         new Oid("1.2.840.113554.1.2.2.1");           /*        * Create a GSSName out of the server's name.        * If a null is passed in the nametype,         * the underlying mechanism will try to         * parse it as the default syntax that it chooses.        * If the krb5PrincipalNameType is passed in,         * then it will be parsing it in the kerberos         * name type.        */       GSSName serverName = manager.createName(hostname, null);           /*        * Create a security context for the initiator        */       if (!isAcceptor) {         /*          * Identify who the client wishes to be          */         GSSName userName =           manager.createName("rich", GSSName.NT_USER_NAME);             /*          * Acquire credentials for the user          */         GSSCredential userCreds =           manager             .createCredential(userName, GSSCredential               .DEFAULT_LIFETIME, krb5Mechanism, GSSCredential               .INITIATE_ONLY);             /*          * Create a GSSContext for mutual authentication with          * the server.          *    - serverName is the GSSName           * that represents the server.          *    - krb5Mechanism is the Oid for           * the kerberos 5 authentication mechanism.          *    - the credentials for the user          *    - DEFAULT_LIFETIME lets the mechanism           * decide how long the          *      context can remain valid.          * Note: If using a ull for the credentials,           * the GSS-API will use the default           * credentials. This means that the mechanism          * will look among the credentials stored           * in the current Subject to find the           * right kind of credentials that it needs.          */         context =           manager.createContext(serverName, krb5Mechanism,                                 userCreds,                                 GSSContext.DEFAULT_LIFETIME);             /*          * Set the desired optional features on           * the context. set the mutual authentication,          * confidentiality and integrity          */         context.requestMutualAuth(true);         context.requestConf(true);          context.requestInteg(true);       /*        * Create a security context for the acceptor        */       } else {             /*          * Acquire credentials for the server          */         GSSCredential serverCreds =           manager             .createCredential(serverName, GSSCredential               .DEFAULT_LIFETIME, krb5Mechanism, GSSCredential               .ACCEPT_ONLY);             /*          * Instantiate and initialize a security           * context that will wait for an           * establishment request token from the client          */         context = manager.createContext(serverCreds);       }       /*        * Catches        */     } catch (org.ietf.jgss.GSSException e) {       e.printStackTrace();     } catch (Exception e) {       e.printStackTrace();     }         return context;   }     /**    * Method contextLoop    * Purpose: to loop until the context is     * established from the tokens    *    *    * @param context the intitialized token    * @param isAcceptor is the acceptor or not    * @param inStream the input stream    * @param outStream the output stream    *    */   public void contextLoop(GSSContext context,                           boolean isAcceptor,                           DataInputStream inStream,                           DataOutputStream outStream) {     byte[] token = null;     try {       while (!context.isEstablished()) {       /*        * Finish a security context for the acceptor        * Read the token and accept it        */         if (isAcceptor) {           token = new byte[inStream.readInt()];               System.out             .println("Will read input token of size "                      + token.length                      + " for processing by acceptSecContext");           inStream.readFully(token);                token = context.acceptSecContext(token, 0,                                            token.length);       /*        * Else , finish a security context for the initiator        * pass a empty token to initialize the context        */         } else {    token = new byte[0];            /*             * token is ignored on the first call            */           token = context.initSecContext(token, 0,                                          token.length);         }             /*          * Send a token to the peer if one was generated by          * initSecContext          */         if (token != null) {           System.out.println("Will send token of size "                              + token.length                              + " from initSecContext.");           outStream.writeInt(token.length);           outStream.write(token);           outStream.flush();         }             /*          * The initiator has an extra read of the token           * from the acceptor          *          */         if (((!context.isEstablished()) && (!isAcceptor))) {           token = new byte[inStream.readInt()];               System.out             .println("Will read input token of size "                      + token.length                      + " for processing by initSecContext");           inStream.readFully(token);         }       }           System.out.println("Context Established! ");       System.out.println("Client is " + context.getSrcName());       System.out.println("Server is " + context.getTargName());       /*        * Catches        */     } catch (org.ietf.jgss.GSSException e) {       e.printStackTrace();     } catch (IOException e) {       e.printStackTrace();     } catch (Exception e) {       e.printStackTrace();     }   }       /**    * Method readMessage    * Purpose: reads a input stream from the socket    *    * @param context the current security context    * @param inStream the input stream    *    * @return the string read from the input    *    */   public String readMessage(GSSContext context,                             DataInputStream inStream) {     String str = null;     try {       /*        * Create a MessageProp which unwrap will use to         * return information such as the         * Quality-of-Protection that was applied to         * the wrapped token, whether or not it was        * encrypted, etc. Since the initial         * MessageProp values are ignored,         * just set them to the defaults of 0 and false.        */       MessageProp prop = new MessageProp(0, false);           /*        * Read the token. This uses the same token byte array        * as that used during context establishment.        */       byte[] token = new byte[inStream.readInt()];           System.out.println("Will read token of size "                          + token.length);       inStream.readFully(token);       byte[] bytes = context.unwrap(token, 0, token.length,                                     prop);       str = new String(bytes);        System.out.println("Received data \"" + str                          + "\" of length " + str.length());       System.out.println("Confidentiality applied: "                          + prop.getPrivacy());           /*        * Catches        */     } catch (org.ietf.jgss.GSSException e) {       e.printStackTrace();     } catch (IOException e) {       e.printStackTrace();     } catch (Exception e) {       e.printStackTrace();     }         return str;   }       /**    * Method writeMessage    * Purpose: writes the output stream to the socket    *    * @param context the current context    * @param message the message to write to the output    * @param outStream the output stream    *    */   public void writeMessage(GSSContext context, String message,                            DataOutputStream outStream) {     try {       byte[] messageBytes = message.getBytes();           /*        * The first MessageProp argument is 0 to request        * the default Quality-of-Protection.        * The second argument is true to request        * privacy (encryption of the message).        */       MessageProp prop = new MessageProp(0, true);           /*        * Encrypt the data and send it across.         * Integrity protection is always applied,        * irrespective of confidentiality (i.e., encryption).        * You can use the same token (byte array) as that         * used when establishing the context.        */       byte[] token = context.wrap(messageBytes, 0,                                   messageBytes.length, prop);       System.out.println("Will send wrap token of size "                          + token.length);       outStream.writeInt(token.length);       outStream.write(token);       outStream.flush();           /*        * Catches        */     } catch (org.ietf.jgss.GSSException e) {       e.printStackTrace();     } catch (IOException e) {       e.printStackTrace();     } catch (Exception e) {       e.printStackTrace();     }   } } 
end example
 

Naming components

The GSS-API can be used in conjunction with JAAS. JAAS uses the concept of a subject, using a named subject in the form of the principal and associated credentials to prove the identity.

Cross-Reference  

See Chapter 19 for information on JAAS.

For the GSS-API, there are two classes that make the principal and credentials: the org.ietf.jgss.GSSName interface to handle principal entities and the org.ietf.jgss.GSSCredential interface to encapsulate the credentials for the entity. The GSSName contains many representations of the principal and underlying mechanisms that need to be named. Some of the names can consist of the host name, the user name, an anonymous name, and machine name.

The mechanism name is specified by a matching OID that defines the mechanism. Listing 17-1 demonstrates the Kerberos 5 OID 1.2.840.113554.1.2.2 that is defined in the Kerberos RFC 1964 ( http://www.ietf.org/rfc/rfc1964.txt ). The mechanism name can be used in the GSSName interface to define the name of the authentication mechanism. The different types of GSSNames , such as the anonymous name type, are predefined in the GSSName interface as an OID to be passed in the createName method. The anonymous name type is an OID defined as the NT_ANONYMOUS name type in the GSSName . The purpose of the GSSName is to define a name construct to be passed to other GSS-API methods.

Cross-Reference  

See Chapter 16 for information on Kerberos.

The GSSCredential interface encapsulates the credentials for an entity. A credential contains all the necessary cryptographic information to enable the creation of a context on behalf of the entity that it represents. A named entity, such as a user defined in a GSSName , can have multiple credentials. The GSS-API and other mechanisms communicating to it, such as JAAS, can have multiple authentication mechanisms to authenticate the same principal. To authenticate through multiple types of authentication mechanisms, different types of credentials are required.

There would have to be a credential per authentication mechanism. The Kerberos v5 authentication module requires a Kerberos credential. The same principal could be used throughout in many cases because the name of the user does not change; however, in some cases the type of the principal name may change when being transported across multiple protocols like GSS-API to JSSE. Using the GSS-API requires a Kerberos naming type in almost all conditions, so the principal name type does not need to change. Setting the credentials for both the initiator and acceptor peers of the GSS-API service is shown in Listing 17-1.

Security context components

The org.ietf.jgss.GSSContext is the interface that encapsulates the GSS-API security context and provides security services such as the wrap, unwrap, getMIC, and verifyMIC methods to encrypt, decrypt, and check the validity of messages.

Tip  

The security context is established between peers using the peers' acquired credentials. Multiple contexts may exist simultaneously between a pair of peers.

Before the context establishment phase is initiated, the context initiator may request specific characteristics desired of the established context such as the initiator requesting mutual authentication. The request methods in the security context are used to set the properties of the security context and request operations from the authentication module. To request mutual authentication from the security context to the authentication mechanism, the context.requestMutualAuth(true) method is used in Listing 17-1. The request is made to the authentication mechanism.

The authentication mechanism may or may not support some of these operations. For handling the mutual authentication, nothing else needs to be accomplished in the GSS-API outside the normal transfer of tokens to transfer for the security context. If there are no acceptor credentials, and the initiator is expecting a specific set of credentials, a GSSException will be thrown stating that the authentication was denied from the acceptor with the NO_CRED constant field thrown. The NO_CRED constant field is defined as no credentials in the org.ietf.jgss.GSSException class.

Besides requesting the operations in the security context, the security context can check if the state was set by the underlying security context with the GSSContext's get methods. To check on the acceptor peer if the initiator requested mutual authentication and there was support from the authentication mechanism, the context.getMutualAuthState method is used to return true if mutual authentication was requested.

The context establishment phase begins with the first call to the initSecContext method by the context initiator. During this phase, the initSecContext and acceptSecContext methods produce the GSS-API authentication tokens that the calling application needs to send to its peers. The initSecContext initiates the token from the initiator, and the acceptSecContext method accepts the token from the acceptor. If no exceptions are thrown, the peer application has established the security context connections between the tokens. After the security context is established, the peer can call the isEstablished method to see if the context is established. The peer can call isProtReady to determine the actual characteristics and services of the established context.

To see if the initiator requires delegation, the acceptor's security context can use the getCredDelegState method to check the state. If delegation is required, the acceptor can use the getDelegCr method to retrieve the GSSCredentials from the initiator as its credentials to use instead of the server's principals and credentials. In order for the Kerberos authentication mechanism to delegate the credentials, the DelegationPermission in the policy file must be set to allow the Kerberos server to delegate the credentials.

Encryption and decryption components

After the security context has been established, messages and tokens can be passed from peer to peer. In most cases, the initiator will send the first message to the acceptor. The peer communications is similar to a client sending a message to a server through sockets, except that message encryption, decryption, and message integrity takes place. The initiator usually starts sending a message because it normally initiates the message exchange. To encrypt the message, the security context's wrap method is used to encrypt a byte array. The wrap method also can take an input stream to define where the message will be sent. The term "wrap" is defined in GSS-API as wrapping the security around the message.

When the message is received on the corresponding peer, such as the acceptor, the message needs to be unwrapped. The security context uses the unwrap method to transform the ciphertext back into plaintext. Following the token that the message is wrapped in are also any message properties such as the message integrity checksum. Most of the message properties are returned in the org.ietf.jgss.MessageProp class that is sent with the wrap method and retrieved with the unwrap method. The message property is the property of a specific message, and not global to all the messages. Some of the properties that can be retrieved include information about whether the token is duplicated , if there is a gap between tokens, if the token is out of sequence, and the level of quality of protection.

Note  

The message property can set the level of quality of protection. The QOP is authentication-mechanism dependent.

Other message methods are the getMIC and verifyMIC . The getMIC method generates a message integrity code to be passed to the peer to check the validity of the message. The verifyMIC method checks the message integrity that it received from the peer. Listing 17-2 displays the code for establishing the security context, the wrap method, and unwrap method.

Listing 17-2: The context loop, wrap, and unwrap methods
start example
 /**    * Method contextLoop    * Purpose: to loop until the context is     * established from the tokens    *    *    * @param context the intitialized token    * @param isAcceptor is the acceptor or not    * @param inStream the input stream    * @param outStream the output stream    *    */   public void contextLoop(GSSContext context,                           boolean isAcceptor,                            DataInputStream inStream,                           DataOutputStream outStream) {         byte[] token = null;     try {           while (!context.isEstablished()) {       /*        * Finish a security context for the acceptor        * Read the token and accept it        */         if (isAcceptor) {           token = new byte[inStream.readInt()];               System.out             .println("Will read input token of size "                      + token.length                      + " for processing by acceptSecContext");           inStream.readFully(token);               token = context.acceptSecContext(token, 0,                                            token.length);       /*        * Else , finish a security context for the initiator        * pass an empty token to initialize the context        */         } else {    token = new byte[0];               /*             * token is ignored on the first call            */           token = context.initSecContext(token, 0,                                          token.length);         }             /*          * Send a token to the peer if one was generated by          * initSecContext          */         if (token != null) {           System.out.println("Will send token of size "                              + token.length                              + " from initSecContext.");           outStream.writeInt(token.length);           outStream.write(token);           outStream.flush();         }             /*          * The initiator has an extra read of the token           * from the acceptor          *          */         if (((!context.isEstablished()) && (!isAcceptor))) {           token = new byte[inStream.readInt()];               System.out             .println("Will read input token of size "                      + token.length                      + " for processing by initSecContext");           inStream.readFully(token);         }       }           System.out.println("Context Established! ");       System.out.println("Client is " + context.getSrcName());       System.out.println("Server is " + context.getTargName());       /*        * Catches        */     } catch (org.ietf.jgss.GSSException e) {       e.printStackTrace();     } catch (IOException e) {       e.printStackTrace();     } catch (Exception e) {       e.printStackTrace();     }   }       /**    * Method readMessage    * Purpose: reads a input stream from the socket    *    * @param context the current security context    * @param inStream the input stream    *    * @return the string read from the input    *    */   public String readMessage(GSSContext context,                             DataInputStream inStream) {         String str = null;         try {           /*        * Create a MessageProp which unwrap will use to         * return information such as the         * Quality-of-Protection that was applied to         * the wrapped token, whether or not it was        * encrypted, etc. Since the initial         * MessageProp values are ignored,         * just set them to the defaults of 0 and false.        */       MessageProp prop = new MessageProp(0, false);           /*        * Read the token. This uses the same token byte array        * as that used during context establishment.        */       byte[] token = new byte[inStream.readInt()];           System.out.println("Will read token of size "                          + token.length);       inStream.readFully(token);           byte[] bytes = context.unwrap(token, 0, token.length,                                     prop);           str = new String(bytes);           System.out.println("Received data \"" + str                          + "\" of length " + str.length());       System.out.println("Confidentiality applied: "                          + prop.getPrivacy());           /*        * Catches        */     } catch (org.ietf.jgss.GSSException e) {       e.printStackTrace();     } catch (IOException e) {       e.printStackTrace();     } catch (Exception e) {       e.printStackTrace();     }         return str;   }       /**    * Method writeMessage    * Purpose: writes the output stream to the socket    *    * @param context the current context    * @param message the message to write to the output    * @param outStream the output stream    *    */   public void writeMessage(GSSContext context, String message,                            DataOutputStream outStream) {         try {       byte[] messageBytes = message.getBytes();           /*        * The first MessageProp argument is 0 to request        * the default Quality-of-Protection.        * The second argument is true to request        * privacy (encryption of the message).        */       MessageProp prop = new MessageProp(0, true);           /*        * Encrypt the data and send it across.         * Integrity protection is always applied,        * irrespective of confidentiality (i.e., encryption).        * You can use the same token (byte array) as that         * used when establishing the context.        */       byte[] token = context.wrap(messageBytes, 0,                                   messageBytes.length, prop);           System.out.println("Will send wrap token of size "                          + token.length);       outStream.writeInt(token.length);        outStream.write(token);       outStream.flush();           /*        * Catches        */     } catch (org.ietf.jgss.GSSException e) {       e.printStackTrace();     } catch (IOException e) {       e.printStackTrace();     } catch (Exception e) {       e.printStackTrace();     }   } } 
end example
 
  


Java Security Solutions
Java Security Solutions
ISBN: 0764549286
EAN: 2147483647
Year: 2001
Pages: 222

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net