Subject: Proposed changes to draft-ietf-cat-gssv2-javabind-01.txt

From: Mayank Upadhyay <[email-masked]>
Date: Thu, 13 May 1999 04:39:37 -0700 (PDT)

Attached here is a proposal that makes changes to the current Java
language bindings for GSS-API in draft-ietf-cat-gssv2-javabind-01.txt to
address the issues raised at the CAT meeting in Minneapolis.

There are some new interfaces and methods introduced that will allow the
application programmer to use more than one independent GSS-API
implementation at the same time in his/her program. One reason to do this
might be that different implementations available might support different
sets of mechanisms and the application might need to pick a mechanism from
the union of all the sets at runtime.

The changes will also allow the application to explicitly specify the
provider for the GSS-API implementation it wishes to use. This might be
useful to applets that wish to use a custom GSS-API implementation with
support for a proprietary mechanism rather than the default GSS-API
implementation that the browser uses. 

Please note that this effort does not obviate the need for a service
provider API. A service provider API (SPI) is a set of interfaces at a
lower level in the GSS stack that the application programmer does not see,
but the security mechanism programmer implements. Such an API will allow
any given GSS-API implementation to be modularized such that it becomes a
multi-mechanism implementation which can plug in any arbitrary security
mechanism underneath it at run time. Rather than extending a GSS-API
implementation in this fashion to allow for a new mechanism X, the
proposal in this mail simply incorporates the suggestion for interfaces at
the top level which makes it possible to achieve the same flexibility by
going to a completely different GSS-API implementation that would support
the mechanism X. While this is a quick way to solve the problem till the
SPI is standardized, the trade off in this approach is that the programmer
has to track where he/she obtains some of the objects from because certain
classes' instances cannot be passed back and forth between two different
implementations. 

There is code attached for a sample application that will show how the
programmer uses these new API's. We would appreciate it if you could
evaluate the proposal and the impact of the API changes and send us your
comments before we make the changes to the draft bindings. Please send us
you comments by 27 May 1999.

If you are interested in javadocs and class diagrams they will be
available by the end of this week at the following URL: 

http://playground.sun.com/~mdu/JGSS.html

Thanks in advance!

Sincerely,
Mayank Upadhyay
Jack Kabat
                                                 Mayank Upadhyay
                                                 Jack Kabat

                                                 May 1999

We propose to make the following changes to the current Java
language bindings for GSS-API in draft-ietf-cat-gssv2-javabind-01.txt to
address the issues raised at the CAT meeting in Minneapolis:

			New Interfaces
			--------------

The following four interfaces will be added:

(a) GSSContextInt: The interface equivalent of the current GSSContext
                   class.

(b) GSSCredentialInt: The interface equivalent of the current
                      GSSCredential class.

(c) GSSNameInt: The interface equivalent of the current GSSName
                class.

(d) GSSFactory: An interface for the factory class that would be
                provided with each implementation of GSS-API.

(See appendix A for the complete definition.)

When an application programmer wishes to make use of multiple GSS-API
implementations these interfaces will form the glue that will allow uniform
access to the implementing classes from different providers. As will be
explained later, it will be possible for the application programmer to
avoid the use of these interfaces altogether and leave the dirty work for
certain concrete wrapper classes to do behind the scenes.

It is expected that between two differing implementations of the GSS-API it
will be the concrete classes implementing these interfaces that possess
implementation specific knowledge and may not be inter-mixed. That is, an
object that implements GSSNameInt in GSS-API implementation #1 may not be
passed to a GSSCredentialInt from GSS-API implementation #2.

However, there are some classes that are safe to be instantiated from any
GSS-API implementation and then be passed to other classes from any other
GSS-API implementation. These are Oid, GSSException, MessageProp, and
ChannelBinding. These classes:

(a) do not take other GSS-API classes as arguments in any of their
methods

(b) are simple, general purpose utility classes and do not depend on
any knowledge of the underlying mechanism layers. (Think of them as
being similar to java.lang.String.)

In the interest of not bloating up the API and keeping the application
programmer's life simple, we do not recommend adding corresponding
interfaces for these classes.

	   		   Object Creation
			   ----------------

Objects implementing the three interfaces GSSContextInt,
GSSCredentialInt, and GSSNameInt will be obtained via the implementation
specific GSSFactory. The GSSFactory, in turn, will be obtained using the
Java security provider model (see the class
java.Security.Provider). Essentially, a GSS-API provider will map the
property "org.ietf.jgss.FactoryImplementation" to the name of the
GSSFactory implementation class from that provider.

The application programmer will never need to obtain a reference to an
instance of GSSFactory. It will be the responsibility of the GSSManager
class to obtain a reference to the implementation specific GSSFactory from
the preferred provider using the "org.ietf.jgss.FactoryImplementation"
property.

