RFC 2853

Generic Security Service API Version 2 : Java Bindings

๐Ÿ“… published June 2000, from ietf

RFC 2853: Generic Security Service API Version 2 : Java Bindings ๐ŸŽ€

Part 1 of 18 โœจ

Okay so the title block first, bestie ๐Ÿ’– This is RFC 2853, called "Generic Security Service API Version 2 : Java Bindings". It was written by J. Kabat of ValiCert, Inc. and M. Upadhyay of Sun Microsystems, Inc. It's a Standards Track document dated June 2000. The title block doesn't say it obsoletes or updates anything ๐Ÿงš

Status of this Memo ๐ŸŒธ

This is the official vibe check ๐Ÿ’… The doc specifies an Internet standards track protocol for the Internet community, and it's asking for discussion and suggestions for improvements ๐Ÿซถ For the standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited ๐ŸŒˆ

Copyright (C) The Internet Society (2000). All Rights Reserved. โœจ

Abstract ๐Ÿฆ‹

Okay so the GSS-API (the Generic Security Services Application Program Interface) gives app programmers uniform access to security services, even though it sits on top of a bunch of different underlying cryptographic mechanisms ๐Ÿ”ฅ This doc specifies the Java bindings for GSS-API. The language-independent, conceptual version is described in RFC 2743 [GSSAPIv2-UPDATE] ๐Ÿ“

The GSS-API lets a caller application authenticate a principal identity, delegate rights to a peer, and apply security services like confidentiality and integrity on a per-message basis. It's giving main character energy ๐Ÿ‘‘ Examples of security mechanisms defined for GSS-API are The Simple Public-Key GSS-API Mechanism [SPKM] and The Kerberos Version 5 GSS-API Mechanism [KERBV5] ๐Ÿ’–

Table of Contents ๐Ÿงš

Bestie, the text you sent is the Table of Contents again, and we already did that in part 1 ๐Ÿ’…. I don't have the body of RFC 2853 for part 2 yet, so I can't rewrite it without making things up ๐Ÿ™ˆ.

Could you paste the actual section text for part 2, starting where part 1 stopped? Once I have it, I'll keep every MUST, SHOULD, code block, and section number exactly as the original has them โœจ

1. Introduction ๐ŸŽ€

okay so this doc specifies Java language bindings for the Generic Security Services Application Programming Interface Version 2 (GSS-API) ๐Ÿ’–. GSS-API Version 2 is described in a language independent format in RFC 2743 [GSSAPIv2-UPDATE]. The GSS-API lets a caller application authenticate a principal identity, delegate rights to a peer, and apply security services such as confidentiality and integrity on a per-message basis โœจ.

This document leverages the work the WG did in the area of RFC 2743 [GSSAPIv2-UPDATE] and the C-bindings RFC 2744 [GSSAPI-C]. Whenever appropriate, text has been used from the C-bindings RFC 2744 to explain generic concepts and provide direction to the implementors ๐Ÿงš.

The design goals of this API were to satisfy all the functionality defined in RFC 2743 and to provide those services in an object oriented way ๐Ÿฆ‹. The spec also aims to satisfy the needs of both types of Java app developers: the ones who want access to a "system-wide" GSS-API implementation, and the ones who want to provide their own "custom" implementation ๐Ÿ’….

A "system-wide" implementation is one that's available to all applications in the form of a library package ๐Ÿ“š. It may be a standard package in the Java runtime environment (JRE) being used, or it may be additionally installed and accessible to any application via the CLASSPATH.

A "custom" implementation, on the other hand, is one that would, in most cases, be bundled with the application during distribution ๐ŸŽ. It's expected that a custom one would be meant to provide for some particular need of the application, such as support for some specific mechanism.

The design of this API also aims to provide a flexible framework to add and manage GSS-API mechanisms ๐ŸŒธ. GSS-API leverages the Java Cryptography Architecture (JCA) provider model to support the plugability of mechanisms. Mechanisms can be added on a "system-wide" basis, where all users of the framework will have them available. The specification also allows for the addition of mechanisms per-instance of the GSS-API.

Lastly, this specification presents an API that will naturally fit within the operating environment of the Java platform ๐Ÿ‘‘. Readers are assumed to be familiar with both the GSS-API and the Java platform, so no hand-holding here, bestie ๐Ÿ˜˜.

2. GSS-API Operational Paradigm ๐Ÿฆ‹

The Generic Security Service Application Programming Interface Version 2 [GSSAPIv2-UPDATE] defines a generic security API for calling applications. It lets a communicating application authenticate the user associated with another application, delegate rights to another application, and apply security services such as confidentiality and integrity on a per-message basis ๐Ÿ”.

There are four stages to using GSS-API, and they go like this:

  1. The application acquires a set of credentials with which it may prove its identity to other processes. The application's credentials vouch for its global identity, which may or may not be related to any local username under which it may be running ๐Ÿชช.
  2. A pair of communicating applications establish a joint security context using their credentials. The security context encapsulates shared state information, which is required in order that per-message security services may be provided. Examples of state information that might be shared between applications as part of a security context are cryptographic keys, and message sequence numbers ๐Ÿ—๏ธ. As part of the establishment of a security context, the context initiator is authenticated to the responder, and may require that the responder is authenticated back to the initiator. The initiator may optionally give the responder the right to initiate further security contexts, acting as an agent or delegate of the initiator. This transfer of rights is termed "delegation", and it's achieved by creating a set of credentials, similar to those used by the initiating application, but which may be used by the responder ๐Ÿค.

A GSSContext object is used to establish and maintain the shared information that makes up the security context. Certain GSSContext methods will generate a token, which applications treat as cryptographically protected, opaque data. The caller of such a GSSContext method is responsible for transferring the token to the peer application, encapsulated if necessary in an application-to-application protocol. On receipt of such a token, the peer application should pass it to a corresponding GSSContext method, which will decode the token and extract the information, updating the security context state information accordingly ๐Ÿ’Œ.

  1. Per-message services are invoked on a GSSContext object to apply either integrity and data origin authentication, or confidentiality, integrity and data origin authentication, to application data, which are treated by GSS-API as arbitrary octet-strings ๐Ÿ”’. An application transmitting a message that it wishes to protect will call the appropriate GSSContext method (getMIC or wrap) to apply protection, and send the resulting token to the receiving application. The receiver will pass the received token (and, in the case of data protected by getMIC, the accompanying message-data) to the corresponding decoding method of the GSSContext interface (verifyMIC or unwrap) to remove the protection and validate the data โœ….
  2. At the completion of a communications session (which may extend across several transport connections), each application uses a GSSContext method to invalidate the security context and release any system or cryptographic resources held ๐Ÿงน. Multiple contexts may also be used (either successively or simultaneously) within a single communications association, at the discretion of the applications ๐Ÿฆ‹.

3. Additional Controls ๐ŸŒˆ

This section discusses the optional services that a context initiator may request of the GSS-API before the context establishment ๐ŸŽ›๏ธ. Each of these services is requested by calling the appropriate mutator method in the GSSContext object before the first call to init is performed. Only the context initiator can request context flags, so the acceptor is not invited to this party ๐Ÿ™…โ€โ™€๏ธ.

The optional services defined are:

  • Delegation: The (usually temporary) transfer of rights from initiator to acceptor, enabling the acceptor to authenticate itself as an agent of the initiator ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘.
  • Mutual Authentication: In addition to the initiator authenticating its identity to the context acceptor, the context acceptor should also authenticate itself to the initiator ๐Ÿชž.
  • Replay Detection: In addition to providing message integrity services, GSSContext per-message operations of getMIC and wrap should include message numbering information to enable verifyMIC and unwrap to detect if a message has been duplicated ๐Ÿ‘ฏ.
  • Out-of-Sequence Detection: In addition to providing message integrity services, GSSContext per-message operations (getMIC and wrap) should include message sequencing information to enable verifyMIC and unwrap to detect if a message has been received out of sequence ๐Ÿงฉ.
  • Anonymous Authentication: The establishment of the security context should not reveal the initiator's identity to the context acceptor ๐Ÿซฅ.

Some mechanisms may not support all optional services, and some mechanisms may only support some services in conjunction with others ๐Ÿ™ƒ. The GSSContext interface offers query methods that let the calling application verify which services will be available from the context when the establishment phase is complete. In general, if the security mechanism is capable of providing a requested service, it should do so even if additional services must be enabled in order to provide the requested service ๐Ÿ’ซ. If the mechanism is incapable of providing a requested service, it should proceed without the service, leaving the application to abort the context establishment process if it considers the requested service to be mandatory ๐Ÿšฆ.

Some mechanisms may specify that support for some services is optional, and that implementors of the mechanism need not provide it. This is most commonly true of the confidentiality service, often because of legal restrictions on the use of data-encryption, but it may apply to any of the services ๐ŸŒ. Such mechanisms are required to send at least one token from acceptor to initiator during context establishment when the initiator indicates a desire to use such a service, so that the initiating GSS-API can correctly indicate whether the service is supported by the acceptor's GSS-API ๐Ÿ“จ.

3.1. Delegation ๐Ÿ’Œ

The GSS-API allows delegation to be controlled by the initiating application via the requestCredDeleg method before the first call to init has been issued ๐ŸŽ€. Some mechanisms do not support delegation, and for such mechanisms, attempts by an application to enable delegation are ignored ๐Ÿ™ˆ.

The acceptor of a security context, for which the initiator enabled delegation, can check whether delegation was enabled by using the getCredDelegState method of the GSSContext interface. In cases when it is, the delegated credential object can be obtained by calling the getDelegCred method ๐Ÿ”‘. The obtained GSSCredential object may then be used to initiate subsequent GSS-API security contexts as an agent or delegate of the initiator. If the original initiator's identity is "A" and the delegate's identity is "B", then, depending on the underlying mechanism, the identity embodied by the delegated credential may be either "A" or "B acting for A" ๐ŸŽญ.

