8. Sample Applications
8.1. Simple GSS Context Initiator
<CODE BEGINS> 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 RFC 8353. * * * 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 " + clientCred.getName().toString()); print("Credential lifetime (sec)=" + clientCred.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, clientCred, 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(); } peer = context.getTargName();
print("Security context established with " + peer + " using underlying mechanism " + mech.toString()); } catch (GSSException e) { print("GSS-API error during context establishment: " + e.getMessage()); // If the exception contains an output token, // it should be sent to the acceptor. byte[] outTok = e.getOutputToken(); if (outTok != null) { writeGSSToken(outTok); } ... ... } ... ... } /** * 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(true); 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.getTargName(); 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 <CODE ENDS>
8.2. Simple GSS Context Acceptor
<CODE BEGINS> 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() throws Exception { ... ... mgr = GSSManager.getInstance(); name = mgr.createName(serviceName, GSSName.NT_HOSTBASED_SERVICE); cred = mgr.createCredential(name, GSSCredential.INDEFINITE_LIFETIME, (Oid[])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; // Container for multiple input-output arguments to // and from the per-message routines // (i.e., wrap/unwrap). MessageProp supplInfo = new MessageProp(true); 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()); // 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() // If the exception contains an output token, // it should be sent to the initiator. byte[] outTok = e.getOutputToken(); if (outTok != null) { writeGSSToken(outTok); } print("Abandoning security context."); ... ... } ... ... } // end of run method in ServerThread } // end of inner class ServerThread ... ... } // end of class SimpleServer <CODE ENDS>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) 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) 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. IANA Considerations
This document has no IANA actions.11. Changes since RFC 5653
This document has following changes: 1) New error token embedded in GSSException There is a design flaw in the initSecContext and acceptSecContext methods of the GSSContext class defined in "Generic Security Service API Version 2: Java Bindings Update" [RFC5653]. The methods could either return a token (possibly null if no more tokens are needed) when the call succeeds or throw a GSSException if there is a failure, but NOT both. On the other hand, the C-bindings of GSS-API [RFC2744] can return both; that is to say, a
call to the GSS_Init_sec_context() function can return a major status code, and at the same time, fill in the output_token argument if there is one. Without the ability to emit an error token when there is a failure, a Java application has no mechanism to tell the other side what the error is. For example, a "reject" NegTokenResp token can never be transmitted for the SPNEGO mechanism [RFC4178]. While a Java method can never return a value and throw an exception at the same time, we can embed the error token inside the exception so that the caller has a chance to retrieve it. This update adds a new GSSException constructor to include this token inside a GSSException object and a getOutputToken() method to retrieve the token. The specification for the initSecContext and acceptSecContext methods are updated to describe the new behavior. Various examples are also updated. New JGSS programs SHOULD make use of this new feature, but it is not mandatory. A program that intends to run with both old and new GSS Java bindings can use reflection to check the availability of this new method and call it accordingly. 2) Removing Stream-Based GSSContext Methods The overloaded methods of GSSContext that use input and output streams as the means to convey authentication and per-message GSS-API tokens as described in Section 5.15 of RFC 5653 [RFC5653] are removed in this update as the wire protocol should be defined by an application and not a library. It's also impossible to implement these methods correctly when the token has no self- framing (where the end cannot be determined), or the library has no knowledge of the token format (for example, as a bridge talking to another GSS library). These methods include initSecContext (Section 7.4.5 of RFC 5653 [RFC5653]), acceptSecContext (Section 7.4.9 of RFC 5653 [RFC5653]), wrap (Section 7.4.15 of RFC 5653 [RFC5653]), unwrap (Section 7.4.17 of RFC 5653 [RFC5653]), getMIC (Section 7.4.19 of RFC 5653 [RFC5653]), and verifyMIC (Section 7.4.21 of RFC 5653 [RFC5653]).
12. Changes since RFC 2853
This document has the 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 it 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.1. 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.1 to be consistent with the C-bindings in RFC 2744 [RFC2744].
13. References
13.1. Normative References
[RFC2025] Adams, C., "The Simple Public-Key GSS-API Mechanism (SPKM)", RFC 2025, DOI 10.17487/RFC2025, October 1996, <https://www.rfc-editor.org/info/rfc2025>. [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>. [RFC2743] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, DOI 10.17487/RFC2743, January 2000, <https://www.rfc-editor.org/info/rfc2743>. [RFC2744] Wray, J., "Generic Security Service API Version 2 : C-bindings", RFC 2744, DOI 10.17487/RFC2744, January 2000, <https://www.rfc-editor.org/info/rfc2744>. [RFC2853] Kabat, J. and M. Upadhyay, "Generic Security Service API Version 2 : Java Bindings", RFC 2853, DOI 10.17487/RFC2853, June 2000, <https://www.rfc-editor.org/info/rfc2853>. [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, DOI 10.17487/RFC4121, July 2005, <https://www.rfc-editor.org/info/rfc4121>. [RFC4178] Zhu, L., Leach, P., Jaganathan, K., and W. Ingersoll, "The Simple and Protected Generic Security Service Application Program Interface (GSS-API) Negotiation Mechanism", RFC 4178, DOI 10.17487/RFC4178, October 2005, <https://www.rfc-editor.org/info/rfc4178>. [RFC5653] Upadhyay, M. and S. Malkani, "Generic Security Service API Version 2: Java Bindings Update", RFC 5653, DOI 10.17487/RFC5653, August 2009, <https://www.rfc-editor.org/info/rfc5653>. [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.
13.2. Informative References
[ISOIEC-8824] International Organization for Standardization, "Information technology -- Abstract Syntax Notation One (ASN.1): Specification of basic notation", ISO/ IEC 8824-1:2014, November 2015, <https://www.iso.org/standard/68350.html>. [ISOIEC-8825] International Organization for Standardization, "Information technology -- ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)", ISO/IEC 8825-1:2015, November 2015, <https://www.iso.org/standard/68345.html>. [JLS] Gosling, J., Joy, B., Steele, G., Bracha, G., Buckley, A., and D. Smith, "The Java Language Specification", Java SE 10 Edition, February 2018, <https://docs.oracle.com/javase/specs/jls/se10/html/ index.html>.
Acknowledgments
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 Greg Hudson, Benjamin Kaduk, Joe Salowey and Michael Smith for many insightful ideas and suggestions that have contributed to this document.Authors' Addresses
Mayank D. Upadhyay Google Inc. 1600 Amphitheatre Parkway Mountain View, CA 94043 United States of America Email: m.d.upadhyay+ietf@gmail.com Seema Malkani ActivIdentity Corp. 6623 Dumbarton Circle Fremont, California 94555 United States of America Email: Seema.Malkani@gmail.com Weijun Wang Oracle Building No. 24, Zhongguancun Software Park Beijing 100193 China Email: weijun.wang@oracle.com