If need be, the application programmer can obtain a reference to
an object implementing one of the other three interfaces GSSContextInt,
GSSCredentialInt, and GSSNameInt by going through the GSSManager. The
GSSManager will simply query the GSSFactory from the preferred provider and
obtain this reference from it.

The following methods will be added to GSSManager to support transparent
selection of providers:

(1) Setting the default GSS-API Provider:

   - void GSSManager.setDefaultProvider(Provider p)

(2) Context related factory methods:

   - GSSContextInt GSSManager.getContext(Provider p);
   - GSSContextInt GSSManager.getContext(); // use the default
                                            // provider set in (1) 

(3) Credential related factory methods:

   - GSSCredentialInt GSSManager.getCredential(Provider p);
   - GSSCredentialInt GSSManager.getCredential(); // default provider

(4) Name related factory methods:

   - GSSNameInt GSSManager.getName(Provider p);
   - GSSNameInt GSSManager.getName(); // default provider

Each of the three interfaces (GSSContextInt, GSSCredentialInt, and
GSSNameInt) will have overloaded init() methods with
arguments that exactly match the arguments taken by the constructors
for their current concrete class counterparts. The init() call should
be made after using the GSSManager to obtain a reference to the object
that implements the interface.

			Wrapper Classes
			---------------

For ease of use, the original concrete classes GSSContext, GSSName,
and GSSCredential will be retained as wrapper classes around their
respective interfaces GSSContextInt, GSSNameInt, and
GSSCredentialInt. Calling the constructor on one of these wrapper
classes should obtain an implementation of the corresponding interface
from the preferred provider using the GSSManager factory methods. The
wrapper will then call init() on object and store a reference to
it. When any method in the wrapper class is invoked it should
delegate that call to this object.

The wrapper classes will implement the respective interfaces that they are
meant for. As a result a wrapper class will define all the methods that
come with the interface and it will also pass the compiler's type checking
when passed as argument to methods that expect the counterpart interface.

			Changes to Method Signatures
			----------------------------

Any method in any of the classes in the org.ietf.jgss package that
took as argument an instance of GSSContext, GSSCredential, or
GSSName will now take the corresponding interface instead.

The same rule will apply to methods that returned an instance of
GSSContext, GSSCredential, or GSSName.

The methods that get affected by this change and their new versions are
listed in Appendix B.

A note on mixing objects:
-------------------------

By the term "mixing objects" we mean passing objects obtained from one 
GSS-API implementation to another. The earlier section on the new
interfaces talks about this in more detail. To reiterate, an object
implementing an interface GSSContextInt, GSSNameInt, or
GSSCredentialInt cannot be freely passed around to other objects
if the application is using two or more GSS-API implementations at
the same time.

To help the application programmer track which implementation an
object of one of these types came from, the following methods are
defined:

  - Provider GSSContextInt.getProvider()

  - Provider GSSNameInt.getProvider()

  - Provider GSSCredentialInt.getProvider()

			Sample Applications
			-------------------

Files: 

SimpleClient.java 
SimpleServer.java 

Description:

Attached is a sample applications that will demonstrate how to use
the API with the wrapper classes and also directly with the
interfaces. The application consists of a server and a client. The
server listens for the client's request and when the connection
request is received, it spawns a new thread that serves the client in
a secure fashion.

The server uses the interfaces to obtain references to objects from
two different providers. The client uses concrete classes with
one provider but is still able to explicitly set the provider it
wishes to use.

The GSS-API implementations at the client and server ends may or may
not be multi-mechanism. Moreover, the server and the client may be
using different GSS-API implementations, but obviously the underlying
mechanism the client chooses to use must be available for use in the
server side GSS-API implementation or context establishment will fail.

Appendix A
----------

New interfaces:

/**
 * GSSFactory is the main interface that a provider implements. The
 * GSSManager locates the provider's implementation of this interface and 
 * delegates to it all calls that require implementation specific
 * knowledge.
 * The provider maps the name of the implementing class to the property 
 * "org.ietf.jgss.FactoryImplementation".
 */
public interface GSSFactory {

	// Factory methods
	public GSSContextInt    getContext();
	public GSSCredentialInt getCredential();
	public GSSNameInt       getName();

	// Corresponds to methods of the same name in GSSManager.
	// GSSManager delegates call to appropriate GSSFactory.
	public Oid[] getMechs();
        public Oid[] getNamesForMech(Oid mech) throws GSSException;
        public Oid[] getMechsForName(Oid nameType);
        public Oid getDefaultMech();
}

/**
 * The counterpart of the GSSContext class in
 * draft-ietf-cat-gssv2-javabind-01.txt. The only differences are:
 * (a) this interface has oveloaded init() methods instead of constructors
 * (b) this interfaces adds a getProvider method
 * (c) All references to GSSName and GSSCredential have been replaced
 *     by GSSNameInt and GSSCredentialInt respectively.
 */
public interface GSSContextInt {

	public static final int INDEFINITE;
	public static final int COMPLETE;
	public static final int CONTINUE_NEEDED;

