7.5. public class MessageProp
This is a utility class used within the per-message GSSContext methods to convey per-message properties. When used with the GSSContext interface's wrap and getMIC methods, an instance of this class is used to indicate the desired QOP and to request if confidentiality services are to be applied to caller supplied data (wrap only). To request default QOP, the value of 0 should be used for QOP. When used with the unwrap and verifyMIC methods of the GSSContext interface, an instance of this class will be used to indicate the applied QOP and confidentiality services over the supplied message. In the case of verifyMIC, the confidentiality state will always be "false". Upon return from these methods, this object will also contain any supplementary status values applicable to the processed token. The supplementary status values can indicate old tokens, out of sequence tokens, gap tokens, or duplicate tokens.
7.5.1. Constructors
public MessageProp(boolean privState) Constructor that sets QOP to 0 indicating that the default QOP is requested. Parameters: privState: The desired privacy state. "true" for privacy and "false" for integrity only. public MessageProp(int qop, boolean privState) Constructor that sets the values for the qop and privacy state. Parameters: qop: The desired QOP. Use 0 to request a default QOP. privState: The desired privacy state. "true" for privacy and "false" for integrity only.7.5.2. getQOP
public int getQOP() Retrieves the QOP value.7.5.3. getPrivacy
public boolean getPrivacy() Retrieves the privacy state.7.5.4. getMinorStatus
public int getMinorStatus() Retrieves the minor status that the underlying mechanism might have set.7.5.5. getMinorString
public String getMinorString() Returns a string explaining the mechanism-specific error code. "null" will be returned when no mechanism error code has been set.
7.5.6. setQOP
public void setQOP(int qopVal) Sets the QOP value. Parameters: qopVal: The QOP value to be set. Use 0 to request a default QOP value.7.5.7. setPrivacy
public void setPrivacy(boolean privState) Sets the privacy state. Parameters: privState: The privacy state to set.7.5.8. isDuplicateToken
public boolean isDuplicateToken() Returns "true" if this is a duplicate of an earlier token.7.5.9. isOldToken
public boolean isOldToken() Returns "true" if the token's validity period has expired.7.5.10. isUnseqToken
public boolean isUnseqToken() Returns "true" if a later token has already been processed.7.5.11. isGapToken
public boolean isGapToken() Returns "true" if an expected per-message token was not received.
7.5.12. setSupplementaryStates
public void setSupplementaryStates(boolean duplicate, boolean old, boolean unseq, boolean gap, int minorStatus, String minorString) This method sets the state for the supplementary information flags and the minor status in MessageProp. It is not used by the application but by the GSS implementation to return this information to the caller of a per-message context method. Parameters: duplicate: "true" if the token was a duplicate of an earlier token; otherwise, "false". old: "true" if the token's validity period has expired; otherwise, "false". unseq: "true" if a later token has already been processed; otherwise, "false". gap: "true" if one or more predecessor tokens have not yet been successfully processed; otherwise, "false". minorStatus: The integer minor status code that the underlying mechanism wants to set. minorString: The textual representation of the minorStatus value.7.6. public class ChannelBinding
The GSS-API accommodates the concept of caller-provided channel binding information. Channel bindings are used to strengthen the quality with which peer entity authentication is provided during context establishment. They enable the GSS-API callers to bind the establishment of the security context to relevant characteristics like addresses or to application-specific data. The caller initiating the security context must determine the appropriate channel binding values to set in the GSSContext object. The acceptor must provide an identical binding in order to validate that received tokens possess correct channel-related characteristics. Use of channel bindings is optional in GSS-API. Since channel- binding information may be transmitted in context establishment tokens, applications should therefore not use confidential data as channel-binding components.
7.6.1. Constructors
public ChannelBinding(InetAddress initAddr, InetAddress acceptAddr, byte[] appData) Create a ChannelBinding object with user-supplied address information and data. "null" values can be used for any fields that the application does not want to specify. Parameters: initAddr: The address of the context initiator. "null" value can be supplied to indicate that the application does not want to set this value. acceptAddr: The address of the context acceptor. "null" value can be supplied to indicate that the application does not want to set this value. appData: Application-supplied data to be used as part of the channel bindings. "null" value can be supplied to indicate that the application does not want to set this value. public ChannelBinding(byte[] appData) Creates a ChannelBinding object without any addressing information. Parameters: appData: Application supplied data to be used as part of the channel bindings.7.6.2. getInitiatorAddress
public InetAddress getInitiatorAddress() Returns the initiator's address for this channel binding. "null" is returned if the address has not been set.7.6.3. getAcceptorAddress
public InetAddress getAcceptorAddress() Returns the acceptor's address for this channel binding. "null" is returned if the address has not been set.
7.6.4. getApplicationData
public byte[] getApplicationData() Returns application data being used as part of the ChannelBinding. "null" is returned if no application data has been specified for the channel binding.7.6.5. equals
public boolean equals(Object obj) Returns "true" if two channel bindings match. (Note that the Java language specification requires that two objects that are equal according to the equals(Object) method must return the same integer result when the hashCode() method is called on them.) Parameters: obj: Another channel binding with which to compare.7.7. public class Oid
This class represents Universal Object Identifiers (Oids) and their associated operations. Oids are hierarchically globally interpretable identifiers used within the GSS-API framework to identify mechanisms and name formats. The structure and encoding of Oids is defined in ISOIEC-8824 and ISOIEC-8825. For example, the Oid representation of the Kerberos v5 mechanism is "1.2.840.113554.1.2.2". The GSSName name class contains public static Oid objects representing the standard name types defined in GSS-API.7.7.1. Constructors
public Oid(String strOid) throws GSSException Creates an Oid object from a string representation of its integer components (e.g., "1.2.840.113554.1.2.2"). Parameters: strOid: The string representation for the oid. public Oid(InputStream derOid) throws GSSException
Creates an Oid object from its DER encoding. This refers to the full encoding including tag and length. The structure and encoding of Oids is defined in ISOIEC-8824 and ISOIEC-8825. This method is identical in functionality to its byte array counterpart. Parameters: derOid: Stream containing the DER-encoded oid. public Oid(byte[] DEROid) throws GSSException Creates an Oid object from its DER encoding. This refers to the full encoding including tag and length. The structure and encoding of Oids is defined in ISOIEC-8824 and ISOIEC-8825. This method is identical in functionality to its byte array counterpart. Parameters: derOid: Byte array storing a DER-encoded oid.7.7.2. toString
public String toString() Returns a string representation of the oid's integer components in dot separated notation (e.g., "1.2.840.113554.1.2.2").7.7.3. equals
public boolean equals(Object Obj) Returns "true" if the two Oid objects represent the same oid value. (Note that the Java language specification [JLS] requires that two objects that are equal according to the equals(Object) method must return the same integer result when the hashCode() method is called on them.) Parameters: obj: Another Oid object with which to compare.7.7.4. getDER
public byte[] getDER() Returns the full ASN.1 DER encoding for this oid object, which includes the tag and length.
7.7.5. containedIn
public boolean containedIn(Oid[] oids) A utility method to test if an Oid object is contained within the supplied Oid object array. Parameters: oids: An array of oids to search.7.8. public class GSSException extends Exception
This exception is thrown whenever a fatal GSS-API error occurs including mechanism-specific errors. It may contain both, the major and minor, GSS-API status codes. The mechanism implementors are responsible for setting appropriate minor status codes when throwing this exception. Aside from delivering the numeric error code(s) to the caller, this class performs the mapping from their numeric values to textual representations. All Java GSS-API methods are declared throwing this exception. All implementations are encouraged to use the Java internationalization techniques to provide local translations of the message strings.7.8.1. Static Constants
All valid major GSS-API error code values are declared as constants in this class. public static final int BAD_BINDINGS Channel bindings mismatch error. The value of this constant is 1. public static final int BAD_MECH Unsupported mechanism requested error. The value of this constant is 2. public static final int BAD_NAME Invalid name provided error. The value of this constant is 3. public static final int BAD_NAMETYPE Name of unsupported type provided error. The value of this constant is 4.
public static final int BAD_STATUS Invalid status code error - this is the default status value. The value of this constant is 5. public static final int BAD_MIC Token had invalid integrity check error. The value of this constant is 6. public static final int CONTEXT_EXPIRED Specified security context expired error. The value of this constant is 7. public static final int CREDENTIALS_EXPIRED Expired credentials detected error. The value of this constant is 8. public static final int DEFECTIVE_CREDENTIAL Defective credential error. The value of this constant is 9. public static final int DEFECTIVE_TOKEN Defective token error. The value of this constant is 10. public static final int FAILURE General failure, unspecified at GSS-API level. The value of this constant is 11. public static final int NO_CONTEXT Invalid security context error. The value of this constant is 12. public static final int NO_CRED Invalid credentials error. The value of this constant is 13. public static final int BAD_QOP Unsupported QOP value error. The value of this constant is 14. public static final int UNAUTHORIZED Operation unauthorized error. The value of this constant is 15.
public static final int UNAVAILABLE Operation unavailable error. The value of this constant is 16. public static final int DUPLICATE_ELEMENT Duplicate credential element requested error. The value of this constant is 17. public static final int NAME_NOT_MN Name contains multi-mechanism elements error. The value of this constant is 18. public static final int DUPLICATE_TOKEN The token was a duplicate of an earlier token. This is contained in an exception only when detected during context establishment, in which case it is considered a fatal error. (Non-fatal supplementary codes are indicated via the MessageProp object.) The value of this constant is 19. public static final int OLD_TOKEN The token's validity period has expired. This is contained in an exception only when detected during context establishment, in which case it is considered a fatal error. (Non-fatal supplementary codes are indicated via the MessageProp object.) The value of this constant is 20. public static final int UNSEQ_TOKEN A later token has already been processed. This is contained in an exception only when detected during context establishment, in which case it is considered a fatal error. (Non-fatal supplementary codes are indicated via the MessageProp object.) The value of this constant is 21. public static final int GAP_TOKEN An expected per-message token was not received. This is contained in an exception only when detected during context establishment, in which case it is considered a fatal error. (Non-fatal supplementary codes are indicated via the MessageProp object.) The value of this constant is 22.
7.8.2. Constructors
public GSSException(int majorCode) Creates a GSSException object with a specified major code. Parameters: majorCode: The GSS error code causing this exception to be thrown. public GSSException(int majorCode, int minorCode, String minorString) Creates a GSSException object with the specified major code, minor code, and minor code textual explanation. This constructor is to be used when the exception is originating from the security mechanism. It allows to specify the GSS code and the mechanism code. Parameters: majorCode: The GSS error code causing this exception to be thrown. minorCode: The mechanism error code causing this exception to be thrown. minorString: The textual explanation of the mechanism error code.7.8.3. getMajor
public int getMajor() Returns the major code representing the GSS error code that caused this exception to be thrown.7.8.4. getMinor
public int getMinor() Returns the mechanism error code that caused this exception. The minor code is set by the underlying mechanism. Value of 0 indicates that mechanism error code is not set.
7.8.5. getMajorString
public String getMajorString() Returns a string explaining the GSS major error code causing this exception to be thrown.7.8.6. getMinorString
public String getMinorString() Returns a string explaining the mechanism-specific error code. "null" will be returned when no mechanism error code has been set.7.8.7. setMinor
public void setMinor(int minorCode, String message) Used internally by the GSS-API implementation and the underlying mechanisms to set the minor code and its textual representation. Parameters: minorCode: The mechanism-specific error code. message: A textual explanation of the mechanism error code.7.8.8. toString
public String toString() Returns a textual representation of both the major and minor status codes.7.8.9. getMessage
public String getMessage() Returns a detailed message of this exception. Overrides Throwable.getMessage. It is customary in Java to use this method to obtain exception information.
8. Sample Applications
8.1. Simple GSS Context Initiator
import org.ietf.jgss.*; /** * This is a partial sketch for a simple client program that acts * as a GSS context initiator. It illustrates how to use the Java * bindings for the GSS-API specified in * Generic Security Service API Version 2 : Java bindings * * * This code sketch assumes the existence of a GSS-API * implementation that supports the mechanism that it will need * and is present as a library package (org.ietf.jgss) either as * part of the standard JRE or in the CLASSPATH the application * specifies. */ public class SimpleClient { private String serviceName; // name of peer (i.e., server) private GSSCredential clientCred = null; private GSSContext context = null; private Oid mech; // underlying mechanism to use private GSSManager mgr = GSSManager.getInstance(); ... ... private void clientActions() { initializeGSS(); establishContext(); doCommunication(); } /** * Acquire credentials for the client. */ private void initializeGSS() { try { clientCred = mgr.createCredential(null /*default princ*/, GSSCredential.INDEFINITE_LIFETIME /* max lifetime */, mech /* mechanism to use */,
GSSCredential.INITIATE_ONLY /* init context */); print("GSSCredential created for " + cred.getName().toString()); print("Credential lifetime (sec)=" + cred.getRemainingLifetime()); } catch (GSSException e) { print("GSS-API error in credential acquisition: " + e.getMessage()); ... ... } ... ... } /** * Does the security context establishment with the * server. */ private void establishContext() { byte[] inToken = new byte[0]; byte[] outToken = null; try { GSSName peer = mgr.createName(serviceName, GSSName.NT_HOSTBASED_SERVICE); context = mgr.createContext(peer, mech, gssCred, GSSContext.INDEFINITE_LIFETIME/*lifetime*/); // Will need to support confidentiality context.requestConf(true); while (!context.isEstablished()) { outToken = context.initSecContext(inToken, 0, inToken.length); if (outToken != null) writeGSSToken(outToken); if (!context.isEstablished()) inToken = readGSSToken(); }
GSSName peer = context.getSrcName(); print("Security context established with " + peer + " using underlying mechanism " + mech.toString()); } catch (GSSException e) { print("GSS-API error during context establishment: " + e.getMessage()); ... ... } ... ... } /** * Sends some data to the server and reads back the * response. */ private void doCommunication() { byte[] inToken = null; byte[] outToken = null; byte[] buffer; // Container for multiple input-output arguments to and // from the per-message routines (e.g., wrap/unwrap). MessageProp messgInfo = new MessageProp(); try { /* * 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 = context.wrap(buffer, 0, buffer.length, messgInfo); writeGSSToken(outToken); /* * Now read the response from the server. */
inToken = readGSSToken(); buffer = context.unwrap(inToken, 0, inToken.length, messgInfo); // All ok if no exception was thrown! GSSName peer = context.getSrcName(); 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()); ... ... } catch (GSSException e) { print("GSS-API error in per-message calls: " + e.getMessage()); ... ... } ... ... } // end of doCommunication method ... ... } // end of class SimpleClient
8.2. Simple GSS Context Acceptor
import org.ietf.jgss.*; /** * This is a partial sketch for a simple server program that acts * as a GSS context acceptor. It illustrates how to use the Java * bindings for the GSS-API specified in * Generic Security Service API Version 2 : Java bindings. * * This code sketch assumes the existence of a GSS-API * implementation that supports the mechanisms that it will need * and is present as a library package (org.ietf.jgss) either as * part of the standard JRE or in the CLASSPATH the application * specifies. */ import org.ietf.jgss.*; public class SimpleServer { private String serviceName; private GSSName name; private GSSCredential cred; private GSSManager mgr; ... ... /** * Wait for client connections, establish security contexts * and provide service. */ private void loop() { ... ... mgr = GSSManager.getInstance(); name = mgr.createName(serviceName, GSSName.NT_HOSTBASED_SERVICE); cred = mgr.createCredential(name, GSSCredential.INDEFINITE_LIFETIME, null, GSSCredential.ACCEPT_ONLY);
// Loop infinitely while (true) { Socket s = serverSock.accept(); // Start a new thread to serve this connection Thread serverThread = new ServerThread(s); serverThread.start(); } } /** * Inner class ServerThread whose run() method provides the * secure service to a connection. */ private class ServerThread extends Thread { ... ... /** * Deals with the connection from one client. It also * handles all GSSException's thrown while talking to * this client. */ public void run() { byte[] inToken = null; byte[] outToken = null; byte[] buffer; GSSName peer; // Container for multiple input-output arguments to // and from the per-message routines // (i.e., wrap/unwrap). MessageProp supplInfo = new MessageProp(); GSSContext secContext = null; try { // Now do the context establishment loop GSSContext context = mgr.createContext(cred);
while (!context.isEstablished()) { inToken = readGSSToken(); outToken = context.acceptSecContext(inToken, 0, inToken.length); if (outToken != null) writeGSSToken(outToken); } // SimpleServer wants confidentiality to be // available. Check for it. if (!context.getConfState()){ ... ... } GSSName peer = context.getSrcName(); Oid mech = context.getMech(); print("Security context established with " + peer.toString() + " using underlying mechanism " + mech.toString() + " from Provider " + context.getProvider().getName()); // Now read the bytes sent by the client to be // processed. inToken = readGSSToken(); // Unwrap the message buffer = context.unwrap(inToken, 0, inToken.length, supplInfo); // All ok if no exception was thrown! // Print other supplementary per-message status // information. print("Message from " + peer.toString() + " arrived."); print("Was it encrypted? " + supplInfo.getPrivacy()); print("Duplicate Token? " + supplInfo.isDuplicateToken()); print("Old Token? " + supplInfo.isOldToken());
print("Unsequenced Token? " + supplInfo.isUnseqToken()); print("Gap Token? " + supplInfo.isGapToken()); /* * Now process the bytes and send back an * encrypted response. */ buffer = serverProcess(buffer); // Encipher it and send it across supplInfo.setPrivacy(true); // privacy requested supplInfo.setQOP(0); // default QOP outToken = context.wrap(buffer, 0, buffer.length, supplInfo); writeGSSToken(outToken); } catch (GSSException e) { print("GSS-API Error: " + e.getMessage()); // Alternatively, could call e.getMajorMessage() // and e.getMinorMessage() print("Abandoning security context."); ... ... } ... ... } // end of run method in ServerThread } // end of inner class ServerThread ... ... } // end of class SimpleServer
9. Security Considerations
The Java language security model allows platform providers to have policy-based fine-grained access control over any resource that an application wants. When using a Java security manager (such as, but not limited to, the case of applets running in browsers) the application code is in a sandbox by default. Administrators of the platform JRE determine what permissions, if any, are to be given to source from different codebases. Thus, the administrator has to be aware of any special requirements that the GSS provider might have for system resources. For instance, a Kerberos provider might wish to make a network connection to the Key Distribution Center (KDC) to obtain initial credentials. This would not be allowed under the sandbox unless the administrator had granted permissions for this. Also, note that this granting and checking of permissions happens transparently to the application and is outside the scope of this document. The Java language allows administrators to pre-configure a list of security service providers in the <JRE>/lib/security/java.security file. At runtime, the system approaches these providers in order of preference when looking for security related services. Applications have a means to modify this list through methods in the "Security" class in the "java.security" package. However, since these modifications would be visible in the entire Java Virtual Machine (JVM) and thus affect all code executing in it, this operation is not available in the sandbox and requires special permissions to perform. Thus, when a GSS application has special needs that are met by a particular security provider, it has two choices: 1) To install the provider on a JVM-wide basis using the java.security.Security class and then depend on the system to find the right provider automatically when the need arises. (This would require the application to be granted a "insertProvider SecurityPermission".) 2) To pass an instance of the provider to the local instance of GSSManager so that only factory calls going through that GSSManager use the desired provider. (This would not require any permissions.)10. Acknowledgments
This proposed API leverages earlier work performed by the IETF's CAT WG as outlined in both RFC 2743 [GSSAPIv2-UPDATE] and RFC 2744 [GSSAPI-Cbind]. Many conceptual definitions, implementation directions, and explanations have been included from these documents.
We would like to thank Mike Eisler, Lin Ling, Ram Marti, Michael Saltz, and other members of Sun's development team for their helpful input, comments, and suggestions. We would also like to thank Joe Salowey, and Michael Smith for many insightful ideas and suggestions that have contributed to this document.11. Changes since RFC 2853
This document has following changes: 1) Major GSS Status Code Constant Values RFC 2853 listed all the GSS status code values in two different sections: section 4.12.1 defined numeric values for them, and section 6.8.1 defined them as static constants in the GSSException class without assigning any values. Due to an inconsistent ordering between these two sections, all of the GSS major status codes resulted in misalignment, and a subsequent disagreement between deployed implementations. This document defines the numeric values of the GSS status codes in both sections, while maintaining the original ordering from section 6.8.1 of RFC 2853 [RFC2853], and obsoletes the GSS status code values defined in section 4.12.1. The relevant sections in this document are sections 5.12.1 and 7.8.1. 2) GSS Credential Usage Constant Values RFC 2853 section 6.3.2 defines static constants for the GSSCredential usage flags. However, the values of these constants were not defined anywhere in RFC 2853 [RFC2853]. This document defines the credential usage values in section 7.3.2. The original ordering of these values from section 6.3.2 of RFC 2853 [RFC2853] is maintained. 3) GSS Host-Based Service Name RFC 2853 [RFC2853], section 6.2.2, defines the static constant for the GSS host-based service OID NT_HOSTBASED_SERVICE, using a deprecated OID value. This document updates the NT_HOSTBASED_SERVICE OID value in section 7.2.2 to be consistent with the C-bindings in RFC 2744 [GSSAPI-Cbind].
12. References
12.1. Normative References
[GSSAPI-Cbind] Wray, J., "Generic Security Service API Version 2 : C-bindings", RFC 2744, January 2000. [GSSAPIv2-UPDATE] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000. [RFC2025] Adams, C., "The Simple Public-Key GSS-API Mechanism (SPKM)", RFC 2025, October 1996. [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. [RFC2853] Kabat, J. and M. Upadhyay, "Generic Security Service API Version 2 : Java Bindings", RFC 2853, June 2000. [RFC4121] Zhu, L., Jaganathan, K., and S. Hartman, "The Kerberos Version 5 Generic Security Service Application Program Interface (GSS-API) Mechanism: Version 2", RFC 4121, July 2005.12.2. Informative References
[JLS] Gosling, J., Joy, B., Steele, G., and G. Bracha "The Java Language Specification", Third Edition, http://java.sun.com/docs/books/jls/.
Authors' Addresses
Mayank D. Upadhyay Google Inc. 1600 Amphitheatre Parkway Mountain View, CA 94043 USA EMail: m.d.upadhyay+ietf@gmail.com Seema Malkani ActivIdentity Corp. 6623 Dumbarton Circle Fremont, California 94555 USA EMail: Seema.Malkani@gmail.com