For many mechanisms that support delegation, a simple boolean does not provide enough control ๐ŸŽš๏ธ. Examples of additional aspects of delegation control that a mechanism might provide to an application are duration of delegation, network addresses from which delegation is valid, and constraints on the tasks that may be performed by a delegate ๐Ÿ—“๏ธ๐Ÿ“๐Ÿงพ. Such controls are presently outside the scope of the GSS-API. GSS-API implementations supporting mechanisms offering additional controls should provide extension routines that allow these controls to be exercised (perhaps by modifying the initiator's GSS-API credential object prior to its use in establishing a context) ๐Ÿ› ๏ธ. However, the simple delegation control provided by GSS-API should always be able to override other mechanism-specific delegation controls. If the application instructs the GSSContext object that delegation is not desired, then the implementation must not permit delegation to occur. This is an exception to the general rule that a mechanism may enable services even if they are not requested: delegation may only be provided at the explicit request of the application ๐Ÿšซ๐Ÿซถ.

3.2. Mutual Authentication โœจ

okay so, usually the context acceptor is gonna demand that the context initiator proves who they are ๐Ÿ” so it can decide if they get access before it does any service for them. sometimes the initiator wants the acceptor to prove itself too, which is giving double verification ๐Ÿ‘€ GSS-API lets the initiating app ask for this by calling the requestMutualAuth method of the GSSContext interface with a "true" parameter, and it has to do that before the first call to init. the initiating app then finds out whether the context acceptor actually authenticated itself ๐Ÿ’–

ngl not every mechanism supports mutual auth, and some mechanisms always do it no matter if the app asked ๐Ÿ™„ for some mechanisms, mutual auth is required to get replay or out-of-sequence message detection working. for those, asking for either of those services will automatically turn on mutual auth ๐Ÿซถ


3.3. Replay and Out-of-Sequence Detection ๐Ÿ”

the GSS-API may be able to detect mis-ordered messages once a security context is established ๐Ÿ‘€ messages can be protected by either app by calling the getMIC or wrap methods of the GSSContext interface, and the peer app verifies them by calling verifyMIC or unwrap on its own GSSContext object ๐Ÿ’…

getMIC works out a cryptographic checksum of an app message and gives that checksum back in a token. the app passes both the token and the message to the peer app, which hands them to verifyMIC on its GSSContext object ๐Ÿฆ‹

wrap is kinda the same vibe, but it puts the checksum and the message together inside one single token ๐ŸŽ€ the app sends that token over, and the peer hands it to unwrap on its GSSContext object, which pulls out the message and checks the checksum ๐Ÿงš

either pair of routines might be able to spot out-of-sequence delivery or duplicated messages โœจ the details about those mis-ordered messages come back through the supplementary query methods of the MessageProp object that each of these routines fills in ๐Ÿ’œ

a mechanism doesn't have to keep a list of every token it has ever processed to report these status codes ๐ŸŒธ a typical mechanism might just remember the most recent "N" tokens it processed, which lets it tell apart duplicates and missing tokens inside those last "N" messages ๐Ÿ“ if a token shows up that's older than the most recent "N", the isOldToken method of that MessageProp instance returns "true" ๐Ÿ’€


3.4. Anonymous Authentication ๐Ÿ•ต๏ธโ€โ™€๏ธ

sometimes an app wants to start authentication so it can check who its peer is, but it doesn't want to reveal its own identity ๐Ÿ™ˆ picture an app that gives access to a database full of medical info and offers unrestricted access to its service ๐Ÿฅ a client might want to verify the service (so it can trust the info it gets back), but it might not want the service to learn who the client is. maybe that's about privacy and the specific questions it asks, or maybe it just doesn't want to end up on mailing lists ๐Ÿ“ญ

normally in GSS-API, the initiator's identity gets handed to the acceptor during context establishment ๐Ÿชช but initiators can ask for their identity to not be revealed to the context acceptor ๐Ÿซฃ lots of mechanisms don't support anonymous auth, and for those the request won't be honored ๐Ÿ˜ฌ an authentication token still gets generated anyway, but the app is always told when a requested service isn't available, and it can choose to abort context establishment if anonymity matters more to it than the other security services that would need a context ๐Ÿ’…

in addition to telling the app that a context was set up anonymously (through the isAnonymous method of the GSSContext class), the getSrcName method of the acceptor's GSSContext object will return a reserved internal-form name for those contexts. that name is defined by the implementation ๐Ÿงš

the toString method of a GSSName object that stands for an anonymous entity will return a printable name โœจ that string has to be syntactically different from any valid principal name the implementation supports ๐Ÿ™Œ the name-type object identifier is an oid representing the value of NT_ANONYMOUS. this name-type oid is defined as a public, static Oid object of the GSSName class ๐Ÿ’– the printable form of an anonymous name should be picked so it implies anonymity, since it might show up in stuff like audit logs ๐Ÿ“ for example, the string "<anonymous>" might be a good pick, as long as no valid printable names the implementation supports can start with "<" and end with ">" ๐ŸŽ€

when you use the equal method of the GSSName interface and one of the operands is a GSSName instance for an anonymous entity, the method must return "false" ๐Ÿšซ


3.5. Confidentiality ๐Ÿ”’

if a GSSContext supports the confidentiality service, the wrap method can be used to encrypt app messages ๐Ÿคซ the encryption is selective, and you control it with the setPrivacy method of the MessageProp object that gets used in the wrap method ๐Ÿ’…


3.6. Inter-process Context Transfer ๐Ÿงšโ€โ™€๏ธ

GSS-API V2 gives you a way to transfer a security context between processes on a single machine ๐Ÿ–ฅ๏ธ this is done with the export method of GSSContext and a byte array constructor of the same class. the most common use is a client-server design where the server is one process that accepts incoming security contexts, then launches child processes to handle the data on those contexts ๐Ÿ‘‘ in that setup, the child processes need access to the security context object that the parent created, so they can use the per-message protection services and delete the security context when the communication session ends ๐Ÿ’œ

the security context data structure is expected to hold sequencing info, so sharing a context between processes is impractical in general ๐Ÿ™ƒ that's why the GSSContext interface has an export method. the process that currently owns the context can call it to say it doesn't plan to use the context anymore, and to make an inter-process token with the info the adopting process needs to re-create the context ๐Ÿฆ‹ after export completes successfully, GSS-API makes the original security context inaccessible to the calling process, and any further use of that object will fail โŒ the originating process hands the inter-process token to the adopting process, which makes a new GSSContext object with the byte array constructor. the properties of the context match the original one ๐ŸŒˆ

the inter-process token might have sensitive data from the original security context in it, including cryptographic keys ๐Ÿ˜ฐ apps that use inter-process tokens to transfer contexts must take appropriate steps to protect those tokens in transit ๐Ÿ”

implementations are not required to support inter-process transfer of security contexts ๐Ÿคทโ€โ™€๏ธ calling the isTransferable method of the GSSContext interface will tell you if the context object is transferable โœ…


3.7. The Use of Incomplete Contexts โณ

some mechanisms might let the per-message services get used before context establishment is finished ๐Ÿ’ซ for example, a mechanism might put enough info in its initial context-level tokens so the context acceptor can decode messages protected with wrap or getMIC right away. for a mechanism like that, the initiating app doesn't need to wait for later context-level tokens to be sent and received before it uses the per-message protection services ๐Ÿƒโ€โ™€๏ธ

an app can call the isProtReady method of the GSSContext class to check if the per-message services are available before the context is fully established ๐Ÿ” apps that want per-message protection on partially established contexts should check this method before they try to call wrap or getMIC ๐Ÿซถ


4. Calling Conventions ๐Ÿ’…

Java gives implementors not just a syntax for the language but a whole operational environment ๐ŸŒท for example, memory is managed automatically and doesn't need app involvement ๐Ÿงน these language features made the API simpler and got rid of certain GSS-API functions ๐Ÿ”ฅ

on top of that, the JCA defines a provider model that gives you implementation-independent access to security services ๐Ÿฆ„ with this model, apps can switch between different implementations and add new services on the fly โœจ the GSS-API spec uses these ideas by relying on providers for the mechanism implementations ๐Ÿ’–

4.1. Package Name ๐Ÿ“ฆ

the classes and interfaces defined in this document live in the package called "org.ietf.jgss". apps that want to use this API should import this package name, as shown in section 7 ๐ŸŽ€

4.2. Provider Framework ๐Ÿงฉ

the Java security APIs use a provider architecture, which lets apps stay implementation independent and lets security API implementations be modular and extensible ๐ŸŒธ the java.security.Provider class is an abstract class that a vendor extends. it maps the various properties that represent the different security services available to the names of the actual vendor classes that implement those services ๐Ÿ“š when an app requests a service, it just names the desired provider, and the API hands the request off to the service classes that provider has ๐Ÿ’œ

using the Java security provider model shields apps from the implementation details of the services they use ๐Ÿ›ก๏ธ apps can switch between providers easily, and new providers can be added as needed, even at runtime ๐Ÿƒโ€โ™€๏ธ

the GSS-API may use providers to find components for specific underlying security mechanisms ๐Ÿ”Ž for instance, one provider might have components that let the GSS-API support the Kerberos v5 mechanism, and another might have components for the SPKM mechanism ๐Ÿ“ by delegating mechanism-specific functionality to components from providers, the GSS-API can be extended to support an arbitrary list of mechanisms ๐ŸŒˆ

how the GSS-API finds and queries these providers is outside the scope of this document, and it's being left to a Service Provider Interface (SPI) specification ๐Ÿ™ an SPI specification isn't mandatory for adopting this API spec, and using providers in a GSS-API framework implementation isn't mandatory either ๐Ÿคทโ€โ™€๏ธ but if you pair the provider framework with an SPI specification, you can build an extensible and implementation-independent GSS-API framework ๐Ÿ‘‘โœจ

4.3. Integer types โœจ

Okay so every number in this API is declared as the Java int primitive type, and bestie, the Java spec literally guarantees it's a 32 bit two's complement signed number ๐Ÿ”ข๐Ÿ’–. And anywhere a true/false value is needed or returned, the boolean primitive type shows up. Simple, clean, iconic.

4.4. Opaque Data types ๐Ÿซถ

Byte arrays (byte[]) are how we represent opaque data types, the stuff GSS-API consumes and produces in the form of tokens ๐Ÿ“ฆ. Java arrays carry their own length field, so you can always tell how big they are without any drama ๐Ÿ“. Plus Java has automatic garbage collection, which means developers don't have to manually release memory, and buffer ownership gets way less messy ๐Ÿงนโœจ.

4.5. Strings ๐ŸŽ€

The String object is used for all textual data, period ๐Ÿ’…. Java's String treats every character as a two-byte Unicode character, which means it can support lots of different locales ๐ŸŒ๐ŸŒˆ. Every routine that returns or accepts text uses the String object, so it's consistent everywhere.

4.6. Object Identifiers ๐Ÿ”ฅ

The Oid object represents Universal Object Identifiers (Oids) ๐Ÿ†”. Oids are ISO-defined, hierarchical, globally-interpretable identifiers, and GSS-API uses them to identify security mechanisms and name formats ๐Ÿ‘‘. You can create an Oid from a string in dot notation, like "1.3.6.1.5.6.2", or from its ASN.1 DER encoding. There are also methods to test equality and to get the DER representation of the object ๐Ÿฆ‹.

Here's the important part, bestie: Oid instances are immutable. There are no methods that let you change what's inside an Oid ๐Ÿ™ˆ. Because of that, you can treat them like "statics" without ever having to make copies ๐Ÿ’œ.

Certain routines let you use a default oid, and in those cases you can pass a "null" value ๐Ÿ“.

4.7. Object Identifier Sets ๐Ÿงš

Object identifier sets are represented as arrays of Oid objects. And since Java arrays have a length field, they're super easy to manipulate and reference ๐Ÿ“š.

To fully support RFC 2743, the Oid class includes a method that checks whether a given Oid exists within a specified array. It works the same way as gss_test_oid_set_member ๐Ÿ”. Java's arrays plus automatic garbage collection mean the following routines aren't needed anymore: gss_create_empty_oid_set, gss_release_oid_set, and gss_add_oid_set_member. So Java GSS-API implementations won't include them ๐Ÿ™Œ. The combo of garbage collection and immutable Oids clears up all the complicated memory management headaches from the C version ๐Ÿ’€โœจ.

Whenever a default value for an Object Identifier Set is needed, you can use a "null" value. Check the detailed method description for the specifics ๐Ÿ’….

4.8. Credentials ๐Ÿ’–

GSS-API credentials are represented by the GSSCredential interface ๐Ÿ”. It has a bunch of constructs that help you create the most common credential objects for both the initiator and the acceptor. You compare credentials with the interface's equals method. Here's the general description of GSS-API credentials, pulled from the C-bindings specification:

GSS-API credentials can contain mechanism-specific principal authentication data for multiple mechanisms. A GSS-API credential is composed of a set of credential-elements, each of which is applicable to a single mechanism. A credential may contain at most one credential-element for each supported mechanism. A credential-element identifies the data needed by a single mechanism to authenticate a single principal, and conceptually contains two credential-references that describe the actual mechanism-specific authentication data, one to be used by GSS-API for initiating contexts, and one to be used for accepting contexts. For mechanisms that do not distinguish between acceptor and initiator credentials, both references would point to the same underlying mechanism-specific authentication data. Credentials describe a set of mechanism-specific principals, and give their holder the ability to act as any of those principals. All principal identities asserted by a single GSS-API credential should belong to the same entity, although enforcement of this property is an implementation-specific matter. A single GSSCredential object represents all the credential elements that have been acquired.

The creation of a GSSContext object lets you pass "null" as the GSSCredential input parameter ๐ŸŒธ. That tells GSS-API the app wants to act as a default principal ๐ŸŽ€. Individual implementations are free to decide what that default behavior looks like for their mechanism, but the following default behavior is recommended for portability ๐Ÿงธ.

For the initiator side of the context:

  1. If there is only a single principal capable of initiating security contexts for the chosen mechanism that the application is authorized to act on behalf of, then that principal shall be used, otherwise
  2. If the platform maintains a concept of a default network-identity for the chosen mechanism, and if the application is authorized to act on behalf of that identity for the purpose of initiating security contexts, then the principal corresponding to that identity shall be used, otherwise
  3. If the platform maintains a concept of a default local identity, and provides a means to map local identities into network-identities for the chosen mechanism, and if the application is authorized to act on behalf of the network-identity image of the default local identity for the purpose of initiating security contexts using the chosen mechanism, then the principal corresponding to that identity shall be used, otherwise
  4. A user-configurable default identity should be used.

And for the acceptor side of the context:

  1. If there is only a single authorized principal identity capable of accepting security contexts for the chosen mechanism, then that principal shall be used, otherwise
  2. If the mechanism can determine the identity of the target principal by examining the context-establishment token processed during the accept method, and if the accepting application is authorized to act as that principal for the purpose of accepting security contexts using the chosen mechanism, then that principal identity shall be used, otherwise
  3. If the mechanism supports context acceptance by any principal, and if mutual authentication was not requested, any principal that the application is authorized to accept security contexts under using the chosen mechanism may be used, otherwise
  4. A user-configurable default identity shall be used.

The whole point of these rules is to let both initiator and acceptor establish security contexts using default behavior whenever possible ๐Ÿซง. Apps that request default behavior are generally more portable across mechanisms and implementations than apps that instantiate a GSSCredential for one specific identity ๐Ÿฆ‹โœจ.

4.9. Contexts ๐ŸŒท

The GSSContext interface represents one end of a GSS-API security context ๐Ÿ”—. It stores the state info for that end of the peer communication, including cryptographic state ๐Ÿ”‘. The initiator and acceptor create the context object in different ways ๐Ÿ™ƒ. Once the context exists, the initiator can set various context options that decide the characteristics of the security context it wants ๐Ÿ› ๏ธ. When every desired characteristic is set, the initiator calls the initSecContext method, which produces a token for the peer's acceptSecContext method to consume ๐ŸŽ. Delivering those authentication tokens between the peer applications is the application's job ๐Ÿ“ฌ.

After context establishment finishes, both the initiator and acceptor can retrieve context attributes using the accessor methods ๐Ÿ”. These reflect the actual attributes of the established context ๐Ÿ’ฏ. At that point, the app can use the context to apply cryptographic services to its data ๐Ÿ”๐Ÿ’….

4.10. Authentication tokens ๐ŸŽŸ๏ธ

A token is a caller-opaque type that GSS-API uses to keep both ends of a GSS-API security context in sync ๐Ÿ”„. It's a cryptographically protected octet-string, generated by the underlying mechanism at one end of the context for use by the peer mechanism at the other end ๐Ÿง. Encapsulating the token within the application protocol (if needed) and transferring it is the peer applications' responsibility ๐Ÿ“ฎ.

Java GSS-API uses byte arrays to represent authentication tokens ๐ŸŒˆ. There are also overloaded methods that let the caller supply input and output streams for reading and writing the token data ๐ŸŒŠ.

4.11. Interprocess tokens ๐Ÿฆ„

Some GSS-API routines transfer data between processes in multi-process programs ๐Ÿงฉ. These routines use a caller-opaque octet-string, generated by GSS-API in one process for use by GSS-API in another process ๐Ÿ”€. The calling application is responsible for transferring these tokens between processes ๐Ÿšš.

GSS-API implementors are encouraged to avoid placing sensitive information within interprocess tokens, or to cryptographically protect them, but many implementations will be unable to avoid placing key material or other sensitive data within them. It is the application's responsibility to ensure that interprocess tokens are protected in transit, and transferred only to processes that are trustworthy.

An interprocess token is represented as a byte array emitted from the export method of the GSSContext interface ๐Ÿ“ค. The receiver of the interprocess token initializes a GSSContext object with this token to create a new context ๐Ÿ“ฅ. Once a context has been exported, the GSSContext object is invalidated and is no longer available ๐Ÿ’€.

4.12. Error Reporting ๐Ÿšจ

RFC 2743 defined how major and minor status values signal GSS-API errors ๐Ÿ“ฃ. The major code, also called the GSS status code, signals errors at the GSS-API level, independent of the underlying mechanism(s) ๐Ÿง . The minor status value, or Mechanism status code, is a mechanism-defined error value that indicates a mechanism-specific error code ๐Ÿ”ง.

Java GSS-API uses exceptions implemented by the GSSException class to signal both minor and major error values ๐ŸŽฏ. Both mechanism-specific errors and GSS-API-level errors come through instances of this class ๐Ÿซถ. Because exceptions exist, the API calls don't need major and minor codes at all ๐Ÿ™…โ€โ™€๏ธ. The GSSException class also has methods that return textual representations of both the major and minor values, which does the same job as gss_display_status ๐ŸŒŸ๐Ÿ’–.

4.12.1. GSS status codes โœจ

Okay bestie, GSS status codes are for errors that don't depend on which underlying mechanism is doing the security work ๐Ÿ’…. The errors you can flag with one are the generic API routine errors, the ones defined in the GSS-API specification itself ๐ŸŽ€. These bindings lean on Java's exceptions mechanism, so there's no need for calling errors at all ๐Ÿ™ˆ.

A GSS status code marks a single fatal generic API error from whichever routine threw the GSSException. Throwing an exception announces that something fatal went wrong during the method ๐Ÿ’€. The GSS-API operational model also lets per-message calls hand back supplementary status information ๐Ÿฆ‹. That kind of info is warning-ish, not fatal, so exceptions are the wrong tool for it. It gets handled as return values instead ๐Ÿ’œ. The two per-message methods that can produce supplementary information are GSSContext.verifyMIC() and GSSContext.unwrap() โœจ. They fill in the supplementary status codes inside the MessageProp object that gets passed in.

The GSSException object does two jobs. It handles setting the various error codes and turning them into readable text, and it also holds the definitions of all the numeric error values ๐Ÿ”ฅ. Here's the full lineup of error codes:

Table: GSS Status Codes

Name                   Value   Meaning

BAD_MECH                 1     An unsupported mechanism
                               was requested.

BAD_NAME                 2     An invalid name was supplied.

BAD_NAMETYPE             3     A supplied name was of an
                               unsupported type.

BAD_BINDINGS             4     Incorrect channel bindings were
                               supplied.

BAD_STATUS               5     An invalid status code was
                               supplied.

BAD_MIC                  6     A token had an invalid MIC.

NO_CRED                  7     No credentials were supplied, or
                               the credentials were unavailable
                               or inaccessible.

NO_CONTEXT               8     Invalid context has been
                               supplied.

DEFECTIVE_TOKEN          9     A supplied token was invalid.

DEFECTIVE_CREDENTIAL    10     A supplied credential was
                               invalid.

CREDENTIALS_EXPIRED     11     The referenced credentials
                               have expired.

CONTEXT_EXPIRED         12     The context has expired.

FAILURE                 13     Miscellaneous failure,
                               unspecified at the GSS-API level.

BAD_QOP                 14     The quality-of-protection
                               requested could not be provided.

UNAUTHORIZED            15     The operation is forbidden by
                               local security policy.

UNAVAILABLE             16     The operation or option is
                               unavailable.

DUPLICATE_ELEMENT       17     The requested credential
                               element already exists.

NAME_NOT_MN             18     The provided name was not a
                               mechanism name.

OLD_TOKEN               19     The token's validity period has
                               expired.

DUPLICATE_TOKEN         20     The token was a duplicate of an
                               earlier version.

The GSS major status code FAILURE is the catch-all ๐Ÿงš. It means the underlying mechanism hit an error that doesn't have a specific GSS status code defined. The mechanism-specific status code can give you more details about what happened ๐Ÿ”.

The different major status codes that can show up in the GSSException object thrown by the methods in this spec are the same ones returned by the matching calls in RFC 2743 [GSSAPIv2-UPDATE] ๐Ÿ“š.


4.12.2. Mechanism-specific status codes ๐ŸŒธ

Mechanism-specific status codes come through in two ways. They can be part of any GSSException thrown from the mechanism-specific layer to signal a fatal error. Or they can live in the MessageProp object, which the per-message calls use to signal non-fatal errors ๐Ÿ’–.

A default value of 0 in either the GSSException object or the MessageProp object stands for "no mechanism-specific status code here" ๐Ÿ“.


4.12.3. Supplementary status codes ๐Ÿฆ‹

Supplementary status codes stick to the per-message methods of the GSSContext interface ๐Ÿ’œ. Because they're informative, using exceptions to signal them isn't appropriate. So the per-message operations of the GSSContext interface return these values inside a MessageProp object instead โœจ.

The MessageProp class has query methods that return boolean values for these supplementary states:

Table: Supplementary Status Methods

Method Name       Meaning when "true" is returned

isDuplicateToken   The token was a duplicate of an
                   earlier token.

isOldToken         The token's validity period has
                   expired.

isUnseqToken       A later token has already been
                   processed.

isGapToken         An expected per-message token was
                   not received.

A "true" return value from any of the above methods means the token has that property ๐ŸŽฏ. The application has to decide what to do about these supplementary values ๐Ÿซถ. They are not treated as errors by the GSS-API, so don't panic when you see them ๐Ÿ˜ญ.

4.13. Names ๐ŸŽ€

okay so a name is basically how we identify a person or entity ๐Ÿงš. the big thing is that GSS-API checks that the name and the entity actually claiming it really go together โœจ. no catfishing allowed ๐Ÿ™…โ€โ™€๏ธ

different auth mechanisms can use totally different namespaces for their principals ๐Ÿ’…, so GSS-API's naming stuff gets pretty complex in multi-mechanism setups. it can get messy even in single-mechanism setups, if the underlying mechanism supports more than one namespace ๐Ÿ™ˆ

there are two distinct ways to represent a name ๐Ÿ’–:

  1. a GSS-API form, represented by implementations of the GSSName interface. one GSSName object can hold multiple names from different namespaces, but all of those names should refer to the same entity ๐Ÿฆ‹. for example, if you call the getName method of the GSSCredential interface on a credential that has credential elements for several mechanisms with different namespaces, the name you get back is an internal name like this. this GSSName object will have a separate name for the entity for each authentication mechanism ๐ŸŒˆ

for GSS-API implementations that support multiple namespaces, GSSName implementations must contain enough info to work out which namespace each primitive name belongs to ๐Ÿ”ฅ

  1. mechanism-specific contiguous byte array and string forms ๐Ÿ“. there are different GSSName initialization methods for byte array and string formats, so you can pick what works for your app and the kind of name you have. these forms can only hold a single name (from a single namespace) ๐Ÿซถ. contiguous string names always come with an object identifier that says which namespace the name belongs to, and their format depends on the auth mechanism using that name ๐Ÿ’œ. string name forms are assumed to be printable, so GSS-API apps can show them to their users ๐ŸŒธ. byte array name formats are assumed to be non-printable (for example, the byte array returned by the export method of the GSSName interface) ๐Ÿ‘‘

a GSSName object can be turned into a contiguous representation with the toString method โœจ. this guarantees the name gets converted to a printable format ๐Ÿ’–. the GSSName interface has several initialization methods, which means you can use multiple syntaxes for each supported namespace and pick whichever name representation you like best ๐Ÿฆ‹. the toString method should use an implementation-chosen printable syntax for each supported name-type ๐ŸŽ€. if you want to find out the printable name type, use the getStringNameType method ๐Ÿ”

โš ๏ธ heads up bestie: calling toString will not always give you back the same string you originally imported ๐Ÿ˜ญ. the name might not even have come from a string in the first place. namespace identifiers might not survive unchanged after going through the internal name-form either ๐Ÿ™ˆ

here's an example of what I mean ๐Ÿงš. say there's a mechanism that authenticates X.500 names but also has an algorithmic mapping of Internet DNS names into X.500 ๐Ÿ’…. when that mechanism's GSSName implementation gets a DNS name, it might build an internal name that holds both the original DNS name and the equivalent X.500 name ๐ŸŒˆ. or it might only store the X.500 name ๐Ÿ“. in that second case, toString would most likely give you a printable X.500 name instead of the original DNS name ๐Ÿ’€

the context acceptor can get a GSSName object for the entity that started the context by using the getSrcName method โœจ. because a single mechanism authenticated this name, it only has one name in it, even if the internal name the context initiator gave to the GSSContext object had multiple components ๐Ÿ‘‘. names like this are called internal mechanism names, or "MN"s, and the names the GSSContext interface returns from getSrcName and getTargName are always this type ๐Ÿฆ‹. some apps need MNs but don't want to pay the overhead of an authentication operation ๐Ÿซถ, so there are creation methods that take the name buffer, the name type, and also the mechanism oid the name should be created for ๐Ÿ’œ. when you already have a GSSName object, you can call the canonicalize method to turn a general internal name into an MN ๐ŸŒธ

GSSName objects can be compared with their equal method ๐Ÿ”ฅ, which returns "true" if the two names refer to the same entity โœจ. this is the preferred way to compare names, rather than comparing the printable names a GSS-API implementation might support ๐Ÿ’–. GSS-API assumes that all primitive names inside a given internal name refer to the same entity, so equal can return "true" if the two names share at least one primitive name ๐ŸŽ€. if the implementation knows about equivalence relationships between names from different namespaces, that knowledge might also let it successfully compare internal names that have no overlapping primitive elements ๐Ÿงš

when you've got a big access control list, making a GSSName object for every name and calling equal on each one from the ACL could be way too expensive ๐Ÿ˜ญ. so, as another option, GSS-API defines a special form of the contiguous byte array name that can be compared directly, byte by byte ๐Ÿ’…. contiguous names that are suitable for comparison are generated by the export method ๐Ÿ“. you can re-import exported names by using the byte array constructor and specifying NT_EXPORT_NAME as the name type object identifier ๐ŸŒˆ. the resulting GSSName will also be an MN ๐Ÿ‘‘. the GSSName interface defines public static Oid objects that represent the standard name types ๐Ÿฆ‹. structurally, an exported name object has a header with an OID that identifies the mechanism that authenticated the name, and a trailer with the name itself ๐Ÿซถ. the syntax of that trailer is defined by each individual mechanism specification ๐Ÿ’œ. for a detailed description of the format, check the language-independent GSS-API specification [GSSAPIv2-UPDATE] ๐Ÿ“š

ngl, this is a really important one ๐Ÿ™ˆ: the results you get from the equals method will generally be different from what you get by calling canonicalize and export, and then comparing the byte array output ๐Ÿ’€. the first approach figures out whether two (unauthenticated) names identify the same principal ๐Ÿ”. the second one figures out whether a particular mechanism would authenticate them as the same principal ๐ŸŒธ. those two operations will generally only give the same results for MNs ๐ŸŽ€

also, the stuff above is just guidelines for how GSSName implementations should behave ๐Ÿ’–. it's not meant to be a list of specific requirements for how name objects must be built ๐Ÿงš. mechanism designers are free to decide the details of their GSSName implementations, as long as the behaviour still follows those guidelines โœจ


4.14. Channel Bindings ๐Ÿฆ‹

GSS-API lets you use user-specified tags to identify a particular context to the peer application ๐Ÿ’…. these tags are meant to identify the specific communications channel that carries the context ๐ŸŒˆ. channel bindings are passed to GSS-API using the ChannelBinding object ๐ŸŽ€. the application can use byte arrays to specify the application data for the channel binding, and it can also use instances of InetAddress ๐Ÿซถ. the InetAddress for the initiator and/or acceptor can be used inside a ChannelBinding instance ๐Ÿ’œ

a ChannelBinding can be set on the GSSContext object with the setChannelBinding method, but only before the first call to init or accept ๐Ÿ”ฅ. if setChannelBinding hasn't been used to set the ChannelBinding for a GSSContext object, then a "null" ChannelBinding is assumed ๐Ÿ™ˆ. InetAddress is currently the only address type defined within the Java platform, so it's the only one the ChannelBinding class supports ๐Ÿ“. apps that use other address types can put them in as part of the application-specific data ๐Ÿงš

conceptually, GSS-API joins the initiator and acceptor address information together with the application-supplied byte array to make an octet string โœจ. the mechanism calculates a MIC over this octet string and binds the MIC to the context establishment token that the init method of the GSSContext interface emits ๐Ÿ’–. the context acceptor sets the same bindings on its GSSContext object, and while processing the accept method, it calculates a MIC the same way ๐ŸŒธ. the calculated MIC is then compared with the one in the token ๐Ÿ‘‘. if the MICs differ, accept will throw a GSSException with the major code set to BAD_BINDINGS, and the context will not be established ๐Ÿ˜ญ

some mechanisms might include the actual channel binding data in the token (instead of just a MIC) ๐Ÿ’€. so, applications should not use confidential data as channel-binding components ๐Ÿ”’ โœ‹

individual mechanisms can put extra constraints on the addresses that show up in channel bindings ๐Ÿฆ‹. for example, a mechanism might check that the initiator address field of the channel binding contains the correct network address of the host system ๐Ÿซถ. so, portable applications should make sure that they either provide correct information in the address fields, or leave out the addressing information entirely ๐ŸŽ€


4.15. Stream Objects ๐ŸŒŠ

the context object has overloaded methods that use input and output streams to send authentication and per-message GSS-API tokens ๐Ÿ’…. the streams are expected to contain the usual GSS-API tokens, which would otherwise be handled through byte arrays ๐ŸŒˆ. tokens are expected to have a definite start and a definite end โœจ. the callers are responsible for making sure the supplied streams won't block, or for expecting to block until a full token has been processed by the GSS-API method ๐Ÿ™ˆ. only one GSS-API token gets processed per invocation of a stream-based method ๐Ÿ“

streams give callers control over and management of the buffers they supply ๐Ÿ’–. since streams are non-primitive objects, callers can make them as complicated or as simple as they like, just by using the streams defined in the java.io package or by creating their own through inheritance ๐Ÿงš. this gives applications the greatest flexibility ๐Ÿ‘‘


4.16. Optional Parameters ๐Ÿซถ

whenever the application wants to leave out an optional parameter, the "null" value shall be used ๐Ÿ’œ. the detailed method descriptions say which parameters are optional ๐Ÿ”. method overloading is also used as a technique to indicate default parameters ๐Ÿฆ‹


5. Introduction to GSS-API Classes and Interfaces โœจ

this section gives a brief description of the classes and interfaces that make up the GSS-API ๐ŸŽ€. the implementations of these come from the CLASSPATH defined by the application ๐Ÿ’–. if Java GSS becomes part of the standard Java APIs, these classes will be available by default on all systems, as part of the JRE's system classes ๐ŸŒˆ

this section also shows the RFC 2743 functionality that each of the classes implements ๐Ÿงš. detailed descriptions of these classes and their methods are in section 6 ๐Ÿ’… ๐Ÿซถ

5.1. GSSManager class

okay so the GSSManager class is basically the factory ๐Ÿญ that makes all the other GSS-API pieces for you. It also lets you ask what security mechanisms are around and what they can do, which is iconic โœจ

You can grab the default one with the static method getInstance(). If you want your own version, you can just extend the abstract class yourself ๐Ÿ’…

This class has the equivalents of these RFC 2743 routines:

gss_import_name              Create an internal name from   6.1.9-
                             the supplied information.      6.1.12

gss_acquire_cred             Acquire credential             6.1.13-
                             for use.                       6.1.15

gss_import_sec_context       Create a previously exported   6.1.18
                             context.

gss_indicate_mechs           List the mechanisms            6.1.6
                             supported by this GSS-API
                             implementation.

gss_inquire_mechs_for_name   List the mechanisms            6.1.8
                             supporting the
                             specified name type.

gss_inquire_names_for_mech   List the name types            6.1.7
                             supported by the
                             specified mechanism.

5.2. GSSName interface

GSS-API names show up in the Java bindings through the GSSName interface ๐Ÿท๏ธ Each name format gets its own universal Object Identifier (oid), and you can work out the format of a name just from its unique oid. The GSSName interface gives you these GSS-API routines:

RFC 2743 Routine                 Function               Section(s)


gss_display_name        Covert internal name             6.2.7
                        representation to text format.

gss_compare_name        Compare two internal names.      6.2.3, 6.2.4

gss_release_name        Release resources associated     N/A
                        with the internal name.

gss_canonicalize_name   Convert an internal name to a    6.1.11,
                        mechanism name.

gss_export_name         Convert a mechanism name to      6.2.6
                        export format.

gss_duplicate_name      Create a copy of the internal    N/A
                        name.

The gss_release_name call isn't here because Java handles its own garbage collection ๐Ÿ—‘๏ธ The gss_duplicate_name call is extra too, since the GSSName interface has no mutator methods that can change the state of the object, so it's safe to share ๐Ÿซถ

5.3. GSSCredential interface

The GSSCredential interface wraps up GSS-API credentials ๐Ÿ” A credential identifies a single entity and carries the cryptographic info needed to create a context on that entity's behalf. One credential can hold several mechanism-specific credentials, and each of those is called a credential element. This interface gives you these GSS-API routines:

RFC 2743 Routine               Function                Section(s)

gss_add_cred               Constructs credentials        6.3.12
                           incrementally.

gss_inquire_cred           Obtain information about   6.3.4,6.3.5
                           credential.

gss_inquire_cred_by_mech   Obtain per-mechanism       6.3.5-6.3.10
                           information about
                           a credential.

gss_release_cred           Disposes of credentials       6.3.3
                           after use.

5.4. GSSContext interface

This interface handles the context-level calls for setting up and managing a security context between peers, plus the per-message services apps use ๐Ÿฆ‹ A context is set up between a pair of peers and lets you use security services on a per-message basis for application data. It's created over one single security mechanism. The GSSContext interface gives you these GSS-API routines:

RFC 2743 Routine                 Function                Section(s)

gss_init_sec_context     Initiate the creation of a       6.4.3,
                         security context with a peer.    6.4.4

gss_accept_sec_context   Accept a security context        6.4.5,
                         initiated by a peer.             6.4.6

gss_delete_sec_context   Destroy a security context.      6.4.8

gss_context_time         Obtain remaining context         6.4.37
                         time.

gss_inquire_context      Obtain context                   6.4.29 to
                         characteristics.                 6.3.42

gss_wrap_size_limit      Determine token-size limit       6.4.9
                         for gss_wrap.

gss_export_sec_context   Transfer security context        6.4.18
                         to another process.


gss_get_mic              Calculate a cryptographic        6.4.14,
                         Message Integrity Code (MIC)     6.4.15
                         for a message.

gss_verify_mic           Verify integrity on a received   6.4.16,
                         message.                         6.4.17

gss_wrap                 Attach a MIC to a message and    6.4.10,
                         optionally encrypt the message   6.4.11
                         content.

gss_unwrap               Obtain a previously wrapped      6.4.12,
                         application message verifying    6.4.13
                         its integrity and optionally
                         decrypting it.

The gss_process_context_token routine didn't make it into the Java bindings spec ๐Ÿ™ˆ The gss_delete_sec_context routine got tweaked so it doesn't return any peer tokens, and that change was proposed following the recommendations stated in RFC 2743. Even so, GSSContext still lets you destroy the locally-stored context information ๐Ÿ’–

5.5. MessageProp class

The MessageProp class is a helper used in the per-message operations on the context โœ‰๏ธ Your app makes an instance of it and then passes it into those per-message calls. Sometimes the app tells the GSS-API implementation things through this object, and other times the GSS-API hands info back to the app by setting it on this object. For the details on the per-message operations wrap, unwrap, getMIC, and verifyMIC, check out the GSSContext interface ๐ŸŒธ

5.6. GSSException class

Exceptions are how the Java bindings signal fatal errors to the calling apps ๐Ÿšจ This replaces the major and minor codes from the C-bindings spec as the way to signal failures. The GSSException class handles both minor and major codes, and it also turns them into text. Every GSS-API method is declared as throwing this exception.

RFC 2743 Routine           Function              Section

gss_display_status   Retrieve textual          6.8.5, 6.8.6,
                     representation of error   6.8.8, 6.8.9
                     codes.

5.7. Oid class

The Oid class is a utility for representing Universal Object Identifiers and the operations that go with them ๐Ÿ”ข GSS-API uses object identifiers to tell security mechanisms and name types apart. Whenever you need an object identifier, you use this class, and it also gives you this GSS-API functionality:

RFC 2743 Routine                  Function              Section

gss_test_oid_set_member   Determine if the specified oid   6.7.5
                          is part of a set of oids.

5.8. ChannelBinding class

An instance of ChannelBinding is how you pass channel binding info to a GSSContext object before a security context gets established ๐ŸŽ€ The app can use a byte array for application data to go into the channel binding, and it can also use instances of InetAddress. InetAddress is currently the only address type defined within the Java platform, so it's the only one ChannelBinding supports. If your app uses other address types, you can include them as part of the application data ๐Ÿงš

6. Detailed GSS-API Class Description โœจ

This section goes through the detailed description of all the public methods that each GSS-API class and interface has to provide ๐Ÿ“š

6.1. public abstract class GSSManager

GSSManager is an abstract class and a factory for three GSS interfaces: GSSName, GSSCredential, and GSSContext ๐Ÿญ It also has methods that let apps figure out which mechanisms the GSS implementation offers and which nametypes those mechanisms support. You can get an instance of the default GSSManager subclass through the static method getInstance(), but apps are free to instantiate other GSSManager subclasses too ๐Ÿ’œ

Every method in this class is declared abstract except one. That means subclasses have to supply the full implementation for those methods. The only exception is the static method getInstance(), which has platform-specific code to return an instance of the default subclass.

Platform providers of GSS are required not to add any constructors to this class, whether private, public, or protected. This makes sure every subclass only invokes the default constructor the compiler gives the base class ๐Ÿ”’

A subclass that extends the GSSManager abstract class can be built as a modular, provider-based layer that uses some well-known service provider specification. The GSSManager API gives the app methods for setting provider preferences on such an implementation. These methods also let the implementation throw a well-defined exception when provider-based configuration isn't supported. Apps that want to be portable should know about this and recover cleanly by catching the exception ๐Ÿซถ

There are three most common ways providers get used:

  1. The application doesn't care which provider is used (the default case).
  2. The application wants a particular provider used preferentially, either for a particular mechanism or all the time, no matter the mechanism.
  3. The application wants to use the locally configured providers as far as possible, but if support is missing for one or more mechanisms, it wants to fall back on its own provider.

The GSSManager class has two methods for these modes of usage: addProviderAtFront() and addProviderAtEnd() ๐ŸŒˆ These methods create an ordered list of <provider, oid> pairs, where each pair shows a provider preference for a given oid.

You don't need to know anything about whatever service provider specification the GSSManager subclass follows to use these methods. They're hoped to serve the needs of most applications ๐Ÿ’– Extended GSSManager classes might add more methods, which could become part of a service provider specification that gets standardized later.

6.1.1. Example Code ๐Ÿ’…

okay bestie, let's see this in action ๐ŸŽ€ here's how you'd poke at the GSSManager and set up some providers.

GSSManager mgr = GSSManager.getInstance();

// What mechs are available to us?
Oid[] supportedMechs = mgr.getMechs();

// Set a preference for the provider to be used when support is needed
// for the mechanisms "1.2.840.113554.1.2.2" and "1.3.6.1.5.5.1.1".

Oid krb = new Oid("1.2.840.113554.1.2.2");
Oid spkm1 = new Oid("1.3.6.1.5.5.1.1");

Provider p = (Provider) (new com.foo.security.Provider());

mgr.addProviderAtFront(p, krb);
mgr.addProviderAtFront(p, spkm1);

// What name types does this spkm implementation support?
Oid[] nameTypes = mgr.getNamesForMech(spkm1);

6.1.2. getInstance โœจ

public static GSSManager getInstance()

this one gives you the default GSSManager implementation ๐ŸŒธ

6.1.3. getMechs ๐Ÿฆ‹

public abstract Oid[] getMechs()

this hands back an array of Oid objects for the mechanisms that GSS-API callers can use ๐Ÿ’– if no mechanisms are available, you get null back. ngl that happens when mechanisms are configured dynamically and none are installed right now ๐Ÿ™ˆ

6.1.4. getNamesForMech ๐Ÿงš

public abstract  Oid[] getNamesForMech(Oid mech)
                       throws GSSException

returns the name type Oids supported by the mechanism you pass in ๐Ÿ”ฅ

Parameters:

  • mech: The Oid object for the mechanism to query.

6.1.5. getMechsForName ๐ŸŒˆ

public abstract  Oid[] getMechsForName(Oid nameType)

this gives you an array of Oid objects for the mechanisms that support a specific name type ๐Ÿ“ if nothing supports that name type, it's giving null ๐Ÿ’€

Parameters:

  • nameType: The Oid object for the name type.

6.1.6. createName ๐Ÿ’œ

public abstract GSSName createName(String nameStr, Oid nameType)
                throws GSSException

this is a factory method that turns a contiguous string name from the namespace you specify into a GSSName object ๐Ÿซถ usually the GSSName you get back won't be an MN. the two exceptions are when the namespace type says NT_EXPORT_NAME, or when the GSS-API implementation isn't multi-mechanism. so main character energy, but with exceptions ๐Ÿ‘‘

Parameters:

  • nameStr: The string representing a printable form of the name to create.
  • nameType: The Oid specifying the namespace of the printable name supplied. Note that nameType serves to describe and qualify the interpretation of the input nameStr, it does not necessarily imply a type for the output GSSName implementation. A null value can be used to specify that a mechanism specific default printable syntax should be assumed by each mechanism that examines nameStr.

6.1.7. createName ๐ŸŒธ

public abstract GSSName createName(byte name[], Oid nameType)
                throws GSSException

same vibe as 6.1.6, except this one takes a contiguous byte array containing the name from the specified namespace and turns it into a GSSName object ๐Ÿฆ‹ the usual exceptions still apply, so the GSSName usually won't be an MN, unless the namespace type says NT_EXPORT_NAME or the GSS-API implementation isn't multi-mechanism ๐Ÿ’…

Parameters:

  • name: The byte array containing the name to create.
  • nameType: The Oid specifying the namespace of the name supplied in the byte array. Note that nameType serves to describe and qualify the interpretation of the input name byte array, it does not necessarily imply a type for the output GSSName implementation. A null value can be used to specify that a mechanism specific default syntax should be assumed by each mechanism that examines the byte array.

6.1.8. createName โœจ

public abstract GSSName createName(String nameStr, Oid nameType,
                Oid mech) throws GSSException

okay so this one is a little combo move ๐ŸŽ€ it takes a contiguous string name from the specified namespace and gives you a GSSName that's a mechanism name (MN). basically it does two things for you: the createName from 6.1.7, and then GSSName.canonicalize() from 6.2.5 ๐Ÿงš

Parameters:

  • nameStr: The string representing a printable form of the name to create.
  • nameType: The Oid specifying the namespace of the printable name supplied. Note that nameType serves to describe and qualify the interpretation of the input nameStr, it does not necessarily imply a type for the output GSSName implementation. A null value can be used to specify that a mechanism specific default printable syntax should be assumed when the mechanism examines nameStr.
  • mech: The Oid specifying the mechanism for which this name should be created.

6.1.9. createName ๐ŸŒˆ

public abstract createName(byte name[], Oid nameType, Oid mech)
                throws GSSException

this is the byte array version of 6.1.8 ๐Ÿ“ it makes a GSSName that's an MN from a contiguous byte array in the specified namespace. same deal as before: it's the createName from 6.1.8 plus GSSName.canonicalize() from 6.2.5, all in one go ๐Ÿ’–

Parameters:

  • name: The byte array representing the name to create.
  • nameType: The Oid specifying the namespace of the name supplied in the byte array. Note that nameType serves to describe and qualify the interpretation of the input name byte array, it does not necessarily imply a type for the output GSSName implementation. A null value can be used to specify that a mechanism specific default syntax should be assumed by each mechanism that examines the byte array.
  • mech: The Oid specifying the mechanism for which this name should be created.

6.1.10. createCredential ๐Ÿ”ฅ

public abstract GSSCredential createCredential (int usage)
                throws GSSException

this is the factory method for grabbing default credentials ๐Ÿ’… it tells the GSS-API to use system specific defaults for the set of mechanisms, the name, and a DEFAULT lifetime. bestie, that's a whole lot of "figure it out for me" energy ๐Ÿ˜ญ

Parameters:

  • usage: The intended usage for this credential object. The value of this parameter must be one of:
    • GSSCredential.ACCEPT_AND_INITIATE
    • GSSCredential.ACCEPT_ONLY
    • GSSCredential.INITIATE_ONLY

6.1.11. createCredential ๐Ÿฆ‹

public abstract GSSCredential createCredential (GSSName aName,
                int lifetime, Oid mech, int usage)
                throws GSSException

factory method for acquiring a single mechanism credential ๐ŸŒธ this one lets you pick the principal, lifetime, mechanism, and usage yourself, so you're in control ๐Ÿ‘‘

Parameters:

  • aName: Name of the principal for whom this credential is to be acquired. Use null to specify the default principal.
  • lifetime: The number of seconds that credentials should remain valid. Use GSSCredential.INDEFINITE_LIFETIME to request that the credentials have the maximum permitted lifetime. Use GSSCredential.DEFAULT_LIFETIME to request default credential lifetime.
  • mech: The oid of the desired mechanism. Use (Oid) null to request the default mechanism(s).
  • usage: The intended usage for this credential object. The value of this parameter must be one of:
    • GSSCredential.ACCEPT_AND_INITIATE
    • GSSCredential.ACCEPT_ONLY
    • GSSCredential.INITIATE_ONLY

6.1.12. createCredential ๐Ÿ’œ

public abstract GSSCredential createCredential(GSSName aName,
                int lifetime, Oid mechs[], int usage)
                throws GSSException

this is the version for getting credentials over a whole set of mechanisms ๐Ÿงš it acquires credentials for each mechanism in the mechs array. to find out which mechanisms the acquisition actually worked for, call GSSCredential.getMechs() ๐Ÿซถ

Parameters:

  • aName: Name of the principal for whom this credential is to be acquired. Use null to specify the default principal.
  • lifetime: The number of seconds that credentials should remain valid. Use GSSCredential.INDEFINITE_LIFETIME to request that the credentials have the maximum permitted lifetime. Use GSSCredential.DEFAULT_LIFETIME to request default credential lifetime.
  • mechs: The array of mechanisms over which the credential is to be acquired. Use (Oid[]) null for requesting a system specific default set of mechanisms.
  • usage: The intended usage for this credential object. The value of this parameter must be one of:
    • GSSCredential.ACCEPT_AND_INITIATE
    • GSSCredential.ACCEPT_ONLY
    • GSSCredential.INITIATE_ONLY

6.1.13. createContext ๐ŸŒˆ

public abstract GSSContext createContext(GSSName peer, Oid mech,
                GSSCredential myCred, int lifetime)
                throws GSSException

factory method for making a context on the initiator's side ๐Ÿ“ you can tweak the context flags with the mutator methods before you call GSSContext.initSecContext() ๐Ÿ’–

Parameters:

  • peer: Name of the target peer.
  • mech: Oid of the desired mechanism. Use (Oid) null to request default mechanism.
  • myCred: Credentials of the initiator. Use null to act as a default initiator principal.
  • lifetime: The request lifetime, in seconds, for the context. Use GSSContext.INDEFINITE_LIFETIME and GSSContext.DEFAULT_LIFETIME to request indefinite or default context lifetime.

6.1.14. createContext ๐Ÿ”ฅ

public abstract GSSContext createContext(GSSCredential myCred)
                throws GSSException

factory method for making a context on the acceptor side ๐Ÿ™ˆ the context's properties get determined from the input token that's supplied to the accept method, so you don't set them up yourself ๐Ÿ’…

Parameters:

  • myCred: Credentials for the acceptor. Use null to act as a default acceptor principal.

6.1.15. createContext ๐Ÿงš

public abstract GSSContext createContext(byte [] interProcessToken)
                throws GSSException

last one in this batch, and it's the factory method for recreating a previously exported context ๐Ÿฆ‹ the context properties come from the input token, and they can't be changed through the set methods after that ๐Ÿซถ

Parameters:

  • interProcessToken: The token previously emitted from the export method.

6.1.16. addProviderAtFront โœจ

public abstract void addProviderAtFront(Provider p, Oid mech)
             throws GSSException

okay so this method lets the app tell the GSSManager "use THIS provider first, bestie" whenever it needs support for a given mechanism ๐Ÿ’…. If you pass null instead of an Oid for the mechanism, the GSSManager must use the provider you picked ahead of all the others, no matter what the mechanism is ๐Ÿ‘‘. It only moves on to a different provider when the one you picked doesn't support the mechanism it needs ๐Ÿซถ.

Calling this repeatedly doesn't wipe your older settings ๐Ÿฆ‹. It just pushes them down in priority, so you build up an ordered list of provider and Oid pairs that keeps growing at the top ๐ŸŒธ.

Calling addProviderAtFront with a null Oid removes all previous preferences that were set for this provider in that GSSManager instance ๐Ÿ’€. Calling it with a non-null Oid only removes the previous preference that used that same mechanism and that same provider together โœจ.

If the GSSManager implementation doesn't support an SPI with a pluggable provider architecture, it should throw a GSSException with the status code GSSException.UNAVAILABLE to say the operation is unavailable ๐Ÿ™ˆ.

Parameters:

  • p: The provider instance that should be used whenever support is needed for mech.
  • mech: The mechanism for which the provider is being set.

6.1.16.1. Example Code ๐Ÿงš

Say an app wants provider A to always get checked first whenever any mechanism is needed. It would call:

        GSSManager mgr = GSSManager.getInstance();
        // mgr may at this point have its own pre-configured list
        // of provider preferences. The following will prepend to
        // any such list:

        mgr.addProviderAtFront(A, null);

Now if it also wants the mechanism of Oid m1 to come from provider B before A gets checked, it would call:

        mgr.addProviderAtFront(B, m1);

So the GSSManager would first check with B if m1 is needed. If B doesn't support m1, the GSSManager continues on to check with A ๐ŸŽ€. If any mechanism m2 is needed, and m2 is different from m1, then the GSSManager skips B and checks with A directly ๐Ÿ’–.

Later on, suppose this call is made to the same GSSManager instance:

        mgr.addProviderAtFront(B, null)

Then the earlier (B, m1) setting gets subsumed by this one and should be removed. The list of preferences now effectively becomes:

{(B, null), (A, null),
        ... //followed by the pre-configured list.

Please note, though, that this call:

        mgr.addProviderAtFront(A, m3)

does NOT subsume the previous (A, null) setting, so the list effectively becomes:

{(A, m3), (B, null), (A, null), ...}

6.1.17. addProviderAtEnd ๐ŸŒˆ

public abstract addProviderAtEnd(Provider p, Oid mech)
                throws GSSException

this one is the opposite energy ๐Ÿฅน. It tells the GSSManager that the app wants a certain provider used only if no other provider can be found that supports the given mechanism. If you pass null instead of an Oid, the GSSManager must use that provider for any mechanism ๐Ÿ“.

Calling this repeatedly keeps the older settings and ranks them above the newer ones. So you get an ordered list of provider and Oid pairs that grows at the bottom, and the older provider settings always get used first ๐Ÿ’œ.

If there are any previously existing preferences that conflict with the one being set here, the GSSManager should ignore this request ๐Ÿ™…โ€โ™€๏ธ.

If the GSSManager implementation doesn't support an SPI with a pluggable provider architecture, it should throw a GSSException with the status code GSSException.UNAVAILABLE to indicate the operation is unavailable ๐Ÿ’€.

Parameters:

  • p: The provider instance that should be used whenever support is needed for mech.
  • mech: The mechanism for which the provider is being set.

6.1.17.1. Example Code ๐ŸŽ€

Say an app wants this: whenever a mechanism of Oid m1 is needed, the system default providers get checked first, and only if they don't support m1 should provider A be checked. It would make this call:

        GSSManager mgr = GSSManager.getInstance();

        mgr.addProviderAtEnd(A, m1);

Now if it also wants provider B to be checked, for all mechanisms, after all the configured providers have been checked, it would call:

        mgr.addProviderAtEnd(B, null);

So the list of preferences effectively becomes {..., (A, m1), (B, null)} ๐Ÿซถ.

Later on, suppose this call is made to the same GSSManager instance:

        mgr.addProviderAtEnd(B, m2)

Then the earlier (B, null) pair subsumes this one, so this request should be ignored. The same thing happens if a request is made for the pairs that already exist, (A, m1) or (B, null) ๐Ÿ™ˆ.

Please note, though, that this call:

        mgr.addProviderAtEnd(A, null)

is NOT subsumed by the earlier (A, m1) setting, so the list effectively becomes {..., (A, m1), (B, null), (A, null)} ๐ŸŒธ.


6.2. public interface GSSName ๐Ÿฆ‹

This interface wraps up a single GSS-API principal entity ๐Ÿงธ. Different name formats and their definitions are identified with universal Object Identifiers (Oids). You can work out the format of a name from the unique Oid of its namespace type ๐Ÿ”.

6.2.1. Example Code ๐Ÿ’…

Here are some code examples using the GSSName interface โœจ. The code below creates a GSSName, converts it to a mechanism name (MN), performs a comparison, gets a printable representation of the name, exports it, and then re-imports it to get a brand-new GSSName ๐Ÿซง.

GSSManager mgr = GSSManager.getInstance();

// create a host based service name
GSSName name = mgr.createName("service@host",
                GSSName.NT_HOSTBASED_SERVICE);

Oid krb5 = new Oid("1.2.840.113554.1.2.2");

GSSName mechName = name.canonicalize(krb5);

// the above two steps are equivalent to the following
GSSName mechName = mgr.createName("service@host",
                GSSName.NT_HOSTBASED_SERVICE, krb5);

// perform name comparison
if (name.equals(mechName))
        print("Names are equals.");

// obtain textual representation of name and its printable
// name type
print(mechName.toString() +
                mechName.getStringNameType().toString());

// export and re-import the name
byte [] exportName = mechName.export();

// create a new name object from the exported buffer
GSSName newName = mgr.createName(exportName,
                GSSName.NT_EXPORT_NAME);

6.2.2. Static Constants ๐ŸŽ€

public static final Oid NT_HOSTBASED_SERVICE

This Oid indicates a host-based service name form ๐Ÿ–ฅ๏ธ. It's used to represent services associated with host computers. The name form is built from two elements, "service" and "hostname", like this:

     service@hostname

Values for the "service" element are registered with the IANA. This constant represents the following value: { 1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes), 2(gss-host-based-services) } ๐Ÿ’œ

public static final Oid NT_USER_NAME

This name type indicates a named user on a local system. It represents the following value: { iso(1) member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) generic(1) user_name(1) } ๐Ÿงš