	public void init(GSSNameInt peer, Oid mechOid, GSSCredentialInt myCred,
                                   int lifetime) throws GSSException;
	public init(GSSCredentialInt myCred) throws GSSException;
	public init(byte [] interProcessToken) throws GSSException;

	public byte[] init(byte inputBuf[], int offset, int len)
	                                   throws GSSException;
	public int init(InputStream inputBuf, OutputStream outputBuf)
	                                   throws GSSException;
	public byte[] accept(byte inTok[], int offset, int len)
	                                   throws GSSException;
	public int accept(InputStream inputBuf, OutputStream outputBuf)
	                                   throws GSSException;
	public boolean isEstablished();
	public void dispose() throws GSSException;

	public int getWrapSizeLimit(int qop, boolean confReq,
	                           int maxTokenSize) throws GSSException;
	public byte[] wrap(byte inBuf[], int offset, int len,
	                           MessageProp msgProp) throws GSSException;
	public void wrap(InputStream inBuf, OutputStream outBuf,
	                     MessageProp msgProp) throws GSSException;
	public byte [] unwrap(byte[] inBuf, int offset, int len,
	                           MessageProp msgProp) throws GSSException;
	public void unwrap(InputStream inBuf, OutputStream outBuf,
	                           MessageProp msgProp) throws GSSException;
	public byte[] getMIC(byte []inMsg, int offset, int len,
	                           MessageProp msgProp) throws GSSException;
	public void getMIC(InputStream inMsg, OutputStream outBuf,
	                           MessageProp msgProp) throws GSSException;
	public void verifyMIC(byte []inTok, int tokOffset, int tokLen,
	                           byte[] inMsg, int msgOffset, int msgLen,
	                           MessageProp msgProp) throws GSSException;
	public void verifyMIC(InputStream inTok, InputStream inMsg,
	                           MessageProp msgProp) throws GSSException;

	public byte [] export() throws GSSException;

	public void requestMutualAuth(boolean state) throws GSSException;
	public void requestReplayDet(boolean state) throws GSSException;
	public void requestSequenceDet(boolean state) throws GSSException;
	public void requestCredDeleg(boolean state) throws GSSException;
	public void requestAnonymity(boolean state) throws GSSException;
	public void requestConf(boolean state) throws GSSException;
	public void requestInteg(boolean state) throws GSSException;
	public void requestLifetime(int lifetime) throws GSSException;
	public void setChannelBinding(ChannelBinding cb) throws GSSException;
	public boolean getCredDelegState();
	public boolean getMutualAuthState();
	public boolean getReplayDetState();
	public boolean getSequenceDetState();
	public boolean getAnonymityState();
	public boolean isTransferable() throws GSSException;
	public boolean isProtReady();
	public boolean getConfState();
	public boolean getIntegState();
	public int getLifetime();
	public GSSNameInt getSrcName() throws GSSException;
	public GSSNameInt getTargName() throws GSSException;
	public Oid getMech() throws GSSException;
	public GSSCredentialInt getDelegCred() throws GSSException;
	public boolean isInitiator() throws GSSException;

	public Provider getProvider();
}

/**
 * The counterpart of the GSSCredential class in
 * draft-ietf-cat-gssv2-javabind-01.txt. The only differences are:
 * (a) this interface has oveloaded init() methods instead of constructors
 * (b) this interfaces adds a getProvider method
 * (c) All references to GSSName have been replaced by GSSNameInt.
 */
public interface GSSCredentialInt {
	public static final int INITIATE_AND_ACCEPT;
	public static final int INITIATE_ONLY;
	public static final int ACCEPT_ONLY;
	public static final int INDEFINITE;

	public init(int usage) throws GSSException;
	public init(GSSNameInt aName, int usage) throws GSSException;
	public init(GSSNameInt aName, int lifetime, Oid mechOid,
	                         int usage) throws GSSException;
	public init(GSSNameInt aName, int lifetime, Oid mechs[],
	                         int usage) throws GSSException;

	public void dispose() throws GSSException;
	public GSSNameInt getGSSName() throws GSSException;
	public GSSNameInt getGSSName(Oid mechOID) throws GSSException;
	public int getRemainingLifetime() throws GSSException;
	public int getRemainingInitLifetime(Oid mech) throws GSSException;
	public int getRemainingAcceptLifetime(Oid mech) throws GSSException;
	public int getUsage() throws GSSException;
	public int getUsage(Oid mechOID) throws GSSException;
	public Oid[] getMechs() throws GSSException;
	public void add(GSSNameInt aName, int initLifetime, int acceptLifetime,
	                           Oid mech, int usage) throws GSSException;
	public boolean equals(Object another);

	public Provider getProvider();
}

/**
 * The counterpart of the GSSName class in
 * draft-ietf-cat-gssv2-javabind-01.txt. The only differences are:
 * (a) this interface has oveloaded init() methods instead of constructors
 * (b) this interfaces adds a getProvider method
 * (c) All references to GSSName have been replaced by GSSNameInt.
 */
public interface GSSNameInt {

	public static final Oid NT_HOSTBASED_SERVICE;
	public static final Oid NT_USER_NAME;
	public static final Oid NT_MACHINE_UID_NAME;
	public static final Oid NT_STRING_UID_NAME;
	public static final Oid NT_ANONYMOUS;
	public static final Oid NT_EXPORT_NAME;

	public init(String nameStr, Oid type) throws GSSException;
	public init(byte name[], Oid type) throws GSSException;
	public init(String nameStr, Oid nameType, Oid mechType)
	                                   throws GSSException;
	public init(byte name[], Oid nameType, Oid mechType)
	                                   throws GSSException;

	public boolean equals(Object another);
	public boolean equals(GSSNameInt another) throws GSSException;
	public GSSNameInt canonicalize(Oid mechOid) throws GSSException;
	public byte[] export() throws GSSException;
	public String toString();
	public Oid getStringNameType() throws GSSException;
	public Object clone() throws CloneNotSupportedException;
	public boolean isAnonymous();

	public Provider getProvider();
}

Appendix B
----------

Change in method signatures:

Old: boolean GSSName.equals(GSSName)
New: boolean GSSName.equals(GSSNameInt)

Old: GSSName    GSSName.canonicalize(Oid)
New: GSSNameInt GSSName.canonicalize(Oid)

Old: GSSCredential(GSSName,    int) //Constructor for GSSCredential
New: GSSCredential(GSSNameInt, int)

Old: GSSCredential(GSSName,    int, Oid, int) //Constructor for GSSCredential
New: GSSCredential(GSSNameInt, int, Oid, int)

Old: GSSCredential(GSSName,    int, Oid[], int) //Constructor for GSSCredential
New: GSSCredential(GSSNameInt, int, Oid[], int)

Old: GSSName    GSSCredential.getGSSName()
New: GSSNameInt GSSCredential.getGSSName()

Old: GSSName    GSSCredential.getGSSName(Oid)
New: GSSNameInt GSSCredential.getGSSName(Oid)

Old: void GSSCredential.add(GSSName,    int, int, Oid, int)
New: void GSSCredential.add(GSSNameInt, int, int, Oid, int)

Old: GSSContext(GSSName, Oid, GSSCredential, int) //Constructor for GSSContext
New: GSSContext(GSSNameInt, Oid, GSSCredentialInt, int)

Old: GSSContext(GSSCredential) //Constructor for GSSContext
Old: GSSContext(GSSCredentialInt)

Appendix C
----------

New public methods added to GSSManager:

   - void GSSManager.setDefaultProvider(Provider p)

   - GSSContextInt GSSManager.getContext(Provider p);
   - GSSContextInt GSSManager.getContext(); // default provider

   - GSSCredentialInt GSSManager.getCredential(Provider p);
   - GSSCredentialInt GSSManager.getCredential(); // default provider

   - GSSNameInt GSSManager.getName(Provider p);
   - GSSNameInt GSSManager.getName(); // default provider

   -  Oid[] getMechs(Provider p);

   -  Oid[] getNamesForMech(Provider p, Oid mech) throws GSSException;

   -  Oid[] getMechsForName(Provider p, Oid nameType);

   -  Oid getDefaultMech(Provider p);

Change of name of public methods in GSSContext:

Old: init
New: initSecContext

Old: accept
New: acceptSecContext
import org.ietf.JGSS.*;
import java.net.*;
import java.io.*;
import java.security.Provider;
import java.security.Security;

/**
 * This is the sketch for a simple client program that excercises
 * CONCRETE CLASSES with the proposed changes to
 * draft-ietf-cat-gssv2-javabind-01.txt. It explicitly
 * specifies the GSS-API provider that the concrete class wrappers
 * should use behind the scenes.
 * <hr>
 * The client program acts as a GSS context initiator. The main() method
 * starts up the client and tries to connect to the server at the specified
 * address and port. The client code then sends some bytes to the server
 * and reads back a response.
 */

//  Note: Copyright statement at bottom of file.

public class SimpleClient {

    private String serviceName; // name of peer (ie. server)
    private GSSCredential clientCred = null;
    private GSSContext secContext = null;
    private Oid mech; // underlying mechanism to use

    private InetAddress addr; // server address
    private int port; // server port
    private Socket sock = null;

    // MyNetworkIOHelper is a utility class containing routines to help
    // with the network I/O.
    private MyNetworkIOHelper nw;

    /**
     * Constructor for SimpleClient that simply stores the arguments passed
     * to private data for use later on.
     */
    public SimpleClient(InetAddress addr, String serviceName,
		     int port, Oid mech) throws GSSException{

	this.addr = addr;
	this.serviceName = serviceName;
	this.port = port;
	this.mech = mech;
    }