public static final Oid NT_MACHINE_UID_NAME

This name type indicates a numeric user identifier that corresponds to a user on a local system (e.g. Uid). It represents the following value: { iso(1) member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) generic(1) machine_uid_name(2) } ๐Ÿ“

public static final Oid NT_STRING_UID_NAME

This name type indicates a string of digits representing the numeric user identifier of a user on a local system. It represents the following value: { iso(1) member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) generic(1) string_uid_name(3) } ๐ŸŒˆ

public static final Oid NT_ANONYMOUS

This name type represents an anonymous entity ๐Ÿ™ˆ. It represents the following value: { 1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes), 3(gss-anonymous-name) } ๐Ÿ‘ป

public static final Oid NT_EXPORT_NAME

This name type indicates an exported name produced by the export method ๐Ÿ“ฆ. It represents the following value: { 1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes), 4(gss-api-exported-name) } โœจ

6.2.3. equals ๐Ÿ’–

public boolean equals(GSSName another) throws GSSException

This compares two GSSName objects to figure out whether they refer to the same entity ๐Ÿ‘ฏ. This method may throw a GSSException when the names can't be compared. If either name represents an anonymous entity, the method returns "false" ๐Ÿ™…โ€โ™€๏ธ.

Parameters:

  • another: GSSName object to compare with.