    /**
     * The SimpleClient method that connects to the server, establishes a
     * security context with it, sends some data across and gets back a
     * response.
     */
    private void clientAction() throws IOException, GSSException{

	sock = new Socket(addr, port);

	// MyNetworkIOHelper is a utility class containing routines
	// to help with the network I/O.
	nw = new MyNetworkIOHelper(sock);

	initializeGSS();
	establishContext();
	doCommunication();
    }

    /**
     * Acquire credentials for the client. Throws a GSSException if any
     * fatal GSS-API error occurs.
     */
    private void initializeGSS() throws GSSException {

	// Commenting these two lines out will use the default provider
	// set up on the system.
	Provider provider = Security.getProvider("COM.XXX.YYY");
	GSSManager.setDefaultProvider(provider);

	clientCred = new GSSCredential(null /* default principal*/, 
			GSSCredential.INDEFINITE /* max lifetime */,
			mech /* mechanism  to use */,
			GSSCredential.INITIATE_ONLY /* init sec context */);

	logGSSInitResults(clientCred);

    }

    /**
     * Does the security context establishment with the server. Throws
     * a GSSException if any fatal GSS-API error occurs.
     */
    private void establishContext() throws GSSException, IOException {

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

	// The code here uses the wrapper concrete classes but it could
	// have alternatively used the factory methods in GSSManager
	// followed by the init() call.

	GSSName peer = new GSSName(serviceName,
				   GSSName.NT_HOSTBASED_SERVICE);
	
	secContext = new GSSContext(peer, mech, gssCred,
			GSSContext.INDEFINITE/*lifetime*/);

	// Will need to support confidentiality
	secContext.requestConf(true);
	
	while (!secContext.isEstablished()) {
    
		outToken = secContext.initSecContext(inToken, 0,
						     inToken.length);

		if (outToken != null)
		    nw.writeGSSToken(outToken);

		if (!secContext.isEstablished())
		    inToken = nw.readGSSToken();
	}

	logContextInitResults(secContext);

    }

    /**
     * Sends some data to the server and reads back the response. Throws
     * a GSSException if any fatal GSS-API error occurs.
     */
    private void doCommunication() throws GSSException, IOException {
	    byte[] inToken = null;
	    byte[] outToken = null;
	    byte[] buffer;

	    GSSName peer;

	    // Container for multiple input-output arguments to and from the
	    // per-message routines (ie. wrap/unwrap).
	    MessageProp messgInfo = new MessageProp();

	    peer = secContext.getSrcName();
	    
	    /*
	     * Now send some bytes to the server to be processed. They
	     * will be integrity protected but not encrypted for
	     * privacy.
	     */
	    
	    buffer = readFromFile();
	    
	    // Set privacy to false and use the default QOP
	    messgInfo.setPrivacy(false);
	    
	    outToken = secContext.wrap(buffer, 0, buffer.length,
				       messgInfo);
	    
	    nw.writeGSSToken(outToken);
	    
	    /*
	     * Now read the response from the server.
	     */
	    
	    inToken = nw.readGSSToken();
	    buffer = secContext.unwrap(inToken, 0, inToken.length,
				      messgInfo);
	    // All ok if no exception was thrown!
	    
	    logUnwrapResults(peer, messgInfo);
	    
	    print(new String(buffer));
	    
    } // end of doCommunication method

    /**
     * Obtain information using the Java equivalent of the
     * GSS_Inquire_cred() call and log it. This is called right after the
     * credentials are acquired.
     */
    private static void logGSSInitResults(GSSCredential cred)
	throws GSSException {

	Oid[] availMechs = cred.getMechs();
	
	print("GSSCredential created for " + cred.getGSSName());
	print("Credential lifetime (sec)=" +
	      cred.getRemainingLifetime());
	
	print("Mechanisms available to ConServer are:");
	for (int i=0; i < availMechs.length; i++) 
	    print(availMechs[i].toString());
	
    }
    
    /**
     * Obtain information about the security context using the Java
     * equivalent of the GSS_Inquire_context() call and log it. This is
     * called after the security context has been established.
     */
    private static void logContextInitResults(GSSContext context)
	throws GSSException {

	GSSName peer = context.getSrcName();
	Oid mech = context.getMech();
	print("Security context established with " + peer + 
	      " using underlying mechanism " + mech.toString());
    }

    /**
     * Log information about the last unwrap call using the MessageProp
     * object that the call filled in.
     */
    private static void logUnwrapResults(GSSName peer,
					 MessageProp messgInfo) {

	print("Message from "       + peer.toString() + " arrived.");
	print("Was it encrypted? "  + messgInfo.getPrivacy());
	print("Duplicate Token? "   + messgInfo.isDuplicateToken());
	print("Old Token? "         + messgInfo.isOldToken());
	print("Unsequenced Token? " + messgInfo.isUnseqToken());
	print("Gap Token? "         + messgInfo.isGapToken());

    }

    private static void printUsage() {
	print("Usage: java SimpleClient <server_addr> <service_name> <port> <mech_oid>");
    }

    private static void print(String message) {
	System.out.println(message);
    }

    /**
     *  The main method for this class. The usage is as follows:
     * "java SimpleClient <server_addr> <service_name> <port> <mech_oid>"
     * 
     * This method also handles all GSSException's and IOException's
     * thrown in any of the other routines.
     */
    public static final void main(String args[])
    throws IOException, GSSException {

	    SimpleClient client = null;

	if (args.length <  4) {
	    printUsage();
	    System.exit(1);
	}
	
	try {

	    InetAddress addr = InetAddress.getByName(args[0]);
	    String service_name = args[1];
	    int port = Integer.parseInt(args[2]);
	    Oid mech = new Oid(args[3]);
	    
	    client = new SimpleClient(addr, service_name, port, mech);
	    
	    client.clientAction();

	} catch (GSSException e) {
	    print("GSS-API Error: " + e.getMessage());

	} catch (IOException e) {
	    print("Network Error: " + e.getMessage());
	    
	} catch (NumberFormatException e) {
	    // Could not parse port
	    printUsage();
	    System.exit(1);

	} finally {
	    
	    if (client != null) {

		if (client.secContext != null)
		    client.secContext.dispose(); // delete the security context
		
		if (client.clientCred != null)
		    client.clientCred.dispose(); // destroy credentials
		
		if (client.sock != null)
		    client.sock.close();
	    }
	}

    } // end of main()
    
} // end of class SimpleClient

/*

Full Copyright Statement

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

*/
import org.ietf.JGSS.*;
import java.net.*;
import java.io.*;
import java.security.Provider;
import java.security.Security;

/**
 * This is the sketch for a simple server program that exercises the
 * INTERFACES that are proposed to be added to
 * draft-ietf-cat-gssv2-javabind-01.txt. It explicitly specifies the
 * GSS-API provider it wishes to use to instantiate classes
 * implementing these interfaces.
 * <hr>
 * The server program acts as a GSS context acceptor. The main() method
 * starts up the server on the port specified and makes it wait for a
 * client request. Each client request is handled in a different thread
 * with a different GSS security context. For context establishment to
 * suceed, the GSS-API implementation from the specified Provider must
 * support the mechanism that the client requests. This server is aware of
 * two different Providers of GSS-API and it attempts to try
 * context establishment with whichever one of the two supports the
 * required mechanism.
 */

// Note: Copyright statement at bottom of file.

public class SimpleServer {

    private String serviceName;

    // Two sets of credentials, one from each GSS-API implementation
    private GSSCredentialInt serverCred1 = null;
    private GSSCredentialInt serverCred2 = null;

    // Two providers to obatain two GSS-API implementations
    private Provider provider1;
    private Provider provider2;

    private int port;
    private ServerSocket serverSock = null;

    /**
     * Constructor for SimpleServer that simply stores the arguments passed
     * to private data for use later on.
     */
    public SimpleServer(String serviceName, int port){
	this.serviceName = serviceName;
	this.port = port;
    }

    /**
     * This method performs the infinite loop where the SimpleServer 
     * accepts connections from different clients, establishes security
     * contexts with them and provides them with some service.
     */
    private void loop() throws IOException, GSSException {

	serverSock = new ServerSocket(port);

	initializeGSS();

	// Loop infinitely
	while (true) {

	    Socket s = serverSock.accept();

	    // Start a new thread to serve this connection
	    Thread serverThread = new ServerThread(s);
	    serverThread.start();

	}
    }