6.2.4. equals ๐Ÿซถ

public boolean equals(Object another)

This is a variation of the equals method from 6.2.3, provided to override the Object.equals() method that the implementing class inherits ๐Ÿงฉ. The behavior is exactly the same as in 6.2.3, except no GSSException is thrown. Instead, false is returned in the situation where an error occurs. (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:

  • another: GSSName object to compare with.

6.2.5. canonicalize ๐ŸŒธ

public GSSName canonicalize(Oid mech) throws GSSException

This creates a mechanism name (MN) from an arbitrary internal name โœจ. It's equivalent to using the factory methods described in 6.1.9 or 6.1.10 that take the mechanism name as one of their parameters.

Parameters:

  • mech: The oid for the mechanism for which the canonical form of the name is requested.

6.2.6. export ๐Ÿ“ฆ

public byte[] export() throws GSSException

This returns a canonical, contiguous byte representation of a mechanism name (MN), suitable for direct, byte-by-byte comparison by authorization functions ๐Ÿ”. If the name isn't an MN, implementations may throw a GSSException with the NAME_NOT_MN status code. If an implementation chooses not to throw an exception, it should use some system-specific default mechanism to canonicalize the name and then export it ๐Ÿ™ˆ. The format of the header of the output buffer is specified in RFC 2743 ๐Ÿ“œ.

6.2.7. toString ๐ŸŽ€

public String toString()

This returns a textual representation of the GSSName object ๐Ÿ’ฌ. To retrieve the printed name format, which determines the syntax of the returned string, you can use the getStringNameType method ๐Ÿ”.

6.2.8. getStringNameType ๐Ÿ’…

public Oid getStringNameType() throws GSSException

This returns the Oid representing the type of name returned through the toString method โœจ. Using this Oid, you can work out the syntax of the printable name ๐Ÿง .

6.2.9. isAnonymous ๐Ÿ™ˆ

public boolean isAnonymous()

This tests whether this name object represents an anonymous entity ๐Ÿ•ต๏ธโ€โ™€๏ธ. It returns "true" if this is an anonymous name ๐Ÿซ .

6.2.10. isMN ๐Ÿฆ‹

public boolean isMN()

This tests whether this name object contains only one mechanism element, which makes it a mechanism name as defined by RFC 2743 ๐Ÿ’–.

6.3. public interface GSSCredential implements Cloneable โœจ

okay so this interface is the GSS-API credentials for an entity ๐Ÿ” A credential holds all the cryptographic info needed to create a context on behalf of the entity it represents. It can contain several mechanism-specific credential elements, each with info for one security mechanism, but they all refer to the same entity. it's giving organized ๐Ÿ’…

A credential may be used to perform context initiation, acceptance, or both.

GSS-API implementations must impose a local access-control policy on callers, so unauthorized callers can't grab credentials they aren't entitled to ๐Ÿšซ Credential creation is NOT meant to be a "login to the network" function ๐Ÿ™…โ€โ™€๏ธ That kind of thing would create new credentials rather than just grabbing a handle to existing ones. If you need that, it should be defined in implementation-specific extensions to the API.

If acquiring a credential is slow for a mechanism, the mechanism may choose to delay the actual acquisition until the credential is needed (for example, by GSSContext) ๐Ÿข Those mechanism-specific decisions should be invisible to the calling app. So the query methods right after you create a credential object must return valid credential data, even if that means paying the cost of the deferred acquisition. no cap, that's the main character move ๐Ÿ‘‘

Applications create a credential object by passing in the parameters they want. Then they can use the query methods to learn about the instantiated credential object (this is the same idea as the gss_inquire routines) ๐Ÿ” When the credential isn't needed anymore, the app should call dispose (the same as gss_release_cred) to free up any resources the credential object holds and to destroy any cryptographically sensitive info ๐Ÿงน

Classes that implement this interface also implement Cloneable ๐Ÿงฌ That means the class supports the clone() method, which lets you make duplicate credentials. It's super useful when you call it right before add(), so you keep a copy of the original credential ๐Ÿซถ

6.3.1. Example Code

this example shows creating a GSSCredential for a specific entity, querying its fields, and releasing it when you're done ๐ŸŽ€

GSSManager mgr = GSSManager.getInstance();

// start by creating a name object for the entity
GSSName name = mgr.createName("userName", GSSName.NT_USER_NAME);

// now acquire credentials for the entity
GSSCredential cred = mgr.createCredential(name,
                GSSCredential.ACCEPT_ONLY);

// display credential information - name, remaining lifetime,
// and the mechanisms it has been acquired over
print(cred.getName().toString());
print(cred.getRemainingLifetime());

Oid [] mechs = cred.getMechs();
if (mechs != null) {
        for (int i = 0; i < mechs.length; i++)
                print(mechs[i].toString());
}

// release system resources held by the credential
cred.dispose();

6.3.2. Static Constants

public static final int INITIATE_AND_ACCEPT

credential usage flag asking that it be usable for both context initiation and acceptance ๐Ÿ’–

public static final int INITIATE_ONLY

credential usage flag asking that it be usable for context initiation only ๐Ÿš€

public static final int ACCEPT_ONLY

credential usage flag asking that it be usable for context acceptance only ๐Ÿšช

public static final int DEFAULT_LIFETIME

a lifetime constant for the default credential lifetime โณ

This value must be set to 0.

public static final int INDEFINITE_LIFETIME

a lifetime constant for an indefinite credential lifetime โ™พ๏ธ This value must be set to the maximum integer value in Java, which is Integer.MAX_VALUE.

6.3.3. dispose

public void dispose() throws GSSException

releases any sensitive info the GSSCredential object might be holding ๐Ÿงผ Applications should call this as soon as the credential isn't needed anymore, so the sensitive info sticks around for as little time as possible โฑ๏ธ

6.3.4. getName

public GSSName getName() throws GSSException

retrieves the name of the entity the credential asserts ๐Ÿชช

6.3.5. getName

public GSSName getName(Oid mechOID) throws GSSException

retrieves a mechanism name of the entity the credential asserts. It's equivalent to calling canonicalize() on the name returned by 7.3.3 โœจ

Parameters:

  • mechOID: the mechanism for which information should be returned.

6.3.6. getRemainingLifetime

public int getRemainingLifetime() throws GSSException

returns the remaining lifetime in seconds for a credential โŒ› The remaining lifetime is the minimum lifetime across all the underlying credential mechanisms. A return value of GSSCredential.INDEFINITE_LIFETIME means the credential doesn't expire ๐ŸŒˆ A return value of 0 means the credential is already expired ๐Ÿ’€

6.3.7. getRemainingInitLifetime

public int getRemainingInitLifetime(Oid mech) throws GSSException

returns the remaining lifetime in seconds for the credential to stay capable of initiating security contexts under the specified mechanism ๐Ÿš€ A return value of GSSCredential.INDEFINITE_LIFETIME means the credential doesn't expire for context initiation. A return value of 0 means it's already expired.

Parameters:

  • mechOID: the mechanism for which information should be returned.

6.3.8. getRemainingAcceptLifetime

public int getRemainingAcceptLifetime(Oid mech) throws GSSException

returns the remaining lifetime in seconds for the credential to stay capable of accepting security contexts under the specified mechanism ๐Ÿšช A return value of GSSCredential.INDEFINITE_LIFETIME means the credential doesn't expire for context acceptance. A return value of 0 means it's already expired.

Parameters:

  • mechOID: the mechanism for which information should be returned.

6.3.9. getUsage

public int getUsage() throws GSSException

returns the credential usage flag ๐ŸŽฏ The return value will be one of GSSCredential.INITIATE_ONLY, GSSCredential.ACCEPT_ONLY, or GSSCredential.INITIATE_AND_ACCEPT.

6.3.10. getUsage

public int getUsage(Oid mechOID) throws GSSException

returns the credential usage flag for the specified credential mechanism ๐ŸŽฏ The return value will be one of GSSCredential.INITIATE_ONLY, GSSCredential.ACCEPT_ONLY, or GSSCredential.INITIATE_AND_ACCEPT.

Parameters:

  • mechOID: the mechanism for which information should be returned.

6.3.11. getMechs

public Oid[] getMechs() throws GSSException

returns an array of the mechanisms this credential supports ๐Ÿงฉ

6.3.12. add

public void add(GSSName aName, int initLifetime, int acceptLifetime,
                Oid mech, int usage) throws GSSException

adds a mechanism-specific credential element to an existing credential ๐Ÿงฑ This lets you build a credential one mechanism at a time.

this one is mainly meant for context acceptors building acceptance credentials that will be used with a bunch of different clients using different security mechanisms ๐Ÿซ‚

add() adds the new credential element "in-place". If you want the new element in a new credential instead, call clone() first to get a copy of this credential, then call its add() method. ๐Ÿช„

Parameters:

  • aName: the name of the principal this credential is to be acquired for. Use "null" to specify the default principal.
  • initLifetime: the number of seconds the credentials should remain valid for initiating security contexts. Use GSSCredential.INDEFINITE_LIFETIME to request the maximum permitted lifetime. Use GSSCredential.DEFAULT_LIFETIME to request the default credential lifetime.
  • acceptLifetime: the number of seconds the credentials should remain valid for accepting security contexts. Use GSSCredential.INDEFINITE_LIFETIME to request the maximum permitted lifetime. Use GSSCredential.DEFAULT_LIFETIME to request the default credential lifetime.
  • mech: the mechanisms over which the credential is to be acquired.
  • usage: the intended usage for this credential object. The value of this parameter must be one of: GSSCredential.ACCEPT_AND_INITIATE, GSSCredential.ACCEPT_ONLY, GSSCredential.INITIATE_ONLY

6.3.13. equals

public boolean equals(Object another)

checks whether this GSSCredential refers to the same entity as the object you pass in ๐Ÿค Both credentials must be acquired over the same mechanisms and must refer to the same principal. Returns "true" if they refer to the same entity, "false" otherwise.

(Heads up, bestie: the Java language spec requires that two objects which are equal according to the equals(Object) method must return the same integer result when hashCode() is called on them ๐Ÿง )

Parameters:

  • another: another GSSCredential object for comparison.

6.4. public interface GSSContext ๐Ÿฆ‹

okay so this interface is the GSS-API security context, and it's giving everything ๐Ÿ’… It gives you the security services (wrap, unwrap, getMIC, verifyMIC) that live over the context. Contexts get set up between peers using credentials you've already acquired locally. You can have multiple contexts going between the same pair of peers at once, using the same credentials or different ones. Bestie, GSS-API doesn't care what transport you're using, so it's on your calling application to carry its tokens between peers ๐Ÿšš

Before the context establishment phase starts, the context initiator can ask for specific characteristics they want from the context. You set those with the set methods. Once the context is established, you check what the context actually gives you (the characteristics and services it offers) with the query methods. Main character energy ๐Ÿ‘‘

The context establishment phase kicks off with the first call to the init method from the context initiator. During this phase, initSecContext and acceptSecContext produce GSS-API authentication tokens, and your application needs to send those to its peer ๐Ÿ“จ If anything goes wrong at any point, an exception gets thrown and the code jumps into a catch block ๐Ÿ’€ If nothing goes wrong, the code keeps flowing normally and you can call isEstablished(). If it returns false, that means you need a token from your peer before you can keep establishing the context. If it returns true, the local end of the context is established. Even then, you might still have to send a token to the peer, if GSS-API produced one ๐ŸŽ€

Also, during establishment, you can call isProtReady() to find out if the context is ready for per-message operations. This lets you use per-message operations on contexts that aren't fully established yet. Iconic โœจ

Once the context is established, or isProtReady() returns "true", you can call the query routines to see the actual characteristics and services of the context. You can also start using the per-message methods wrap and getMIC to get cryptographic operations on application-supplied data ๐Ÿ”

When you're done with the context, your application should call dispose to release any system resources the context is using ๐Ÿงน


6.4.1. Example Code ๐ŸŒธ

This example shows how the GSSContext interface gets used by the initiating peer. It walks through the whole lifecycle: creating the object, setting the flags you want, establishing the context, checking the actual context flags, doing per-message operations on application data, and finally deleting the context ๐Ÿ’–

GSSManager mgr = GSSManager.getInstance();

// start by creating the name for a service entity
GSSName targetName = mgr.createName("service@host",
                GSSName.NT_HOSTBASED_SERVICE);

// create a context using default credentials for the above entity
// and the implementation specific default mechanism
GSSContext context = mgr.createContext(targetName,
                null,   /* default mechanism */
                null,   /* default credentials */
                GSSContext.INDEFINITE_LIFETIME);

// set desired context options - all others are false by default
context.requestConf(true);
context.requestMutualAuth(true);
context.requestReplayDet(true);
context.requestSequenceDet(true);

// establish a context between peers - using byte arrays
byte []inTok = new byte[0];

try {
        do {
                byte[] outTok = context.initSecContext(inTok, 0,
                                                  inTok.length);

                // send the token if present
                if (outTok != null)
                        sendToken(outTok);

                // check if we should expect more tokens
                if (context.isEstablished())
                        break;

                // another token expected from peer
                inTok = readToken();

        } while (true);

} catch (GSSException e) {
        print("GSSAPI error: " + e.getMessage());
}


// display context information
print("Remaining lifetime in seconds = " + context.getLifetime());
print("Context mechanism = " + context.getMech().toString());
print("Initiator = " + context.getSrcName().toString());
print("Acceptor = " + context.getTargName().toString());

if (context.getConfState())
        print("Confidentiality security service available");

if (context.getIntegState())
        print("Integrity security service available");

// perform wrap on an application supplied message, appMsg,
// using QOP = 0, and requesting privacy service
byte [] appMsg ...

MessageProp mProp = new MessageProp(0, true);

byte []tok = context.wrap(appMsg, 0, appMsg.length, mProp);

if (mProp.getPrivacy())
        print("Message protected with privacy.");

sendToken(tok);


// release the local-end of the context
context.dispose();

6.4.2. Static Constants โœจ

public static final int DEFAULT_LIFETIME

This is a lifetime constant for the default context lifetime. This value must be set to 0 ๐Ÿ“

public static final int INDEFINITE_LIFETIME

This is a lifetime constant for indefinite context lifetime. In Java, this value must be set to the maximum integer value, which is Integer.MAX_VALUE ๐ŸŒˆ


6.4.3. initSecContext ๐Ÿงš

public byte[] initSecContext(byte inputBuf[], int offset, int len)
                throws GSSException

The context initiator calls this to kick off the context creation process. It's basically the stream-based method, except the token buffers are byte arrays instead of stream objects ๐Ÿซถ This method might return an output token that your application has to send to the peer, so the peer can process it with the accept call. Usually you'd send it by calling flush() on an OutputStream that wraps the connection between the two peers ๐Ÿšฟ You can call isEstablished() to check whether context establishment is finished for this peer. If it returns "false", more tokens are expected to be passed into initSecContext(). Heads up, it's possible for initSecContext() to return a token for the peer and for isEstablished() to return "true" too. That means the token still needs to go to the peer, but the local end of the context is now fully established ๐Ÿฆ‹

After context establishment is complete, you can check the available context options with the get methods ๐Ÿ”

Parameters:

  • inputBuf: Token generated by the peer. This parameter is ignored on the first call.
  • offset: The offset within the inputBuf where the token begins.
  • len: The length of the token within the inputBuf (starting at the offset).

6.4.3.1. Example Code ๐Ÿ’…

// Create a new GSSContext implementation object.
// GSSContext wrapper implements interface GSSContext.
GSSContext context = mgr.createContext(...);


byte []inTok = new byte[0];

try {

        do {
                byte[] outTok = context.initSecContext(inTok, 0,
                                        inTok.length);

                // send the token if present
                if (outTok != null)
                        sendToken(outTok);


                // check if we should expect more tokens
                if (context.isEstablished())
                        break;

                // another token expected from peer
                inTok = readToken();
        } while (true);

} catch (GSSException e) {
        print("GSSAPI error: " + e.getMessage());
}

6.4.4. initSecContext ๐ŸŒธ

public int initSecContext(InputStream inStream,
                OutputStream outStream) throws GSSException

The context initiator calls this to kick off the context creation process. It's equivalent to the byte array based method ๐ŸŽ€ This method might write an output token to the outStream, which your application has to send to the peer for processing by the accept call. Usually you'd do that by calling flush() on an OutputStream wrapping the connection between the two peers ๐Ÿšฟ You can call isEstablished() to see if context establishment is done for this peer. If it returns "false", more tokens are expected to be supplied to the initSecContext method. Same deal as before: initSecContext() can return a token for the peer and isEstablished() can return "true" at the same time. The token still has to go to the peer, but the local end is now fully established โœจ

GSS-API authentication tokens have a definitive start and end. Each invocation of this method tries to read one of these tokens, and it may block on the stream if only part of the token is available โณ

Once context establishment is complete, you can check the available context options with the get methods ๐Ÿ”

Parameters:

  • inStream: Contains the token generated by the peer. This parameter is ignored on the first call.
  • outStream: Output stream where the output token will be written. During the final stage of context establishment, there may be no bytes written.

6.4.4.1. Example Code ๐Ÿ’–

This sample code just shows the token exchange during the context establishment phase. Most Java apps are expected to use custom Input and Output stream implementations that wrap their communication routines ๐Ÿงƒ For example, a simple read on the application InputStream, when called by the Context, might cause a token to be read from the peer. And a simple flush() on the application OutputStream might send a previously written token to the peer ๐Ÿ“ค

// Create a new GSSContext implementation object.

// GSSContext wrapper implements interface GSSContext.
GSSContext context = mgr.createContext(...);

// use standard java.io stream objects
ByteArrayOutputStream os = new ByteArrayOutputStream();
ByteArrayInputStream is = null;


try {

        do {
                context.initSecContext(is, os);

                // send token if present
                if (os.size() > 0)
                        sendToken(os);

                // check if we should expect more tokens
                if (context.isEstablished())
                        break;

                // another token expected from peer
                is = recvToken();

        } while (true);

} catch (GSSException e) {
        print("GSSAPI error: " + e.getMessage());
}

6.4.5. acceptSecContext ๐Ÿ’Œ

public byte[] acceptSecContext(byte inTok[], int offset, int len)
                throws GSSException

okay so the context acceptor calls this whenever a token comes in from the peer ๐Ÿ“ฉ It's basically the stream version, except the token buffers are plain byte arrays instead of stream objects ๐ŸŽ€

This method may return an output token that the application will need to send to the peer, so the peer can process it with the init call. ๐Ÿฆ‹

A null return value means no token needs to go to the peer ๐Ÿ™…โ€โ™€๏ธ You can call isEstablished() to check whether context establishment is finished for this peer. If isEstablished() returns "false", it's giving "send me more tokens" ๐Ÿฅบ

Heads up, it's possible for acceptSecContext() to return a token for the peer and for isEstablished() to return "true" too. That means the token still has to be sent, but your local end of the context is now fully set up ๐ŸŒธ

Once context establishment is done, you can check the available context options with the get methods โœจ

Parameters:

  • inTok: the token the peer generated.
  • offset: where the token starts inside inTok.
  • len: the length of the token inside inTok, counting from the offset.

6.4.5.1. Example Code ๐Ÿ’…

// acquire server credentials
GSSCredential server = mgr.createCredential(...);

// create acceptor GSS-API context from the default provider
GSSContext context = mgr.createContext(server, null);

try {
        do {
                byte [] inTok = readToken();

                byte []outTok = context.acceptSecContext(inTok, 0,
                                        inTok.length);

                // possibly send token to peer
                if (outTok != null)
                        sendToken(outTok);

                // check if local context establishment is complete
                if (context.isEstablished())
                        break;
        } while (true);

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

6.4.6. acceptSecContext ๐ŸŒˆ

public void acceptSecContext(InputStream inStream,
                OutputStream outStream) throws GSSException

Same energy as the byte array method, just with streams ๐Ÿซถ The context acceptor calls this when a token arrives from the peer. It may write an output token to the outStream, and the application has to send that to the peer so the peer's initSecContext method can process it. Usually the app does this by calling flush() on an OutputStream that wraps the connection between the two peers ๐Ÿ”ฅ

isEstablished() tells you whether context establishment is complete for this peer. A "false" there means more tokens are still expected by this method ๐Ÿ‘€

Same deal as before: acceptSecContext() can return a token for the peer while isEstablished() also returns "true". The token still needs to go to the peer, but the local end is fully established now โœจ

GSS-API authentication tokens have a clear start and end ๐Ÿงš Each invocation of this method tries to read one of them, and it may block on the stream if only part of the token is there yet ๐Ÿ™ˆ

After context establishment, you can check the context options with the get methods ๐Ÿ’–

Parameters:

  • inStream: contains the token generated by the peer.
  • outStream: the output stream where the output token gets written. During the final stage of context establishment, there may be no bytes written at all ๐Ÿ“

6.4.6.1. Example Code ๐ŸŽ€

This sample code just shows the token exchange during context establishment. Most Java apps are expected to use custom Input and Output stream implementations that wrap the communication routines ๐Ÿง For example, a plain read on the app's InputStream, when the Context calls it, might read a token from the peer. A plain flush() on the app's OutputStream might send a token you already wrote out to the peer ๐Ÿ’œ

// acquire server credentials
GSSCredential server = mgr.createCredential(...);

// create acceptor GSS-API context from the default provider
GSSContext context = mgr.createContext(server, null);

// use standard java.io stream objects
ByteArrayOutputStream os = new ByteArrayOutputStream();
ByteArrayInputStream is = null;

try {
        do {

                is = recvToken();

                context.acceptSecContext(is, os);

                // possibly send token to peer
                if (os.size() > 0)
                        sendToken(os);

                // check if local context establishment is complete
                if (context.isEstablished())
                        break;
        } while (true);

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

6.4.7. isEstablished ๐Ÿฆ‹

public boolean isEstablished()

This is the check you use during context establishment to see the state of the context ๐Ÿ” It returns "true" if this is a fully established context on the caller's side and no more tokens are needed from the peer. Call it after initSecContext() or acceptSecContext() when no GSSException gets thrown โœจ

6.4.8. dispose ๐Ÿ—‘๏ธ

public void dispose() throws GSSException

This releases any system resources and cryptographic information stored in the context object ๐Ÿงผ It also invalidates the context, so it's bye bye to that context ๐Ÿ‘‹

6.4.9. getWrapSizeLimit ๐Ÿ“

public int getWrapSizeLimit(int qop, boolean confReq,
                int maxTokenSize) throws GSSException

This returns the biggest message size that, if you hand it to the wrap method with the same confReq and qop parameters, will give you an output token no bigger than maxTokenSize bytes ๐Ÿ“ It's built for apps that talk over protocols with a maximum message size, so they can chop messages into pieces before protecting them ๐Ÿงฉ

GSS-API implementations are recommended but not required to detect invalid QOP values when getWrapSizeLimit gets called. This routine only guarantees a maximum message size. It doesn't guarantee that specific QOP values will actually be available for message protection ๐Ÿ™ƒ

If this call succeeds, that doesn't promise wrap will be able to protect a message of the computed length ๐Ÿคž That depends on system resources being available when wrap runs. Still, if the implementation has its own upper limit on message length for wrap, the implementation should not return a value bigger than that limit ๐Ÿ’…

Parameters:

  • qop: the level of protection wrap will be asked to provide.
  • confReq: whether wrap will be asked to provide privacy service.
  • maxTokenSize: the desired maximum size of the token wrap emits.

6.4.10. wrap ๐Ÿ”

public byte[] wrap(byte inBuf[], int offset, int len,
                MessageProp msgProp) throws GSSException

This applies per-message security services over the established security context ๐Ÿ’– It returns a token with a cryptographic MIC and can optionally encrypt the inBuf you give it. It does the same job as its stream counterpart, and the returned byte array holds both the MIC and the message ๐ŸŽ€

The MessageProp object gets created by the application and is used to set a QOP value, which picks the cryptographic algorithms, plus a privacy service to optionally encrypt the message ๐Ÿง The underlying mechanism might not be able to provide the privacy service. Whatever privacy service it actually provides gets set in this MessageProp object, and the caller should check that after the call returns ๐Ÿ‘€ If the mechanism can't provide the requested QOP, it throws a GSSException with the BAD_QOP code ๐Ÿ˜ญ

Some app-level protocols want to use tokens from wrap for "secure framing", so implementations should support wrapping zero-length messages ๐ŸŒธ

The application is responsible for sending the token to the peer ๐Ÿ“ฌ

Parameters:

  • inBuf: the application data to be protected.
  • offset: where the data starts inside inBuf.
  • len: the length of the data inside inBuf, starting at the offset.
  • msgProp: an instance of MessageProp the application uses to set the desired QOP and privacy state. Set the desired QOP to 0 to request the default QOP. When this method returns, this object holds the actual privacy state the underlying mechanism applied to the message ๐Ÿงš

6.4.11. wrap ๐ŸŒˆ

public void wrap(InputStream inStream, OutputStream outStream,
                MessageProp msgProp) throws GSSException

This lets you apply per-message security services over the established security context โœจ It produces a token with a cryptographic MIC and can optionally encrypt the message in inStream. The outStream ends up holding both the MIC and the message ๐Ÿ’œ

Just like the byte array version, the MessageProp object is created by the application and sets the QOP value and the privacy service ๐Ÿ’… The mechanism might not be able to provide the privacy service, so it sets the actual privacy service it does provide in this MessageProp object. The caller should query that after the call returns ๐Ÿ™ˆ If the mechanism can't provide the requested QOP, it throws a GSSException with the BAD_QOP code ๐Ÿ’€

Again, some app-level protocols want "secure framing" with tokens from wrap, so implementations should support wrapping zero-length messages ๐Ÿซถ

The application is responsible for sending the token to the peer ๐Ÿฆ‹

Parameters:

  • inStream: the input stream containing the application data to be protected.
  • outStream: the output stream the protected message gets written to. The application is responsible for sending this to the other peer, which processes it in its unwrap method.
  • msgProp: an instance of MessageProp the application uses to set the desired QOP and privacy state. Set the desired QOP to 0 to request the default QOP. When this method returns, this object holds the actual privacy state the underlying mechanism applied to the message ๐Ÿ“

6.4.12. unwrap ๐ŸŽ€

public byte [] unwrap(byte[] inBuf, int offset, int len,
                MessageProp msgProp) throws GSSException

Okay so this is the peer app's move ๐Ÿ’… It processes tokens that came out of wrap, and it's basically the same vibe as the stream version ๐Ÿซถ It hands back the message the peer gave to wrap and checks the embedded MIC along the way ๐Ÿ”ฅ

The MessageProp object gets created by the application, and the mechanism uses it to report stuff back, like the QOP, whether confidentiality was applied, and other supplementary message state info โœจ

Some app-level protocols want to use wrap tokens for "secure framing" ๐Ÿงš So implementations should support wrapping and unwrapping zero-length messages too ๐ŸŒธ

Parameters:

  • inBuf: the GSS-API wrap token received from the peer ๐Ÿ’Œ
  • offset: where the token starts inside inBuf ๐Ÿ“
  • len: how long the token is inside inBuf, counting from the offset ๐Ÿ“
  • msgProp: when the method returns, this object holds the applied QOP, the privacy state of the message, and the supplementary info from 4.12.3 about whether the token was a duplicate, old, out of sequence or arriving after a gap ๐Ÿ‘€

6.4.13. unwrap ๐Ÿฆ‹

public void unwrap(InputStream inStream, OutputStream outStream,
                MessageProp msgProp) throws GSSException

Same energy as the byte array one, just with streams ๐ŸŒŠ It's the peer's unwrap, it spits out the message you gave to wrap, and it verifies the embedded MIC while it's at it ๐Ÿ’œ

The MessageProp object is made by the app, and the mechanism fills it in with info like the QOP, whether confidentiality was applied, and other supplementary message state info ๐Ÿ“

Secure framing is a whole thing for some protocols, so implementations should support wrapping and unwrapping zero-length messages as well ๐ŸŒˆ

Parameters:

  • inStream: the input stream holding the GSS-API wrap token received from the peer ๐Ÿ“ฅ
  • outStream: the output stream where the application message gets written ๐Ÿ“ค
  • msgProp: when the method returns, this object holds the applied QOP, the privacy state of the message, and the supplementary info from 4.12.3 about whether the token was a duplicate, old, out of sequence or arriving after a gap ๐Ÿ‘€

6.4.14. getMIC ๐Ÿ”

public byte[] getMIC(byte []inMsg, int offset, int len,
                MessageProp msgProp) throws GSSException

Okay so getMIC returns a token with a cryptographic MIC for your message, which you then send to the peer ๐Ÿ’– Here's the tea: unlike wrap, which tucks the whole user message inside the token, getMIC only puts the MIC in the output token ๐Ÿซฃ It does the same job as the stream version โœจ

Privacy can only be applied through wrap, so don't go looking for it here ๐Ÿ™…โ€โ™€๏ธ

Secure framing again ๐Ÿงš Some app protocols want MICs from tokens made by getMIC, so implementations should support deriving MICs from zero-length messages too ๐Ÿ’…

Parameters:

  • inMsg: the message to generate the MIC over ๐Ÿ’Œ
  • offset: where the token starts inside inMsg ๐Ÿ“
  • len: how long the token is inside inMsg, starting at the offset ๐Ÿ“
  • msgProp: an instance of MessageProp the application uses to pick the QOP it wants. Set the QOP to 0 in msgProp to ask for the default QOP. You can also pass null for msgProp to get the default QOP, which is honestly the same thing ๐Ÿ“

6.4.15. getMIC ๐ŸŒธ

public void getMIC(InputStream inStream, OutputStream outStream,
                MessageProp msgProp) throws GSSException

This one makes a MIC token for your message to send to the peer, just like the byte array version ๐Ÿฆ‹ Same deal as before: getMIC only produces the MIC in the output token, and wrap is the one that actually wraps the message ๐ŸŽ€ It's identical in functionality to the byte array counterpart ๐Ÿ’œ

Reminder bestie: privacy only happens through wrap ๐Ÿ™ˆ

Zero-length messages again, because secure framing is iconic ๐Ÿ‘‘ Implementations should support deriving MICs from zero-length messages โœจ

Parameters:

  • inStream: the input stream with the message to generate the MIC over ๐Ÿ“ฅ
  • outStream: the output stream where the GSS-API output token gets written ๐Ÿ“ค
  • msgProp: an instance of MessageProp the application uses to set the QOP it wants. Set the QOP to 0 in msgProp to request the default QOP. Or pass null for msgProp to request the default QOP ๐Ÿซถ

6.4.16. verifyMIC ๐Ÿ”Ž

public void verifyMIC(byte []inTok, int tokOffset, int tokLen,
                byte[] inMsg, int msgOffset, int msgLen,
                MessageProp msgProp) throws GSSException

This checks the cryptographic MIC in the token against the message you gave it ๐Ÿ•ต๏ธโ€โ™€๏ธ It's the same as the stream version in terms of what it does ๐Ÿ’…

The MessageProp object is created by the app, and the mechanism uses it to tell you stuff like the QOP, which shows how strong the protection was, plus other supplementary message state info ๐ŸŒˆ

For secure framing, implementations should support calculating and verifying MICs over zero-length messages too ๐Ÿงš

Parameters:

  • inTok: the token from the peer's getMIC method ๐ŸŽ
  • tokOffset: where the token starts inside inTok ๐Ÿ“
  • tokLen: how long the token is inside inTok, starting at the offset ๐Ÿ“
  • inMsg: the application message to verify the cryptographic MIC over ๐Ÿ’Œ
  • msgOffset: where the message starts inside inMsg ๐Ÿ“
  • msgLen: how long the message is inside inMsg, starting at the offset ๐Ÿ“
  • msgProp: when the method returns, this object holds the applied QOP and the supplementary info from 4.12.3 about whether the token was a duplicate, old, out of sequence or arriving after a gap. The confidentiality state gets set to "false" ๐Ÿ™ƒ

6.4.17. verifyMIC ๐Ÿ’œ

public void verifyMIC(InputStream tokStream, InputStream msgStream,
                MessageProp msgProp) throws GSSException

Stream edition of the verify call ๐ŸŒŠ It does the same job as the byte array counterpart: it checks the cryptographic MIC in the token against the message ๐Ÿซถ

The app makes the MessageProp object, and the mechanism uses it to report the QOP (the strength of protection applied to the message) and other supplementary message state info โœจ

Secure framing once more ๐ŸŽ€ Implementations should support calculating and verifying MICs over zero-length messages โœจ

Parameters:

  • tokStream: the input stream with the token generated by the peer's getMIC method ๐Ÿ“ฅ
  • msgStream: the input stream with the application message to verify the cryptographic MIC over ๐Ÿ“ฅ
  • msgProp: when the method returns, this object holds the applied QOP and the supplementary info from 4.12.3 about whether the token was a duplicate, old, out of sequence or arriving after a gap. The confidentiality state gets set to "false" ๐Ÿ™ƒ

6.4.18. export ๐Ÿงณ

public byte [] export() throws GSSException

This is for sharing the work between multiple processes ๐Ÿ‘ฏโ€โ™€๏ธ You'll usually see it used by the context-acceptor. Picture an app where one process gets the incoming connection requests and accepts the security contexts, then hands the established context off to one or more other processes for the message exchange ๐Ÿฆ‹

This method deactivates the security context and makes an interprocess token. When that token goes into the byte array constructor of the GSSContext interface in another process, the context comes back to life over there ๐Ÿ”„ Only one instance of a given context can be active at any time. If the context exporter tries to access the exported context afterward, it'll fail ๐Ÿ™…โ€โ™€๏ธ

The implementation might limit which processes can import the interprocess token, based on local security policy or on implementation decisions. For example, some implementations only let contexts move between processes running under the same account, or processes in the same process group ๐Ÿ“

The interprocess token can hold security-sensitive stuff, like cryptographic keys ๐Ÿ˜ญ Mechanisms are encouraged either to keep that sensitive info out of interprocess tokens, or to encrypt the token before it's returned to the app. But in a typical GSS-API implementation, that might not be possible. So the app has to protect the interprocess token carefully, and make sure any process the token gets passed to is trustworthy ๐Ÿ”

Okay bestie, this one's serious. Protect that interprocess token like it owes you money, and only hand it to processes you actually trust ๐Ÿ’€๐Ÿ”

6.4.19. requestMutualAuth ๐Ÿค

public void requestMutualAuth(boolean state) throws GSSException

This sets the request state of the mutual authentication flag for the context ๐Ÿ’… It only works before the context creation process begins, and only for the initiator ๐ŸŽฌ

Parameters:

  • state: a boolean for whether mutual authentication should be requested during context establishment โœ…

6.4.20. requestReplayDet ๐Ÿ”

public void requestReplayDet(boolean state) throws GSSException

This sets the request state of the replay detection service for the context ๐Ÿ›ก๏ธ Same rules: it's only valid before the context creation process begins, and only for the initiator ๐Ÿ™Œ

Parameters:

  • state: a boolean for whether replay detection is wanted over the established context ๐Ÿ”

6.4.21. requestSequenceDet ๐Ÿ”ข

public void requestSequenceDet(boolean state) throws GSSException

This sets the request state for the sequence checking service of the context ๐Ÿ“‹ It's only valid before the context creation process begins, and only for the initiator ๐Ÿงญ

Parameters:

  • state: a boolean for whether sequence detection is wanted over the established context ๐Ÿ”ข

6.4.22. requestCredDeleg ๐ŸŽŸ๏ธ

public void requestCredDeleg(boolean state) throws GSSException

This sets the request state for the credential delegation flag for the context ๐Ÿซก Once again, it's only valid before the context creation process begins, and only for the initiator ๐Ÿ‘‘

Parameters:

  • state: a boolean for whether credential delegation is wanted ๐ŸŽ€

6.4.23. requestAnonymity โœจ

public void requestAnonymity(boolean state) throws GSSException

okay so this one is how you ask for anonymous support over the context ๐Ÿ™ˆ bestie, it is ONLY valid before the context creation process even starts, and only the initiator can call it. no take-backs once the handshake is going ๐Ÿ’…

Parameters:

  • state: a boolean saying whether anonymity support is requested.

6.4.24. requestConf ๐ŸŽ€

public void requestConf(boolean state) throws GSSException

this is you asking for confidentiality service over the context ๐Ÿ” same rules apply: only before context creation begins, and only the initiator gets to ask.

Parameters:

  • state: a boolean saying whether confidentiality services should be requested for the context.

6.4.25. requestInteg ๐Ÿฆ‹

public void requestInteg(boolean state) throws GSSException

requesting integrity services over the context, so nobody gets to quietly mess with your data ๐Ÿซถ again, only valid before context creation starts, and only for the initiator.

Parameters:

  • state: a boolean saying whether integrity services should be requested for the context.

6.4.26. requestLifetime โณ

public void requestLifetime(int lifetime) throws GSSException

this sets how long you want the context to last, measured in seconds โญ only valid before context creation begins, and only for the initiator. if you want forever-ish, use GSSContext.INDEFINITE_LIFETIME, and if you're happy with the usual, use GSSContext.DEFAULT_LIFETIME ๐Ÿ’œ

Parameters:

  • lifetime: the desired context lifetime in seconds.

6.4.27. setChannelBinding ๐Ÿ”—

public void setChannelBinding(ChannelBinding cb) throws GSSException

this sets the channel bindings you want used during context establishment ๐ŸŒธ it's only valid before context creation begins.

Parameters:

  • cb: the channel bindings to be used.

6.4.28. getCredDelegState ๐Ÿ‘‘

public boolean getCredDelegState()

this one returns the state of the delegated credentials for the context, and it's giving honesty ๐Ÿ’… before establishment is finished, or when isProtReady returns "false", you get the desired state. after that, you get the actual state over the established context.

6.4.29. getMutualAuthState ๐Ÿซถ

public boolean getMutualAuthState()

returns the state of the mutual authentication option for the context โœจ same deal as before: before establishment completes, or while isProtReady returns "false", it's the desired state. otherwise it tells you what's actually happening over the established context.

6.4.30. getReplayDetState ๐Ÿ“

public boolean getReplayDetState()

returns the state of the replay detection option for the context ๐Ÿ™ˆ before establishment completes, or while isProtReady returns "false", it gives you the desired state. otherwise it's the real deal over the established context.

6.4.31. getSequenceDetState ๐Ÿงš

public boolean getSequenceDetState()

returns the state of the sequence detection option for the context ๐Ÿ’– same pattern: desired state before establishment completes or while isProtReady is "false", actual state after that.

6.4.32. getAnonymityState ๐ŸŒˆ

public boolean getAnonymityState()

returns "true" if this is an anonymous context ๐Ÿ•ถ๏ธ before establishment completes, or while isProtReady returns "false", it's the desired state. otherwise it shows the actual state over the established context.

6.4.33. isTransferable ๐Ÿšš

public boolean isTransferable() throws GSSException

returns "true" if the context can be handed off to other processes using the export method ๐Ÿ“ฆ this call is only valid on fully established contexts, so wait till it's ready, bestie.

6.4.34. isProtReady ๐Ÿ”ฅ

public boolean isProtReady()

returns "true" if per-message operations can be applied over the context โœจ some mechanisms let you do per-message stuff before the context is fully established, and when this says "true", the get methods start returning the actual context state instead of the desired one. main character energy ๐Ÿ‘‘

6.4.35. getConfState ๐Ÿ”

public boolean getConfState()

returns the confidentiality service state over the context ๐ŸŽ€ before establishment completes, or while isProtReady returns "false", it's the desired state. otherwise it tells you the actual state over the established context.

6.4.36. getIntegState ๐Ÿ›ก๏ธ

public boolean getIntegState()

returns the integrity service state over the context ๐Ÿ’œ before establishment completes, or while isProtReady returns "false", you get the desired state. after that, it reports the actual state over the established context.

6.4.37. getLifetime โณ

public int getLifetime()

returns the context lifetime in seconds ๐ŸŒธ before establishment completes, or while isProtReady returns "false", you get the desired lifetime. otherwise it tells you how much lifetime is left for the context.

6.4.38. getSrcName ๐Ÿชช

public GSSName getSrcName() throws GSSException

returns the name of the context initiator ๐Ÿ’– this call is only valid after the context is fully established, or once isProtReady returns "true". it is guaranteed to return an MN, which is so reliable I'm obsessed ๐Ÿ˜ญ

6.4.39. getTargName ๐ŸŽฏ

public GSSName getTargName() throws GSSException

returns the name of the context target (acceptor) ๐Ÿฆ‹ only valid after the context is fully established, or once isProtReady returns "true". and yes, it's guaranteed to return an MN too ๐Ÿ’…

6.4.40. getMech ๐Ÿงฉ

public Oid getMech() throws GSSException

returns the mechanism oid for this context โœจ you're allowed to call it before the context is fully established, but in the negotiated mechanism case, the mechanism returned might change between calls. plot twist energy ๐ŸŒˆ

6.4.41. getDelegCred ๐Ÿ“œ

public GSSCredential getDelegCred() throws GSSException

returns the delegated credential object on the acceptor's side ๐Ÿ‘‘ to check whether delegated credentials are actually available, call getDelegCredState first. this call is only valid on fully established contexts.

6.4.42. isInitiator ๐Ÿงญ

public boolean isInitiator() throws GSSException

returns "true" if this is the initiator of the context ๐Ÿš€ this call is only valid after the context creation process has started.


6.5. public class MessageProp ๐Ÿ’Œ

public class MessageProp

okay this is a utility class the per-message GSSContext methods use to pass along per-message properties ๐ŸŽ€

When you use it with the GSSContext interface's wrap and getMIC methods, you create an instance to say which QOP you want, and whether you want confidentiality services applied to the data you hand over (that's wrap only). if you want the default QOP, just use 0 for QOP ๐Ÿ“

When you use it with the unwrap and verifyMIC methods of the GSSContext interface, the instance tells you which QOP was applied and what confidentiality services were on the message you gave it. with verifyMIC, the confidentiality state is always "false" ๐Ÿ™ˆ once these methods return, the object also holds any supplementary status values for the token you just processed. those can flag old tokens, out of sequence tokens, gap tokens, or duplicate tokens. so basically it's giving detective vibes ๐Ÿ”

6.5.1. Constructors ๐Ÿ—๏ธ

public MessageProp(boolean privState)

this constructor sets QOP to 0, which means you're asking for the default QOP ๐Ÿ’–

Parameters:

  • privState: the desired privacy state. "true" means privacy, and "false" means integrity only.
public MessageProp(int qop, boolean privState)

this constructor sets the values for the QOP and the privacy state all in one go ๐ŸŒธ

Parameters:

  • qop: the desired QOP. use 0 to request a default QOP.
  • privState: the desired privacy state. "true" means privacy, and "false" means integrity only.

6.5.2. getQOP ๐Ÿ”ข

public int getQOP()

retrieves the QOP value ๐Ÿ’œ

6.5.3. getPrivacy ๐Ÿ”’

public boolean getPrivacy()

retrieves the privacy state ๐ŸŒˆ

6.5.4. getMinorStatus ๐Ÿงพ

public int getMinorStatus()

retrieves the minor status that the underlying mechanism might have set ๐Ÿฆ‹

6.5.5. getMinorString ๐Ÿ“

public String getMinorString()

returns a string explaining the mechanism-specific error code ๐Ÿ’… null gets returned when no mechanism error code has been set.

6.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.

6.5.7. setPrivacy ๐Ÿ”

public void setPrivacy(boolean privState)

sets the privacy state ๐Ÿซถ

Parameters:

  • privState: the privacy state to set.

6.5.8. isDuplicateToken ๐Ÿ‘ฏ

public boolean isDuplicateToken()

returns "true" if this is a duplicate of an earlier token ๐Ÿ™ˆ

6.5.9. isOldToken โŒ›

public boolean isOldToken()

returns "true" if the token's validity period has expired ๐Ÿ’€

6.5.10. isUnseqToken ๐Ÿ”€

public boolean isUnseqToken()

returns "true" if a later token has already been processed ๐Ÿงš

6.5.11. isGapToken ๐Ÿ•ณ๏ธ

public boolean isGapToken()

returns "true" if an expected per-message token was not received ๐Ÿ˜ญ

6.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 โœจ the application doesn't use it. the GSS implementation uses it to pass this information back to the caller of a per-message context method ๐ŸŽ

Parameters:

  • duplicate: "true" if the token was a duplicate of an earlier token, "false" otherwise.
  • old: "true" if the token's validity period has expired, "false" otherwise.
  • unseq: "true" if a later token has already been processed, "false" otherwise.
  • gap: "true" if one or more predecessor tokens have not yet been successfully processed, "false" otherwise.
  • minorStatus: the integer minor status code that the underlying mechanism wants to set.
  • minorString: the textual representation of the minorStatus value.

6.6. public class ChannelBinding ๐Ÿ”—

public class ChannelBinding

ngl this is the important one ๐Ÿฅบ the GSS-API lets callers provide their own channel binding information ๐Ÿ’– channel bindings make peer entity authentication stronger during context establishment. they let GSS-API callers tie the establishment of the security context to things like addresses, or to application-specific data ๐ŸŒˆ

The caller who starts the security context has to work out the right channel binding values and set them in the GSSContext object ๐ŸŽฏ the acceptor has to provide an identical binding, so it can check that the tokens it receives have the correct channel-related characteristics. it has to match exactly, bestie ๐Ÿซถ

Using channel bindings is optional in GSS-API โœจ and since channel-binding information can be sent inside context establishment tokens, applications should not use confidential data as channel-binding components. > don't put secrets in there, babe, they travel in the tokens ๐Ÿšจ

6.6.1. Constructors โœจ

Okay so this first constructor is the main one ๐Ÿ’… It makes a ChannelBinding with actual address info and data in it. Any field the app doesn't want to set can just be null ๐Ÿ™ˆ

public ChannelBinding(InetAddress initAddr, InetAddress acceptAddr,
                byte[] appData)

Creates a ChannelBinding object with user supplied address information and data. null values can be used for any fields which the application does not want to specify.

Parameters:

  • initAddr: The address of the context initiator. A null value can be supplied to indicate that the application does not want to set this value.
  • acceptAddr: The address of the context acceptor. A 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. A null value can be supplied to indicate that the application does not want to set this value.

The second one is the simpler sibling ๐ŸŽ€

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.

6.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.

6.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.

6.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.

6.6.5. equals ๐Ÿ’œ

public boolean equals(Object obj)

Returns true if two channel bindings match. Quick heads up, 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 to compare with.

6.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. Their structure and encoding is defined in ISOIEC-8824 and ISOIEC-8825. For example, the Oid representation of 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.

6.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.

6.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").

6.7.3. equals ๐Ÿฆ‹

public boolean equals(Object Obj)

Returns true if the two Oid objects represent the same oid value. Same deal as before, 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 Oid object to compare with.

6.7.4. getDER ๐ŸŒธ

public byte[] getDER()

Returns the full ASN.1 DER encoding for this oid object, which includes the tag and length.

6.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.

6.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 implementers 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 also maps those 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 ๐ŸŒ

6.8.1. Static Constants ๐Ÿ‘‘

All valid major GSS-API error code values are declared as constants in this class. Here they all are:

  • public static final int BAD_BINDINGS: Channel bindings mismatch error.
  • public static final int BAD_MECH: Unsupported mechanism requested error.
  • public static final int BAD_NAME: Invalid name provided error.
  • public static final int BAD_NAMETYPE: Name of unsupported type provided error.
  • public static final int BAD_STATUS: Invalid status code error - this is the default status value.
  • public static final int BAD_MIC: Token had invalid integrity check error.
  • public static final int CONTEXT_EXPIRED: Specified security context expired error.
  • public static final int CREDENTIALS_EXPIRED: Expired credentials detected error.
  • public static final int DEFECTIVE_CREDENTIAL: Defective credential error.
  • public static final int DEFECTIVE_TOKEN: Defective token error.
  • public static final int FAILURE: General failure, unspecified at GSS-API level.
  • public static final int NO_CONTEXT: Invalid security context error.
  • public static final int NO_CRED: Invalid credentials error.
  • public static final int BAD_QOP: Unsupported QOP value error.
  • public static final int UNAUTHORIZED: Operation unauthorized error.
  • public static final int UNAVAILABLE: Operation unavailable error.
  • public static final int DUPLICATE_ELEMENT: Duplicate credential element requested error.
  • public static final int NAME_NOT_MN: Name contains multi-mechanism elements error.
  • public static final int DUPLICATE_TOKEN: The token was a duplicate of an earlier token. This is a fatal error code that may occur during context establishment. It is not used to indicate supplementary status values. The MessageProp object is used for that purpose.
  • public static final int OLD_TOKEN: The token's validity period has expired. This is a fatal error code that may occur during context establishment. It is not used to indicate supplementary status values. The MessageProp object is used for that purpose.
  • public static final int UNSEQ_TOKEN: A later token has already been processed. This is a fatal error code that may occur during context establishment. It is not used to indicate supplementary status values. The MessageProp object is used for that purpose.
  • public static final int GAP_TOKEN: An expected per-message token was not received. This is a fatal error code that may occur during context establishment. It is not used to indicate supplementary status values. The MessageProp object is used for that purpose.

6.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.

6.8.3. getMajor ๐ŸŽ€

public int getMajor()

Returns the major code representing the GSS error code that caused this exception to be thrown.

6.8.4. getMinor ๐Ÿฆ‹

public int getMinor()

Returns the mechanism error code that caused this exception. The minor code is set by the underlying mechanism. A value of 0 indicates that the mechanism error code is not set.

6.8.5. getMajorString ๐ŸŒธ

public String getMajorString()

Returns a string explaining the GSS major error code causing this exception to be thrown.

6.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.

6.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.

6.8.8. toString ๐Ÿงš

public String toString()

Returns a textual representation of both the major and minor status codes.

6.8.9. getMessage ๐ŸŒˆ

public String getMessage()

Returns a detailed message of this exception. It overrides Throwable.getMessage. It is customary in Java to use this method to obtain exception information.


7. Sample Applications ๐ŸŽ€โœจ

7.1. Simple GSS Context Initiator ๐Ÿ’–

Okay so this is the client side, bestie ๐ŸŽ€ It's a partial sketch of a simple client that acts as a GSS context initiator, and it shows how to use the Java bindings for the GSS-API from Generic Security Service API Version 2 : Java bindings. It assumes a GSS-API implementation that supports the mechanism it needs is there as a library package (org.ietf.jgss), either in the standard JRE or in the CLASSPATH the app sets up ๐Ÿงš

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 (ie. 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

7.2. Simple GSS Context Acceptor โœจ

Now the server side, and this one is giving main character energy ๐Ÿ‘‘ It's a partial sketch of a simple server that acts as a GSS context acceptor, and it uses the same Java bindings from Generic Security Service API Version 2 : Java bindings. Same deal as before: it assumes a GSS-API implementation that supports the mechanisms it needs is present as a library package (org.ietf.jgss), either in the standard JRE or in the CLASSPATH ๐Ÿซถ

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 (ie. 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

8. Security Considerations ๐Ÿ”

okay bestie, security time, and this part is lowkey important ๐Ÿ˜ญ The Java language security model lets platform providers set policy-based, fine-grained access control over any resource an app wants. When a Java security manager is in play (like with applets running in browsers, but not only that), the application code is sandboxed by default ๐Ÿง

The people who run the platform JRE decide which permissions, if any, get granted to code from different codebases. So the administrator needs to know about any special requirements the GSS provider has for system resources. For example, a Kerberos provider might want to open a network connection to the KDC to get initial credentials. That's not allowed inside the sandbox unless the administrator has granted the permission. And the granting and checking of permissions happens transparently to the application, which is outside the scope of this document ๐Ÿฆ‹

The Java language lets administrators pre-configure a list of security service providers in the <JRE>/lib/security/java.security file. At runtime, the system checks these providers in order of preference when it's looking for security-related services. Apps can modify this list through methods in the "Security" class in the "java.security" package. BUT these changes would be visible across the entire JVM and affect all code running in it, so this operation isn't available in the sandbox and needs special permissions. So when a GSS application has special needs that a particular security provider meets, 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 an "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.)
โš ๏ธ Read the security part carefully, babe. Option 1 is a JVM-wide change that needs permissions, and option 2 is scoped to one GSSManager and needs none. Choose wisely ๐Ÿ’…

9. Acknowledgments ๐Ÿซถ

this proposed API builds on earlier work from the IETF's CAT WG, as outlined in both RFC 2743 and RFC 2744. A lot of the conceptual definitions, implementation directions, and explanations come straight from those documents ๐Ÿ“š

big thanks to Mike Eisler, Lin Ling, Ram Marti, Michael Saltz and other members of Sun's development team for their helpful input, comments and suggestions ๐Ÿ’œ We'd also love to thank Joe Salowey and Michael Smith for their insightful ideas and suggestions that helped shape this document โœจ


10. Bibliography ๐Ÿ“–

here are the references, complete with all their details ๐ŸŽ€

[GSSAPIv2]        Linn, J., "Generic Security Service Application
                  Program Interface, Version 2", RFC 2078, January
                  1997.

[GSSAPIv2-UPDATE] Linn, J., "Generic Security Service Application
                  Program Interface, Version 2, Update 1", RFC 2743,
                  January 2000.

[GSSAPI-Cbind]    Wray, J., "Generic Security Service API Version 2 :
                  C-bindings", RFC 2744, January 2000.

[KERBV5]          Linn, J., "The Kerberos Version 5 GSS-API
                  Mechanism", RFC 1964, June 1996.

[SPKM]            Adams, C., "The Simple Public-Key GSS-API
                  Mechanism", RFC 2025, October 1996.

11. Authors' Addresses ๐ŸŒธ

if you want to send comments about this memo, address them to:

<cat-ietf@mit.edu>

the authors, in their own words:

Jack Kabat
ValiCert, Inc.
339 N. Bernardo Avenue
Mountain View, CA
94043, USA

Phone: +1-650-567-5496
EMail: jackk@valicert.com


Mayank Upadhyay
Sun Microsystems, Inc.
901 San Antonio Road, MS CUP02-102
Palo Alto, CA 94303

Phone: +1-408-517-5956
EMail: mdu@eng.sun.com

the legal bit, kept complete and word for word so nothing gets lost in translation ๐Ÿงพ

Copyright (C) The Internet Society (2000).  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.

Acknowledgement ๐Ÿ“

funding for the RFC Editor function is currently provided by the Internet Society ๐Ÿ’œโœจ

๐Ÿ“ฆ where this page comes from