    /**
     * Acquire credentials for the server. Does this using the new
     * interfaces by calling the factory methods in GSSManager with the
     * provider that should be used. Also shows how to do this using the
     * wrapper concrete classes and no interfaces.
     * This routine shows how the application needs to track origins of
     * certain objects when using multiple GSS-API implementations. For
     * example, it has to be careful not to pass name1 which is obtained
     * from implementation #1 to serverCred2 which is obtained from
     * implementation #2.
     */
    private void initializeGSS() throws GSSException {

	// This application is aware of two providers of GSS-API. One is
	// identified by the name ORG.XXX.YYY and the other is identified
	// by the name COM.QQQ. With the help of the class
	// java.security.Security, the application can obtain references to
	// both of these providers.

	provider1 = Security.getProvider("ORG.XXX.YYY");
	provider2 = Security.getProvider("COM.QQQ");

	// If either provider was not found, then quit.
	if (provider1 == null || provider2 == null)
	    throw new GSSException(GSSException.FAILURE,
				   "Could not find GSS-Providers.");

	GSSNameInt name1 = GSSManager.getName(provider1);
	name1.init(serviceName,	GSSNameInt.NT_HOSTBASED_SERVICE);
 
	serverCred1 = GSSManager.getCredential(provider1);
	serverCred1.init(name1 /* server principal*/, 
			 GSSCredentialInt.INDEFINITE /* max lifetime */,
			 null /* default mechanism set */,
			 GSSCredentialInt.ACCEPT_ONLY /*accept sec context*/);
	
    	GSSNameInt name2 = GSSManager.getName(provider2);
    	name2.init(serviceName,	GSSNameInt.NT_HOSTBASED_SERVICE);
    
    	serverCred2 = GSSManager.getCredential(provider2);
    	serverCred2.init(name2
    			 GSSCredentialInt.INDEFINITE,
    			 null,
    			 GSSCredentialInt.ACCEPT_ONLY);

	// Alternate coding style to avoid using interfaces altogether:
	//
	// GSSManager.setDefaultProvider(provider1);
	// name1 =  new GSSName(serviceName, GSSName.NT_HOSTBASED_SERVICE);
	// serverCred1 = new GSSCredential(name1, 
	//                                GSSCredential.INDEFINITE, 
	//                                null, 
	//                                GSSCredential.ACCEPT_ONLY);
	//
	// GSSManager.setDefaultProvider(provider2);
	// name2 =  new GSSName(serviceName, GSSName.NT_HOSTBASED_SERVICE);
	// serverCred2 = new GSSCredential(name2, 
	//                                GSSCredential.INDEFINITE, 
	//                                null, 
	//                                GSSCredential.ACCEPT_ONLY);

	logGSSInitResults(serverCred1, serverCred2);

    }

    /**
     * Inner class ServerThread whose run() method provides the secure
     * service to a connection. run() gets called by the JVM automatically
     * when Thread.start() is invoked in serverLoop().
     */

    private class ServerThread extends Thread {

	Socket sock;

	// MyNetworkIOHelper is a utility class containing routines to help
	// with the network I/O.
	MyNetworkIOHelper nw;

	public ServerThread(Socket s) {
	    sock = s;
	}

	/**
	 * Deals with the connection from one client. It also handles all
	 * IOException's and GSSException's thrown while talking to this
	 * client.
	 */
	public void run() {

	    byte[] inToken = null;
	    byte[] outToken = null;
	    byte[] buffer;

	    GSSNameInt peer;

	    // Container for multiple input-output arguments to and from the
	    // per-message routines (ie. wrap/unwrap).
	    MessageProp messgInfo = new MessageProp();

	    GSSContextInt secContext = null;

	    try {

		// MyNetworkIOHelper is a utility class containing routines
		// to help with the network I/O.
		nw = new MyNetworkIOHelper(sock);

		// Try both GSS implementations to see which one has
		// the required mechanism

		secContext = tryAllImplementations();

		// SimpleServer wants confidentiality to be available. Check
		// for it.
		if (!secContext.getConfState()){
		    return; // Will go via the finally block that performs
		    // the clean up.
		}

		logContextAcceptResults(secContext);

		peer = secContext.getSrcName();

		//Now read the bytes sent by the client to be processed.
		inToken = nw.readGSSToken();

		// Unwrap the message
		buffer = secContext.unwrap(inToken, 0, inToken.length,
					  messgInfo);
		// All ok if no exception was thrown!

		logUnwrapResults(peer, messgInfo);

		/*
		 * Now process the bytes and send back an encrypted
		 * response.
		 */

		buffer = process(buffer); // whatever the server does

		messgInfo.setPrivacy(true);
		outToken = secContext.wrap(buffer, 0, buffer.length,
					   messgInfo);
		nw.writeGSSToken(outToken);

	    } catch (GSSException e) {
		print("GSS-API Error: " + e.getMessage());
		// Alternatively, could call e.getMajorMessage() and
		// e.getMinorMessage()
		print("Abandoning security context.");

	    } catch (IOException e) {
		print("Network Error: " + e.getMessage());

	    } finally {
		// Always executed

		try {
		    // Cleanup can throw exception too. Ignore.

		if (secContext != null)
		    secContext.dispose(); // delete the security context

		sock.close();

		} catch (GSSException e) {
		} catch (IOException e) {
		}

	    }
	} // end of run method in ServerThread

	/**
	 * Tries to establish a GSSContext with all GSS-API
	 * implementatins that this application knows about. Returns
	 * the first GSSContext that succeeds.
	 */
	GSSContextInt tryAllImplementations()
	    throws GSSException, IOException {
	    
	    GSSContextInt context = null;
	    byte[] inToken;
	    byte[] outToken;
	    
	    // Obtain the first context establishment GSS token
	    inToken = nw.readGSSToken();
	    
	    // Now try context establishment with the first GSS-API
	    // implementation. It will throw a GSSException with major
	    // code BAD_MECH after consuming the first GSS Token if this
	    // implementation does not support the requested mechanism.
	    
	    try {
		
		// The following two lines are equivalent to the
		// GSSContext constructor. Since context here is obtained
		// from provider1, pass in serverCred1.

		context = GSSManager.getContext(provider1);
		context.init(serverCred1);
		
		// The context establishment loop
		while (!context.isEstablished()) {

		    // Throws BAD_MECH GSSException here if this
		    // implementation does not support the requested mech.
		    outToken = context.acceptSecContext(inToken, 0,
							inToken.length);

		    if (outToken != null)
			nw.writeGSSToken(outToken);
		    
		if (!context.isEstablished())
		    inToken = nw.readGSSToken();
		}
		
		// This context is established. Return to caller.
		return context;
		
	    } catch (GSSException e) {
		// If this was because the mechanism was not found then
		// proceed to try the next implementation, else throw the
		// exception back and let the caller handle it.
		if (e.getMajor() != GSSException.BAD_MECH)
		    throw e; // exits tryAllImplementations
		
	    } // end of catch
	    
	    // Now try the second implementation and let any sort of
	    // GSSException trickle back up to the caller since there is
	    // nothing more we can do here.
	    
	    // The following two lines are equivalent to the
	    // GSSContext constructor. Since context here is obtained
	    // from provider2, pass in serverCred2.

	    context = GSSManager.getContext(provider2);
	    context.init(serverCred2);
	    
	    // The context establishment loop
	    while (!context.isEstablished()) {
		
		// Throws BAD_MECH GSSException here if this
		// implementation does not support the requested mech.
		outToken = context.acceptSecContext(inToken, 0, 
						    inToken.length);
		
		if (outToken != null)
		    nw.writeGSSToken(outToken);
		
		if (!context.isEstablished())
		    inToken = nw.readGSSToken();
	    }

	    // This context is established. Return to caller.
	    return context;

	}
    } // end of inner class ServerThread

    /**
     * Obtain information using the Java equivalent of the
     * GSS_Inquire_cred() call and log it. This is called right after the
     * credentials are acquired.
     */
    private static void logGSSInitResults(GSSCredentialInt cred1,
					  GSSCredentialInt cred2)
	throws GSSException {

	Oid[] availMechs;
	Provider p;

	print("GSSCredential created for " + cred1.getGSSName());

	print("Mechanisms available to SimpleServer are:");

	availMechs = cred1.getMechs();
	p = cred1.getProvider();

	print("Provider: " + p.getName());
	for (int i=0; i < availMechs.length; i++) 
	    print(availMechs[i].toString());

	availMechs = cred2.getMechs();
	p = cred2.getProvider();
	
	print("Provider: " + p.getName());
	for (int i=0; i < availMechs.length; i++) 
	    print(availMechs[i].toString());

    }

    /**
     * Obtain information about the security context using the Java
     * equivalent of the GSS_Inquire_context() call and log it. This is
     * called after the security context has been established.
     */
    private static void logContextAcceptResults(GSSContextInt context)
	throws GSSException {

	GSSNameInt peer = context.getSrcName();
	Oid mech = context.getMech();
	print("Security context established with " + peer.toString() + 
	      " using underlying mechanism " + mech.toString() +
	      " from Provider " + context.getProvider().getName());
    }

    /**
     * Log information about the last unwrap call using the MessageProp
     * object that the call filled in.
     */
    private static void logUnwrapResults(GSSNameInt peer,
					 MessageProp messgInfo) {

	print("Message from "       + peer.toString() + " arrived.");
	print("Was it encrypted? "  + messgInfo.getPrivacy());
	print("Duplicate Token? "   + messgInfo.isDuplicateToken());
	print("Old Token? "         + messgInfo.isOldToken());
	print("Unsequenced Token? " + messgInfo.isUnseqToken());
	print("Gap Token? "         + messgInfo.isGapToken());

    }

    private static void printUsage() {
	print("Usage: java SimpleServer <service_name> <port>");
    }

    private static void print(String message) {
	System.out.println(message);
    }

    /**
     * The main method for this class. The usage is as follows:
     * "java SimpleServer <service_name> <port>"
     */
    public static final void main(String args[])
	throws GSSException, IOException{

	SimpleServer server = null;

	if (args.length <  2) {
	    printUsage();
	    System.exit(1);
	}

	try {

	    String myServiceName = args[0];
	    int port = Integer.parseInt(args[1]);

	    server = new SimpleServer(myServiceName, port);

	    // Loop indefinitely and serve requests
	    server.loop();

	} catch (GSSException e) {
	    print("GSS-API Error: " + e.getMessage());

	} catch (IOException e) {
	    print("Network Error: " + e.getMessage());

	} catch (NumberFormatException e) {
	    // Could not parse port
	    printUsage();

	} finally {
	    // Always executed

	    if (server != null) {

		if (server.serverCred1 != null)
		    server.serverCred1.dispose(); // destroy credentials
		
		if (server.serverCred2 != null)
		    server.serverCred2.dispose(); // destroy credentials
		
		if (server.serverSock != null)
		    server.serverSock.close();
	    }
	}

    } // end of main()

} // end of class SimpleServer

/*

Full Copyright Statement

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

*/