RFC 2744
Generic Security Service API Version 2 : C-bindings
Okay bestie, RFC 2744 is here and it's giving security API realness πβ¨
This one is called Generic Security Service API Version 2 : C-bindings π. It was written by J. Wray over at Iris Associates, and it's dated January 2000. It's on the Standards Track, so it's an actual standards doc and not just vibes π . It obsoletes RFC 1509, which means this is the glow-up version that replaces it π¦. The Network Working Group is the crew that put it out πΈ.
Status of This Memo
Okay so this section is the official "what is this doc" bit π§. It says this memo specifies an Internet standards track protocol for the Internet community, and it's asking for discussion and suggestions for improvements π«Ά. If you want to know where this protocol stands, check the current edition of the "Internet Official Protocol Standards" (STD 1) π. Distribution of this memo is unlimited, so share it with everyone π.
Copyright Notice
Copyright (C) The Internet Society (2000). All Rights Reserved. π
Abstract
Okay the abstract is giving summary of the whole vibe β¨. This doc specifies C language bindings for Version 2, Update 1 of the Generic Security Service Application Program Interface (GSS-API) π₯. The language-independent, conceptual version of GSS-API is described in RFC-2743 [GSSAPI] π. This memo obsoletes RFC-1509 and makes specific incremental changes based on implementation experience and liaison requests π. So it's intended that this memo, or a successor version of it, will become the basis for later progression of the GSS-API specification on the standards track π.
The Generic Security Service Application Programming Interface gives security services to its callers, and it's meant to run on top of a variety of underlying cryptographic mechanisms π¦. Usually, GSS-API callers are application protocols that get security enhancements by calling the services GSS-API provides π . The GSS-API lets a caller application authenticate a principal identity tied to a peer application, delegate rights to a peer, and apply security services like confidentiality and integrity on a per-message basis π. It's literally the whole security toolkit, bestie π.
1. Introduction β¨
Okay so the intro is where it all starts π. The Generic Security Service Application Programming Interface [GSSAPI] gives security services to 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 the GSS-API, and I am obsessed with how clean they are π:
a) The application gets a set of credentials that it can use to 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 it might be running under πΈ.
b) A pair of communicating applications sets up a joint security context using their credentials π₯. The security context is a pair of GSS-API data structures holding shared state information, which is required so that per-message security services can be provided π§ . Examples of state that might be shared between applications as part of a security context are cryptographic keys and message sequence numbers π. When the context gets established, the context initiator is authenticated to the responder, and the initiator may require that the responder is authenticated in turn π€. 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 called delegation, and it's done by creating a set of credentials that are similar to the ones the initiating application uses, but that the responder can use π¦.
To set up and keep the shared information that makes up the security context, certain GSS-API calls will return a token data structure π. A token is an opaque data type that may contain cryptographically protected data π. The caller of such a GSS-API routine is responsible for sending the token to the peer application, encapsulated if necessary in an application-application protocol π. When the peer application receives such a token, it should pass it to a corresponding GSS-API routine, which will decode the token, extract the information, and update the security context state accordingly π .
c) Per-message services are invoked to apply either:
integrity and data origin authentication, or confidentiality, integrity and data origin authentication, to application data. GSS-API treats that application data as arbitrary octet-strings π. An application sending a message it wants to protect will call the appropriate GSS-API routine (gss_get_mic or gss_wrap) to apply protection, specifying the right security context, and then send the resulting token to the receiving application π. The receiver passes the received token (and, for data protected by gss_get_mic, the accompanying message-data) to the matching decoding routine (gss_verify_mic or gss_unwrap) to remove the protection and validate the data β
.
d) At the end of a communications session (which may stretch across several transport connections), each application calls a GSS-API routine to delete the security context π. Multiple contexts may also be used, either one after another or at the same time, within a single communications association, depending on what the applications choose π«Ά.
2. GSS-API Routines π
This section lists the routines that make up the GSS-API and gives a quick description of what each routine is for π. The detailed descriptions are listed in alphabetical order in section 5 π.
Here are the credential-management routines πͺͺ:
Table 2-1 GSS-API Credential-management Routines
Routine Section Function
------- ------- --------
gss_acquire_cred 5.2 Assume a global identity; Obtain
a GSS-API credential handle for
pre-existing credentials.
gss_add_cred 5.3 Construct credentials
incrementally
gss_inquire_cred 5.21 Obtain information about a
credential
gss_inquire_cred_by_mech 5.22 Obtain per-mechanism information
about a credential.
gss_release_cred 5.27 Discard a credential handle.
Here are the context-level routines π§:
Table 2-2 GSS-API Context-Level Routines
Routine Section Function
------- ------- --------
gss_init_sec_context 5.19 Initiate a security context with
a peer application
gss_accept_sec_context 5.1 Accept a security context
initiated by a
peer application
gss_delete_sec_context 5.9 Discard a security context
gss_process_context_token 5.25 Process a token on a security
context from a peer application
gss_context_time 5.7 Determine for how long a context
will remain valid
gss_inquire_context 5.20 Obtain information about a
security context
gss_wrap_size_limit 5.34 Determine token-size limit for
gss_wrap on a context
gss_export_sec_context 5.14 Transfer a security context to
another process
gss_import_sec_context 5.17 Import a transferred context
Here are the per-message routines π:
Table 2-3 GSS-API Per-message Routines
Routine Section Function
------- ------- --------
gss_get_mic 5.15 Calculate a cryptographic message
integrity code (MIC) for a
message; integrity service
gss_verify_mic 5.32 Check a MIC against a message;
verify integrity of a received
message
gss_wrap 5.33 Attach a MIC to a message, and
optionally encrypt the message
content;
confidentiality service
gss_unwrap 5.31 Verify a message with attached
MIC, and decrypt message content
if necessary.
And the name manipulation routines π·οΈ:
Table 2-4 GSS-API Name manipulation Routines
Routine Section Function
------- ------- --------
gss_import_name 5.16 Convert a contiguous string name
to internal-form
gss_display_name 5.10 Convert internal-form name to
text
gss_compare_name 5.6 Compare two internal-form names
gss_release_name 5.28 Discard an internal-form name
gss_inquire_names_for_mech 5.24 List the name-types supported by
the specified mechanism
gss_inquire_mechs_for_name 5.23 List mechanisms that support the
specified name-type
gss_canonicalize_name 5.5 Convert an internal name to an MN
gss_export_name 5.13 Convert an MN to export form
gss_duplicate_name 5.12 Create a copy of an internal name
Last but not least, the miscellaneous routines π :
Table 2-5 GSS-API Miscellaneous Routines
Routine Section Function
------- ------- --------
gss_add_oid_set_member 5.4 Add an object identifier to
a set
gss_display_status 5.11 Convert a GSS-API status code
to text
gss_indicate_mechs 5.18 Determine available underlying
authentication mechanisms
gss_release_buffer 5.26 Discard a buffer
gss_release_oid_set 5.29 Discard a set of object
identifiers
gss_create_empty_oid_set 5.8 Create a set containing no
object identifiers
gss_test_oid_set_member 5.30 Determines whether an object
identifier is a member of a set.
Okay so individual GSS-API implementations can augment these routines by providing extra mechanism-specific routines if the required functionality isn't available from the generic forms π§©. Applications are encouraged to use the generic routines wherever possible, on portability grounds π«Ά.
3. Data Types and Calling Conventions π
The following conventions are used by the GSS-API C-language bindings π:
3.1. Integer types π’
GSS-API uses the following integer data type:
OM_uint32 32-bit unsigned integer
Where a guaranteed minimum bit-count matters, this portable data type is used by the GSS-API routine definitions π
. Individual GSS-API implementations will include appropriate typedef definitions to map this type onto a built-in data type β¨. If the platform supports the X/Open xom.h header file, the OM_uint32 definition contained in it should be used. The GSS-API header file in Appendix A has logic that detects the prior inclusion of xom.h, so it won't try to re-declare OM_uint32 π. If the X/Open header file isn't available on the platform, the GSS-API implementation should use the smallest natural unsigned integer type that provides at least 32 bits of precision πΈ.
Okay that's a wrap on the first chunk, bestie! ππ More parts are coming, so stay tuned π¦β¨
3.2. String and similar data β¨
Lots of GSS-API routines pass around contiguous octet-strings π§΅, and all of that data moves between the GSS-API and the caller as a gss_buffer_t. It's a pointer to a buffer descriptor with two fields: length, which is the total number of bytes in the datum, and value, which points at the actual datum:
typedef struct gss_buffer_desc_struct {
size_t length;
void *value;
} gss_buffer_desc, *gss_buffer_t;
When a GSS-API routine hands data back to the app through the gss_buffer_t conventions, the GSS-API routine does the allocating π
. The app can free that storage by calling gss_release_buffer. The gss_buffer_desc object itself is always the app's job to allocate, and unused gss_buffer_desc objects can be set to GSS_C_EMPTY_BUFFER πΈ.
3.2.1. Opaque data types
Some multi-word data items are opaque π. Neither the GSS-API nor the caller cares what's inside them, so their internal structure has no significance to either side. Two examples: the input_token parameter of gss_init_sec_context (opaque to the caller) and the input_message parameter of gss_wrap (opaque to the GSS-API). Opaque data goes between the GSS-API and the app using the gss_buffer_t datatype.
3.2.2. Character strings
Some multi-word data items can be treated as plain ISO Latin-1 character strings π. For example, the printable strings you pass to gss_import_name through input_name_buffer. A few GSS-API routines also return character strings. All of these travel between the app and the GSS-API implementation using gss_buffer_t, which points to a gss_buffer_desc object.
When a gss_buffer_desc describes a printable string, the length field should only count the printable characters π. A trailing NUL character should NOT be included in the length count, and neither the GSS-API implementation nor the application should assume there's an uncounted trailing NUL hiding in there π.
3.3. Object Identifiers π¦
Some GSS-API procedures take parameters of type gss_OID, which is an Object Identifier. It's a type holding ISO-defined, tree-structured values, and the caller uses it to pick an underlying security mechanism and to specify namespaces π³. A gss_OID looks like this:
typedef struct gss_OID_desc_struct {
OM_uint32 length;
void *elements;
} gss_OID_desc, *gss_OID;
The elements field points to the first byte of an octet string containing the ASN.1 BER encoding of the value portion of the normal BER TLV encoding of the gss_OID. The length field holds the number of bytes in that value. For example, the gss_OID for {iso(1) identified-organization(3) icd-ecma(12) member-company(2) dec(1011) cryptoAlgorithms(7) DASS(5)} is the DASS X.509 authentication mechanism π. Its length is 7, and its elements field points to seven octets with these octal values: 53,14,2,207,163,7,5.
GSS-API implementations should provide constant gss_OID values so apps can request any supported mechanism. Apps are encouraged to accept the default mechanism anyway, for portability reasons π«Ά. gss_OID values should also be provided so apps can specify particular name types (see section 3.10). Apps should treat gss_OID_desc values returned by GSS-API routines as read-only, and in particular the app should not try to deallocate them with free() π«. The gss_OID_desc datatype is equivalent to the X/Open OM_object_identifier datatype[XOM].
3.4. Object Identifier Sets πΈ
Some GSS-API procedures take parameters of type gss_OID_set. This type holds one or more object identifiers (section 2.3) π. A gss_OID_set looks like this:
typedef struct gss_OID_set_desc_struct {
size_t count;
gss_OID elements;
} gss_OID_set_desc, *gss_OID_set;
The count field is the number of OIDs in the set. The elements field points to an array of gss_OID_desc objects, and each one describes a single OID. gss_OID_set values are used to name the mechanisms GSS-API supports, to request specific mechanisms, and to show which mechanisms a given credential supports β¨.
Every OID set returned to the app by GSS-API is a dynamic object. That covers the gss_OID_set_desc itself, the set's "elements" array, and the "elements" array of each member OID, all of which are dynamically allocated. This storage must be deallocated by the app using the gss_release_oid_set() routine π§Ή.
3.5. Credentials π
A credential handle is a caller-opaque atomic datum that identifies a GSS-API credential data structure πͺͺ. It's represented by the caller-opaque type gss_cred_id_t, which should be implemented as a pointer or an arithmetic type. If you go with a pointer implementation, you have to make sure two gss_cred_id_t values can be compared with the == operator.
GSS-API credentials can hold mechanism-specific principal authentication data for multiple mechanisms π. A GSS-API credential is made up of a set of credential-elements, and each element applies to one mechanism. A credential may contain at most one credential-element for each supported mechanism. A credential-element identifies the data one mechanism needs to authenticate one principal. Conceptually, it holds two credential-references that describe the actual mechanism-specific authentication data: one for initiating contexts and one for accepting them. For mechanisms that don't distinguish between acceptor and initiator credentials, both references point to the same underlying mechanism-specific authentication data.
Credentials describe a set of mechanism-specific principals and give their holder the power to act as any of those principals π. All principal identities asserted by a single GSS-API credential should belong to the same entity, though enforcing that is an implementation-specific matter. The GSS-API doesn't hand the actual credentials to applications. Instead, a credential handle identifies a particular credential, which is held internally by GSS-API. The combination of a GSS-API credential handle and a mechanism identifies the principal whose identity the credential will assert when used with that mechanism π.
The gss_init_sec_context and gss_accept_sec_context routines let you pass GSS_C_NO_CREDENTIAL as their credential handle parameter π. That special handle means the app wants to act as a default principal. Each GSS-API implementation is free to decide what that default behavior looks like for its mechanism, but the following default behavior for these routines is recommended for portability:
gss_init_sec_context
- 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
- 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
- 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
- A user-configurable default identity should be used.
gss_accept_sec_context
- 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
- If the mechanism can determine the identity of the target principal by examining the context-establishment token, 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
- 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
- A user-configurable default identity shall be used.
The point of all these rules is to let both the initiator and the acceptor establish security contexts using default behavior wherever that's possible π§. Apps that request default behavior are likely to be more portable across mechanisms and platforms than apps that use gss_acquire_cred to ask for one specific identity π.
3.6. Contexts π«§
The gss_ctx_id_t datatype holds a caller-opaque atomic value that identifies one end of a GSS-API security context. It should be implemented as a pointer or an arithmetic type. If you pick a pointer type, you should make sure two gss_ctx_id_t values can be compared with the == operator.
A security context keeps state information about each end of a peer communication, including cryptographic state π.
3.7. Authentication tokens πͺ
A token is a caller-opaque type that GSS-API uses to keep the context data structures at each end 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 the peer mechanism at the other end to use. Encapsulating the token (if required) and transferring it is the job of the peer applications π¦. Tokens pass between the GSS-API and the application using the gss_buffer_t conventions.
3.8. Interprocess tokens π§©
Some GSS-API routines are meant to move data between processes in multi-process programs πββοΈ. These routines use a caller-opaque octet-string that the GSS-API generates in one process for use by the GSS-API in another process. The calling application is responsible for carrying these tokens between processes in whatever OS-specific way it uses.
GSS-API implementors are encouraged to keep sensitive information out of interprocess tokens or to cryptographically protect them. Even so, many implementations won't be able to avoid putting key material or other sensitive data inside them π.
So it's the application's responsibility to make sure interprocess tokens are protected in transit, and that they're only transferred to processes that are trustworthy π‘οΈ. An interprocess token passes between the GSS-API and the application using the gss_buffer_t conventions.
3.9. Status values β¨
okay so every GSS-API routine hands back two separate status values to tell the caller what happened: GSS status codes and Mechanism status codes π
3.9.1. GSS status codes π
GSS-API routines return GSS status codes as their OM_uint32 function value. These codes flag errors that have nothing to do with which underlying mechanism is doing the security work π§ The errors you can see through a GSS status code come in two flavours: generic API routine errors (the ones defined in the GSS-API spec itself) or calling errors (the ones specific to these language bindings) π¦
one GSS status code can carry a single fatal generic API error from the routine and a single calling error. On top of that, extra status info can get tucked into the supplementary info field by setting bits in it β¨
here's how the 32 bits get split up π
MSB LSB
|------------------------------------------------------------|
| Calling Error | Routine Error | Supplementary Info |
|------------------------------------------------------------|
Bit 31 24 23 16 15 0
so if a routine gives back a GSS status code whose upper 16 bits aren't zero, the call failed π if the calling error field is non-zero, the app that made the call was doing it wrong (rude, but fixable) π the calling errors are listed in table 5-1. if the routine error field is non-zero, the routine failed for one of the routine-specific reasons in table 5-2. and whether the upper 16 bits say pass or fail, the routine can still drop extra info into the supplementary info field. what each bit means is in table 5-3 π
Table 3-1 Calling Errors
Name Value in field Meaning
---- -------------- -------
GSS_S_CALL_INACCESSIBLE_READ 1 A required input parameter
could not be read
GSS_S_CALL_INACCESSIBLE_WRITE 2 A required output parameter
could not be written.
GSS_S_CALL_BAD_STRUCTURE 3 A parameter was malformed
Table 3-2 Routine Errors
Name Value in field Meaning
---- -------------- -------
GSS_S_BAD_MECH 1 An unsupported mechanism
was requested
GSS_S_BAD_NAME 2 An invalid name was
supplied
GSS_S_BAD_NAMETYPE 3 A supplied name was of an
unsupported type
GSS_S_BAD_BINDINGS 4 Incorrect channel bindings
were supplied
GSS_S_BAD_STATUS 5 An invalid status code was
supplied
GSS_S_BAD_MIC GSS_S_BAD_SIG 6 A token had an invalid MIC
GSS_S_NO_CRED 7 No credentials were
supplied, or the
credentials were
unavailable or
inaccessible.
GSS_S_NO_CONTEXT 8 No context has been
established
GSS_S_DEFECTIVE_TOKEN 9 A token was invalid
GSS_S_DEFECTIVE_CREDENTIAL 10 A credential was invalid
GSS_S_CREDENTIALS_EXPIRED 11 The referenced credentials
have expired
GSS_S_CONTEXT_EXPIRED 12 The context has expired
GSS_S_FAILURE 13 Miscellaneous failure (see
text)
GSS_S_BAD_QOP 14 The quality-of-protection
requested could not be
provided
GSS_S_UNAUTHORIZED 15 The operation is forbidden
by local security policy
GSS_S_UNAVAILABLE 16 The operation or option is
unavailable
GSS_S_DUPLICATE_ELEMENT 17 The requested credential
element already exists
GSS_S_NAME_NOT_MN 18 The provided name was not a
mechanism name
Table 3-3 Supplementary Status Bits
Name Bit Number Meaning
---- ---------- -------
GSS_S_CONTINUE_NEEDED 0 (LSB) Returned only by
gss_init_sec_context or
gss_accept_sec_context. The
routine must be called again
to complete its function.
See routine documentation for
detailed description
GSS_S_DUPLICATE_TOKEN 1 The token was a duplicate of
an earlier token
GSS_S_OLD_TOKEN 2 The token's validity period
has expired
GSS_S_UNSEQ_TOKEN 3 A later token has already been
processed
GSS_S_GAP_TOKEN 4 An expected per-message token
was not received
the routine docs also mention GSS_S_COMPLETE, which is just zero πΈ it's the "all good, no API errors, no extra bits" value β¨
here's a fun twist: every GSS_S_xxx symbol is a whole OM_uint32 status code, not just a little bitfield value π€― like, GSS_S_BAD_NAMETYPE (that's 3 in the routine error field) actually equals 3<<16. there are three macros, GSS_CALLING_ERROR(), GSS_ROUTINE_ERROR() and GSS_SUPPLEMENTARY_INFO(), and each one takes a GSS status code and strips out everything except its own field. so GSS_ROUTINE_ERROR throws away the calling errors and supplementary info, leaving only the routine errors π whatever those macros spit out can be compared directly against a GSS_S_xxx symbol of the matching type π
there's also GSS_ERROR(), which gives a non-zero value if the status code shows a calling or routine error, and zero otherwise. and every macro GSS-API defines evaluates its argument(s) exactly once π«Ά
a GSS-API implementation can choose to signal calling errors in a platform-specific way, either instead of or on top of the routine value. but routine errors and supplementary info should come back through major status values only π
finally, GSS_S_FAILURE is the catch-all for when the underlying mechanism hit an error that doesn't have a specific GSS status code. the mechanism-specific status code is where you'll find the juicy details π₯
3.9.2. Mechanism-specific status codes π¦
GSS-API routines also return a minor_status parameter, which spills the tea on specialized errors coming from the underlying security mechanism π it can hold one mechanism-specific error, represented as an OM_uint32 value β¨
minor_status is always set by a GSS-API routine, even when the routine returns a calling error or one of the generic API errors listed above as fatal. most of the other output parameters might stay unset in those cases though π
now, output parameters that are supposed to hand back pointers to storage the routine allocated are a whole different vibe. those must always be set by the routine, even if there's an error π the routine can set the returned parameter to NULL to say "no storage was actually allocated," and any length field tied to those pointers (like the one in a gss_buffer_desc structure) should also be set to zero in those cases π
3.10. Names β¨
okay so a name is basically how we identify a person or entity π¦, and GSS-API's whole job here is checking that the name actually belongs to whoever is claiming it. no cap, that's the main character energy π
Different authentication mechanisms can use different namespaces for identifying their principals, so GSS-API's naming support is kinda complex in multi-mechanism environments (or even in some single-mechanism environments where the underlying mechanism supports multiple namespaces) π
There are two distinct representations for names πΈ:
An internal form. This is the GSS-API "native" format, represented by the implementation-specific gss_name_t type. It's opaque to GSS-API callers π. A single gss_name_t object can hold multiple names from different namespaces, but all of those names should refer to the same entity. For example, the name returned from a call to the gss_inquire_cred routine is this kind of name when you apply it to a credential that has credential elements for multiple authentication mechanisms using different namespaces. That gss_name_t object will contain a distinct name for the entity for each authentication mechanism β¨.
For GSS-API implementations that support multiple namespaces, objects of type gss_name_t must contain sufficient information to determine the namespace each primitive name belongs to. It's giving organized π
.
Mechanism-specific contiguous octet-string forms. This is a format that can hold a single name from a single namespace. Contiguous string names are always accompanied by an object identifier specifying the namespace the name belongs to, and their format depends on the authentication mechanism that uses the name. Many (but not all!) contiguous string names are printable, so GSS-API applications can use them to talk to their users π¬.
Routines (gss_import_name and gss_display_name) convert names between contiguous string representations and the internal gss_name_t type. gss_import_name may support multiple syntaxes for each supported namespace, so users get the freedom to pick their preferred name representation π. gss_display_name should use an implementation-chosen printable syntax for each supported name-type.
If an application calls gss_display_name() on the internal name it got from gss_import_name(), there is no guarantee the resulting contiguous string name will be the same as the original imported string name π. Name-space identifiers don't necessarily survive unchanged after a trip through the internal name-form either. Picture a mechanism that authenticates X.500 names but does an algorithmic mapping of Internet DNS names into X.500. Its gss_import_name() might, when given a DNS name, generate 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, gss_display_name() would most likely generate a printable X.500 name instead of the original DNS name π.
The authentication process hands the context acceptor an internal name. Since that name was authenticated by a single mechanism, it contains only a single name (even if the internal name the context initiator presented to gss_init_sec_context had multiple components) π. Names like this are called internal mechanism names, or "MN"s, and the names emitted by gss_accept_sec_context() are always this type. Some applications may need MNs without wanting to take on the overhead of an authentication operation, so there's a second function, gss_canonicalize_name(), that converts a general internal name into an MN π§.
Comparing internal-form names can be done with the gss_compare_name() routine, which returns true if the two names being compared refer to the same entity. This means the application doesn't need to understand the syntaxes of all the printable names a given GSS-API implementation might support, which is so relieving π«Ά. Since GSS-API assumes all primitive names inside a given internal name refer to the same entity, gss_compare_name() can return true if the two names have at least one primitive name in common. If the implementation knows about equivalence relationships between names from different namespaces, it may also successfully compare internal names that have no overlapping primitive elements π₯.
When you're working with large access control lists, calling gss_import_name() and gss_compare_name() on every name in the ACL can be prohibitive π©. So GSS-API defines a special form of the contiguous string name that can be compared directly (e.g. with memcmp()). Contiguous names suitable for comparison are generated by the gss_export_name() routine, which requires an MN as input. Exported names can be re-imported by gss_import_name(), and the resulting internal name will also be an MN. The gss_OID constant GSS_C_NT_EXPORT_NAME identifies the "export name" type, and the value of this constant is given in Appendix A π. Structurally, an exported name object is a header containing an OID that identifies the mechanism that authenticated the name, plus a trailer containing the name itself, where the syntax of the trailer is defined by the individual mechanism specification. The precise format of an export name is defined in the language-independent GSS-API specification [GSSAPI] π
.
β οΈ Heads up, bestie: the results fromgss_compare_name()will in general be different from the results you get by callinggss_canonicalize_name()andgss_export_name()and then comparing the exported names. The first series of operations determines whether two (unauthenticated) names identify the same principal. The second determines whether a particular mechanism would authenticate them as the same principal. These two operations will in general only give the same results for MNs π.
The gss_name_t datatype should be implemented as a pointer type. To let the compiler help the application programmer by doing type-checking, the use of (void *) is discouraged π
. A pointer to an implementation-defined type is the preferred choice π.
Storage is allocated by routines that return gss_name_t values. There's a procedure, gss_release_name, that frees the storage associated with an internal-form name π§Ή.
3.11. Channel Bindings π¦
GSS-API supports the use of user-specified tags to identify a given context to the peer application π«§. These tags are meant to identify the particular communications channel that carries the context. Channel bindings are communicated to GSS-API using this structure:
typedef struct gss_channel_bindings_struct {
OM_uint32 initiator_addrtype;
gss_buffer_desc initiator_address;
OM_uint32 acceptor_addrtype;
gss_buffer_desc acceptor_address;
gss_buffer_desc application_data;
} *gss_channel_bindings_t;
The initiator_addrtype and acceptor_addrtype fields denote the type of addresses contained in the initiator_address and acceptor_address buffers. The address type should be one of the following πΈ:
GSS_C_AF_UNSPEC Unspecified address type
GSS_C_AF_LOCAL Host-local address type
GSS_C_AF_INET Internet address type (e.g. IP)
GSS_C_AF_IMPLINK ARPAnet IMP address type
GSS_C_AF_PUP pup protocols (eg BSP) address type
GSS_C_AF_CHAOS MIT CHAOS protocol address type
GSS_C_AF_NS XEROX NS address type
GSS_C_AF_NBS nbs address type
GSS_C_AF_ECMA ECMA address type
GSS_C_AF_DATAKIT datakit protocols address type
GSS_C_AF_CCITT CCITT protocols
GSS_C_AF_SNA IBM SNA address type
GSS_C_AF_DECnet DECnet address type
GSS_C_AF_DLI Direct data link interface address type
GSS_C_AF_LAT LAT address type
GSS_C_AF_HYLINK NSC Hyperchannel address type
GSS_C_AF_APPLETALK AppleTalk address type
GSS_C_AF_BSC BISYNC 2780/3780 address type
GSS_C_AF_DSS Distributed system services address type
GSS_C_AF_OSI OSI TP4 address type
GSS_C_AF_X25 X.25
GSS_C_AF_NULLADDR No address specified
Note that these symbols name address families rather than specific addressing formats πΊοΈ. For address families that have several alternative address forms, the initiator_address and acceptor_address fields must contain sufficient information to determine which address form is used. When nothing else is specified, addresses should be given in network byte-order (that is, native byte-ordering for the address family) π’.
Conceptually, GSS-API concatenates initiator_addrtype, initiator_address, acceptor_addrtype, acceptor_address and application_data to form an octet string. The mechanism calculates a MIC over this octet string and binds the MIC to the context establishment token emitted by gss_init_sec_context. The context acceptor presents the same bindings to gss_accept_sec_context, and a MIC is calculated in the same way. The calculated MIC is compared with the one found in the token, and if the MICs differ, gss_accept_sec_context returns a GSS_S_BAD_BINDINGS error and the context is not established π«. Some mechanisms may include the actual channel binding data in the token (rather than just a MIC), so applications should therefore not use confidential data as channel-binding components π€«.
Individual mechanisms may impose additional constraints on the addresses and address types that may appear in channel bindings π. For example, a mechanism may verify that the initiator_address field of the channel bindings presented to gss_init_sec_context contains the correct network address of the host system. Portable applications should therefore make sure they either provide correct information in the address fields or omit addressing information by specifying GSS_C_AF_NULLADDR as the address-types π.
3.12. Optional parameters π
Various parameters are described as optional. This means they follow a convention where a default value can be requested. The following conventions are used for omitted parameters π§. These conventions apply only to those parameters that are explicitly documented as optional.
3.12.1. gss_buffer_t types
Specify GSS_C_NO_BUFFER as a value. For an input parameter, this signifies that default behavior is requested. For an output parameter, it indicates that the information that would be returned via the parameter is not required by the application π«Ά.
3.12.2. Integer types (input)
Individual parameter documentation lists the values to be used to indicate default actions π.
3.12.3. Integer types (output)
Specify NULL as the value for the pointer π.
3.12.4. Pointer types
Specify NULL as the value πΈ.
3.12.5. Object IDs
Specify GSS_C_NO_OID as the value π¦.
3.12.6. Object ID Sets
Specify GSS_C_NO_OID_SET as the value π.
3.12.7. Channel Bindings π
Bestie, this one's short and sweet π If you don't want channel bindings, you pass GSS_C_NO_CHANNEL_BINDINGS and GSS-API gets the message that you're opting out π
ββοΈπ
4. Additional Controls π
Okay so this section is all about the extra services an initiator can ask GSS-API for while a context is being set up β¨ Each one gets requested by flipping a flag in the req_flags input parameter to gss_init_sec_context π¦
These are the OPTIONAL services that are defined so far:
- Delegation π€ - The initiator hands over rights, usually just temporarily, so the acceptor can authenticate as the initiator's agent.
- Mutual Authentication πͺ - Besides the initiator proving who it is to the context acceptor, the context acceptor SHOULD also prove who it is to the initiator.
- Replay detection π - Besides keeping messages intact,
gss_get_micandgss_wrapSHOULD add message numbers sogss_verify_micandgss_unwrapcan tell when a message got duplicated. - Out-of-sequence detection π - Besides keeping messages intact,
gss_get_micandgss_wrapSHOULD add sequencing info sogss_verify_micandgss_unwrapcan tell when a message arrived out of order. - Anonymous authentication πΆοΈ - Setting up the security context SHOULD NOT reveal the initiator's identity to the context acceptor.
Any flag bits that aren't defined yet SHOULD be ignored by GSS-API implementations when an application passes them in, and SHOULD be set to zero when the implementation hands them back to the application π§Έ
Not every mechanism supports every OPTIONAL service, and some MAY only offer certain services alongside others. π
Both gss_init_sec_context and gss_accept_sec_context tell the application which services the context actually has once establishment is done, through the ret_flags output parameter π£ In general, if a mechanism can provide a requested service, it SHOULD do so, even if other services have to be switched on to make that happen. If it can't, it SHOULD carry on without that service, and the application can abort context establishment if it decides the service was mandatory π€
Some mechanisms MAY say that a service is OPTIONAL and that implementors don't have to build it. This is usually the confidentiality service, often because of legal limits on data encryption, but it MAY apply to any service. Mechanisms like this are REQUIRED to send at least one token from acceptor to initiator during establishment whenever the initiator asks for such a service, so the initiating GSS-API can tell whether the acceptor's GSS-API supports it π
4.1. Delegation π€
GSS-API lets the initiating application control delegation with a boolean parameter to gss_init_sec_context(), which is the routine that sets up a security context β¨ Some mechanisms can't do delegation at all, and for those, the application's attempts to turn it on just get ignored π
The acceptor of a context where the initiator turned on delegation gets a credential handle through the delegated_cred_handle parameter of gss_accept_sec_context. That handle holds the delegated identity and MAY be used to start later GSS-API contexts as the initiator's agent or delegate. So if the initiator is "A" and the delegate is "B", the delegated credential MAY represent either "A" or "B acting for A", depending on the mechanism underneath π¦
Real talk, a plain yes/no isn't always enough. A mechanism might also offer controls like how long the delegation lasts, which network addresses it works from, or what tasks the delegate MAY perform π Those extra controls are outside GSS-API's scope right now. GSS-API implementations that support mechanisms with extra controls SHOULD provide extension routines so those controls can be used, maybe by changing the initiator's GSS-API credential before it's used to set up a context π οΈ
Here's the important part π¨ The simple GSS-API delegation control SHOULD always be able to override any mechanism-specific delegation controls. If the application tells gss_init_sec_context() that it doesn't want delegation, the implementation MUST NOT allow delegation to happen. This is the one exception to the rule that a mechanism MAY turn on services nobody asked for. Delegation MAY only happen when the application explicitly requests it π
4.2. Mutual authentication πͺ
Usually the context acceptor needs the initiator to authenticate itself so it can make an access-control decision before doing anything for the initiator π Sometimes the initiator also wants the acceptor to prove who it is, and GSS-API lets the initiating application ask for this mutual authentication by setting a flag when it calls gss_init_sec_context π
The initiating application finds out whether the context acceptor actually authenticated itself. Heads up, though: some mechanisms MAY not support mutual authentication, and others MAY always do it whether or not the application asks π Also, mutual authentication my be REQUIRED by some mechanisms so they can support replay or out-of-sequence detection. For those mechanisms, asking for either of those services automatically turns on mutual authentication too πΈ
4.3. Replay and out-of-sequence detection π
Once a security context is up, GSS-API MAY detect messages that were delivered out of order β¨ Either application can protect messages, by calling gss_get_mic or gss_wrap, and the peer can verify them by calling gss_verify_mic or gss_unwrap π¬
gss_get_mic computes a cryptographic MIC over an application message and returns that MIC in a token. The application SHOULD send both the token and the message to the peer, which hands them to gss_verify_mic π¦
gss_wrap computes a cryptographic MIC over an application message and puts both the MIC and the message in one token. The Application SHOULD send that token to the peer, which passes it to gss_unwrap to pull out the message and check the MIC π
Either pair of routines MAY be able to detect messages arriving out of sequence or being duplicated. When that happens, the details show up as supplementary status bits in the major status code returned by gss_verify_mic or gss_unwrap π These are the bits:
GSS_S_DUPLICATE_TOKEN- The token is a copy of one that was already received and processed. Only contexts that claim replay detection MAY set this bit π ββοΈGSS_S_OLD_TOKEN- The token is too old to tell whether it's a duplicate. A context that does out-of-sequence detection but not replay detection SHOULD always set this bit wheneverGSS_S_UNSEQ_TOKENis set. A context that does replay detection SHOULD only set it if the token is so old it can't be checked for duplication π°οΈGSS_S_UNSEQ_TOKEN- A later token has already been processed πββοΈGSS_S_GAP_TOKEN- An earlier token hasn't arrived yet π³οΈ
A mechanism doesn't need to keep a list of every token it has processed to support these codes π§ A typical mechanism might just remember the most recent "N" tokens, which is enough to spot duplicates and missing tokens among those "N" messages. If a token older than the most recent "N" shows up, it gets GSS_S_OLD_TOKEN π
4.4. Anonymous Authentication πΆοΈ
Sometimes an application wants to start authentication to verify a peer without revealing who it is π«£ Picture an app that gives access to a medical information database with unrestricted access. A client might want to verify the service so it can trust the info it gets back, but not want the service to learn its identity, maybe for privacy reasons about what it's searching for, or just to avoid getting stuck on mailing lists π§
Normally, the acceptor learns the initiator's identity as part of context establishment. Context initiators MAY ask that their identity not be revealed to the context acceptor. Lots of mechanisms don't support anonymous authentication, and for those, the request just gets ignored π An authentication token still gets generated, but the application is always told when a requested service isn't available, and it can choose to abort establishment if anonymity matters more than the other services that need the context π¦
Along with telling the application the context is anonymous (through the ret_flags outputs of gss_init_sec_context and gss_accept_sec_context), the OPTIONAL src_name output from gss_accept_sec_context and gss_inquire_context will, for these contexts, return a reserved internal-form name that the implementation defines π
When that reserved name goes to gss_display_name, it turns into a printable name that looks nothing like any valid principal name the implementation supports. It's tied to the name-type object identifier GSS_C_NT_ANONYMOUS, whose value us given in Appendix A πͺͺ The printable form SHOULD clearly imply anonymity, since it might end up in audit logs, for example π A good pick could be the string "<anonymous>", as long as no valid printable names the implementation supports can start with "<" and end with ">" π
4.5. Confidentiality π
If a context supports the confidentiality service, gss_wrap MAY be used to encrypt application messages π€« Encryption is selective, controlled by the conf_req_flag input parameter to gss_wrap β¨
4.6. Inter-process context transfer β¨
okay bestie, so GSS-API V2 has two routines, gss_export_sec_context and gss_import_sec_context π¦, that let a security context get passed between processes on a single machine π
. The most common setup 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 π. The children need access to the security context data structure that the parent made when it called gss_accept_sec_context, so they can use the per-message protection services and delete the context when the communication session ends π«Ά.
Since the context data structure holds sequencing information, sharing one between processes is generally impractical π. So GSS-API gives you gss_export_sec_context. The process that currently owns the context calls it to say it has no plans to use the context anymore, and it creates an inter-process token with the info the adopting process needs to import the context successfully π§. Once gss_export_sec_context completes successfully, GSS-API makes the original security context inaccessible to the calling process, and any context handles referring to it are no longer valid π. The originating process hands the token to the adopting process, which passes it to gss_import_sec_context, and a fresh gss_ctx_id_t gets created that is functionally identical to the original β¨.
The inter-process token may contain sensitive data from the original security context, including cryptographic keys π. Applications using inter-process tokens to transfer security contexts must take appropriate steps to protect these tokens in transit π¨.
Implementations are not required to support inter-process transfer of security contexts π€·ββοΈ. You can tell whether the ability is there when the context gets created: gss_init_sec_context or gss_accept_sec_context sets the GSS_C_TRANS_FLAG bit in their ret_flags parameter π.
4.7. The use of incomplete contexts
Some mechanisms may let the per-message services be used before context establishment is finished π. For example, a mechanism may include enough info in its initial context-level token for the context acceptor to decode messages protected with gss_wrap or gss_get_mic right away π. For a mechanism like that, the initiating application need not wait until the subsequent context-level tokens have been sent and received before invoking the per-message protection services β.
A context can provide per-message services before it's fully established if the GSS_C_PROT_READY_FLAG bit is set in the ret_flags parameter from gss_init_sec_context and gss_accept_sec_context π. If you want per-message protection on a partially-established context, check this flag before you try to invoke gss_wrap or gss_get_mic π«Ά.
5. GSS-API Routine Descriptions
Besides the explicit major status codes documented here, any routine may return GSS_S_FAILURE π₯. That means there's an implementation-specific or mechanism-specific error, and the details get reported through the minor_status parameter π.
5.1. gss_accept_sec_context
OM_uint32 gss_accept_sec_context (
OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
const gss_cred_id_t acceptor_cred_handle,
const gss_buffer_t input_token_buffer,
const gss_channel_bindings_t input_chan_bindings,
const gss_name_t *src_name,
gss_OID *mech_type,
gss_buffer_t output_token,
OM_uint32 *ret_flags,
OM_uint32 *time_rec,
gss_cred_id_t *delegated_cred_handle)
Purpose:
This is the routine that lets a remotely initiated security context between your application and a remote peer get established π. It may return an output_token that should be transferred to the peer application, which then presents it to gss_init_sec_context π¨. If no token needs to be sent, gss_accept_sec_context says so by setting the length field of the output_token argument to zero 0οΈβ£. To finish establishing the context, one or more reply tokens may be required from the peer application. If so, gss_accept_sec_context returns the status flag GSS_S_CONTINUE_NEEDED, and you should call it again when the reply token comes back from the peer, passing that token in through the input_token parameters π.
Portable applications should use the token length and return status to figure out whether a token needs to be sent or waited for π§ . So a typical portable caller should always invoke gss_accept_sec_context inside a loop, like this:
gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
do {
receive_token_from_peer(input_token);
maj_stat = gss_accept_sec_context(&min_stat,
&context_hdl,
cred_hdl,
input_token,
input_bindings,
&client_name,
&mech_type,
output_token,
&ret_flags,
&time_rec,
&deleg_cred);
if (GSS_ERROR(maj_stat)) {
report_error(maj_stat, min_stat);
};
if (output_token->length != 0) {
send_token_to_peer(output_token);
gss_release_buffer(&min_stat, output_token);
};
if (GSS_ERROR(maj_stat)) {
if (context_hdl != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&min_stat,
&context_hdl,
GSS_C_NO_BUFFER);
break;
};
} while (maj_stat & GSS_S_CONTINUE_NEEDED);
Whenever the routine returns a major status that includes GSS_S_CONTINUE_NEEDED, the context isn't fully established yet, and these rules apply to the output parameters π§:
The value returned via the time_rec parameter is undefined π«οΈ. Unless the accompanying ret_flags parameter contains the GSS_C_PROT_READY_FLAG bit (which says per-message services may be applied before a successful completion status), the value returned via the mech_type parameter may be undefined until the routine returns GSS_S_COMPLETE π―.
The GSS_C_DELEG_FLAG, GSS_C_MUTUAL_FLAG, GSS_C_REPLAY_FLAG, GSS_C_SEQUENCE_FLAG, GSS_C_CONF_FLAG, GSS_C_INTEG_FLAG and GSS_C_ANON_FLAG bits returned via ret_flags should contain the values the implementation expects would be valid if context establishment succeeded π€.
The GSS_C_PROT_READY_FLAG and GSS_C_TRANS_FLAG bits within ret_flags should show the actual state at the moment gss_accept_sec_context returns, whether or not the context is fully established π.
This requires GSS-API implementations to setGSS_C_PROT_READY_FLAGin the finalret_flagsreturned to a caller (that is, when it comes with aGSS_S_COMPLETEstatus code). Even so, applications should not rely on this behavior, since the flag wasn't defined in Version 1 of the GSS-API π ββοΈ. Instead, applications should be ready to use per-message services after a successful context establishment, based on theGSS_C_INTEG_FLAGandGSS_C_CONF_FLAGvalues π.
All other bits within the ret_flags argument should be set to zero 0οΈβ£. While the routine returns GSS_S_CONTINUE_NEEDED, the values returned via ret_flags tell you which services the implementation expects to be available from the established context π.
If the initial call to gss_accept_sec_context() fails, the implementation should not create a context object, and should leave context_handle set to GSS_C_NO_CONTEXT to show that π
ββοΈ. If a later call fails, the implementation is permitted to delete the "half-built" security context (in which case it should set context_handle to GSS_C_NO_CONTEXT). But the preferred behavior is to leave the security context, and context_handle, untouched so the application can delete it with gss_delete_sec_context π§Ή.
During context establishment, the informational status bits GSS_S_OLD_TOKEN and GSS_S_DUPLICATE_TOKEN indicate fatal errors π«. GSS-API mechanisms should always return them along with a routine error of GSS_S_FAILURE π. This pairing requirement didn't exist in version 1 of the GSS-API specification, so applications that want to run over version 1 implementations must special-case these codes π« .
Parameters:
context_handle: gss_ctx_id_t, read/modify context handle for the new context π§Ύ. SupplyGSS_C_NO_CONTEXTfor the first call, and use the value returned in subsequent calls. Oncegss_accept_sec_context()has returned a value via this parameter, resources have been assigned to the corresponding context, and the application must free them after use with a call togss_delete_sec_context()ποΈ.acceptor_cred_handle: gss_cred_id_t, read, credential handle claimed by the context acceptor πͺͺ. SpecifyGSS_C_NO_CREDENTIALto accept the context as a default principal. IfGSS_C_NO_CREDENTIALis specified but no default acceptor principal is defined,GSS_S_NO_CREDwill be returned π¬.input_token_buffer: buffer, opaque, read, the token obtained from the remote application π₯.input_chan_bindings: channel bindings, read, optional π. These are application-specified bindings that let the application securely bind channel identification information to the security context. If channel bindings aren't used, specifyGSS_C_NO_CHANNEL_BINDINGSπ.src_name: gss_name_t, modify, optional π€. This is the authenticated name of the context initiator. After use, deallocate this name by passing it togss_release_name(). If it isn't required, specifyNULLπ«‘.mech_type: Object ID, modify, optional π§¬. This is the security mechanism used. The returned OID value is a pointer into static storage and should be treated as read-only by the caller (so it doesn't need to be freed). If it isn't required, specifyNULLπ.output_token: buffer, opaque, modify, the token to be passed to the peer application π€. If the length field of the returned token buffer is 0, no token needs to be passed to the peer application β . If a non-zero length field is returned, the associated storage must be freed after use by the application with a call togss_release_buffer()π§½.
Okay so ret_flags is a bit-mask π (it's modify, and it's optional, so you can pass NULL if you don't care). Basically it's a bunch of little yes/no stickers β¨ telling you what the context can actually do. To check one, you AND your value with its symbolic name, and any bits you don't use should be zero π
.
GSS_C_DELEG_FLAG: True means delegated credentials are available through the delegated_cred_handle parameter π. False means no credentials were delegated.GSS_C_MUTUAL_FLAG: True means the remote peer asked for mutual authentication π€. False means they didn't.GSS_C_REPLAY_FLAG: True means replayed protected messages will be detected π΅οΈββοΈ. False means replayed messages won't be detected.GSS_C_SEQUENCE_FLAG: True means out-of-sequence protected messages will be detected π’. False means out-of-sequence messages won't be caught.GSS_C_CONF_FLAG: True means you can invoke confidentiality by calling gss_wrap π. False means there's no confidentiality through gss_wrap at all. It'll still do message encapsulation, data-origin authentication, and integrity, just no secrecy π.GSS_C_INTEG_FLAG: True means integrity can be invoked by calling either gss_get_mic or gss_wrap π‘οΈ. False means per-message integrity is unavailable.GSS_C_ANON_FLAG: True means the initiator doesn't want to be authenticated π», so src_name (if you asked for it) holds an anonymous internal name. False means the initiator was authenticated normally.GSS_C_PROT_READY_FLAG: True means the protection services (set by GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG) are ready as long as the major status is either GSS_S_COMPLETE or GSS_S_CONTINUE_NEEDED π¦. False means they're only ready when the major status is GSS_S_COMPLETE.GSS_C_TRANS_FLAG: True means the context can be handed off to other processes with gss_export_sec_context() π§³. False means it's not transferable.
time_rec is an Integer, modify, and optional β³. It's the number of seconds the context stays valid. Pass NULL if you don't need it.
delegated_cred_handle is a gss_cred_id_t, modify, and optional π. It's the credential handle for the credentials the initiator handed over. It only matters if deleg_flag in ret_flags is true. In that case you get an explicit handle (not GSS_C_NO_CREDENTIAL). If deleg_flag is false, gss_accept_context() sets this parameter to GSS_C_NO_CREDENTIAL. If you do get a handle, you have to release its resources yourself after use with gss_release_cred() π§Ή. Pass NULL if you don't need it.
minor_status is an Integer, and it's modify π§. It's a mechanism-specific status code.
Now the major status codes π¨:
GSS_S_CONTINUE_NEEDED: the context isn't finished yet. You need a token from the peer application, and then gss_accept_sec_context has to be called again with that token π.GSS_S_DEFECTIVE_TOKEN: the consistency checks on the input_token failed π.GSS_S_DEFECTIVE_CREDENTIAL: the consistency checks on the credential failed π ββοΈ.GSS_S_NO_CRED: the supplied credentials weren't valid for accepting a context, or the credential handle didn't point to any credentials π₯².GSS_S_CREDENTIALS_EXPIRED: the referenced credentials have expired β.GSS_S_BAD_BINDINGS: the input_token has different channel bindings than the ones you passed in through input_chan_bindings π«.GSS_S_NO_CONTEXT: the context handle you gave didn't refer to a valid context π«₯.GSS_S_BAD_SIG: the input_token contains an invalid MIC π€.GSS_S_OLD_TOKEN: the input_token was too old. This one is a fatal error during context establishment β οΈ.GSS_S_DUPLICATE_TOKEN: the input_token is valid, but it's a duplicate of one that was already processed. This one is also fatal during context establishment π―.GSS_S_BAD_MECH: the received token asked for a mechanism that the implementation or the provided credential doesn't support π§©.
5.2. gss_acquire_cred β¨
OM_uint32 gss_acquire_cred (
OM_uint32 *minor_status,
const gss_name_t desired_name,
OM_uint32 time_req,
const gss_OID_set desired_mechs,
gss_cred_usage_t cred_usage,
gss_cred_id_t *output_cred_handle,
gss_OID_set *actual_mechs,
OM_uint32 *time_rec)
Purpose:
okay so this one is how an app grabs a handle to a credential that already exists, looked up by name π no cap, the access rules are a big deal here π. GSS-API implementations MUST impose a local access-control policy on callers so that random people can't snag credentials they aren't entitled to π ββοΈ.
This is NOT a "login to the network" button π. A login would create new credentials, and this routine only gets you a handle to ones that already exist. If you need a login function, it SHOULD be defined in implementation-specific extensions to the API β¨.
If desired_name is GSS_C_NO_NAME, the call is treated as a request for a credential handle that will invoke default behavior when passed to gss_init_sec_context() (if cred_usage is GSS_C_INITIATE or GSS_C_BOTH) or gss_accept_sec_context() (if cred_usage is GSS_C_ACCEPT or GSS_C_BOTH) π§.
Mechanisms SHOULD honor the desired_mechs parameter and return a credential that is suitable to use only with the requested mechanisms π . The exception is when one underlying credential element can be shared by multiple mechanisms. In that case it is permissible for an implementation to indicate all mechanisms with which the credential element MAY be used π¦. If desired_mechs is an empty set, behavior is undefined π.
This routine is expected to be used mainly by context acceptors, since implementations are likely to provide mechanism-specific ways of getting GSS-API initiator credentials from the system login process πΈ. So some implementations MAY not support acquiring GSS_C_INITIATE or GSS_C_BOTH credentials via gss_acquire_cred for any name other than GSS_C_NO_NAME. The same goes for a name produced by applying gss_inquire_cred to a valid credential, or gss_inquire_context to an active context π.
If credential acquisition is time-consuming for a mechanism, the mechanism MAY choose to delay the actual acquisition until the credential is required (for example by gss_init_sec_context or gss_accept_sec_context) β³. Mechanism-specific implementation decisions like this SHOULD be invisible to the calling application. That means a call to gss_inquire_cred right after gss_acquire_cred MUST return valid credential data, and it MAY therefore take on the overhead of a deferred credential acquisition π«Ά.
Parameters:
desired_name gss_name_t, read
Name of principal whose credential
should be acquired
time_req Integer, read, optional
number of seconds that credentials
should remain valid. Specify GSS_C_INDEFINITE
to request that the credentials have the maximum
permitted lifetime.
desired_mechs Set of Object IDs, read, optional
set of underlying security mechanisms that
may be used. GSS_C_NO_OID_SET may be used
to obtain an implementation-specific default.
cred_usage gss_cred_usage_t, read
GSS_C_BOTH - Credentials may be used
either to initiate or accept
security contexts.
GSS_C_INITIATE - Credentials will only be
used to initiate security contexts.
GSS_C_ACCEPT - Credentials will only be used to
accept security contexts.
output_cred_handle gss_cred_id_t, modify
The returned credential handle. Resources
associated with this credential handle must
be released by the application after use
with a call to gss_release_cred().
actual_mechs Set of Object IDs, modify, optional
The set of mechanisms for which the
credential is valid. Storage associated with the
returned OID-set must be released by
the application after use with a call to
gss_release_oid_set(). Specify NULL if not
required.
time_rec Integer, modify, optional
Actual number of seconds for which the
returned credentials will remain valid. If the
implementation does not support expiration of
credentials, the value GSS_C_INDEFINITE will
be returned. Specify NULL if not required
minor_status Integer, modify
Mechanism specific status code.
Function value: GSS status code π
GSS_S_COMPLETE Successful completion
GSS_S_BAD_MECH Unavailable mechanism requested
GSS_S_BAD_NAMETYPE Type contained within desired_name parameter
is not supported
GSS_S_BAD_NAME Value supplied for desired_name parameter is ill
formed.
GSS_S_CREDENTIALS_EXPIRED The credentials could not be acquired
Because they have expired.
GSS_S_NO_CRED No credentials were found for the specified name.
5.3. gss_add_cred β¨
OM_uint32 gss_add_cred (
OM_uint32 *minor_status,
const gss_cred_id_t input_cred_handle,
const gss_name_t desired_name,
const gss_OID desired_mech,
gss_cred_usage_t cred_usage,
OM_uint32 initiator_time_req,
OM_uint32 acceptor_time_req,
gss_cred_id_t *output_cred_handle,
gss_OID_set *actual_mechs,
OM_uint32 *initiator_time_rec,
OM_uint32 *acceptor_time_rec)
Purpose
okay bestie, so gss_add_cred adds a credential-element to a credential π The element is identified by the name of the principal it belongs to. GSS-API implementations must impose a local access-control policy on callers of this routine, so unauthorized callers can't grab credential-elements they aren't entitled to π This is NOT a "login to the network" function, ngl. A login would create brand-new mechanism-specific authentication data, whereas this routine just gets you a GSS-API handle to data that already exists π
If you need a login-type function, it should be defined in implementation-specific extensions to the API.
If desired_name is GSS_C_NO_NAME, the call is treated as a request for a credential element that invokes default behavior when it's passed to gss_init_sec_context() (if cred_usage is GSS_C_INITIATE or GSS_C_BOTH) or to gss_accept_sec_context() (if cred_usage is GSS_C_ACCEPT or GSS_C_BOTH) β¨
This routine is mostly for context acceptors, since implementations usually have mechanism-specific ways to get initiator credentials from the system login process π§ So some implementations may not support acquiring GSS_C_INITIATE or GSS_C_BOTH credentials through gss_acquire_cred for any name other than GSS_C_NO_NAME. The other allowed options are a name produced by applying gss_inquire_cred to a valid credential, or by applying gss_inquire_context to an active context.
If acquiring a credential is slow for a mechanism, the mechanism may delay the real acquisition until the credential is actually needed, for example by gss_init_sec_context or gss_accept_sec_context π«Ά That kind of decision should be invisible to the calling application. So a call to gss_inquire_cred right after gss_add_cred must return valid credential data, even if that means paying the cost of the deferred acquisition.
This routine can either compose a brand-new credential containing all the elements of the original plus the newly acquired one, or just add the new element to an existing credential π If NULL is given for output_cred_handle, the new element gets added to the credential named by input_cred_handle. If a valid pointer is given, you get a new credential handle instead.
If GSS_C_NO_CREDENTIAL is passed as input_cred_handle, gss_add_cred composes a credential (and sets output_cred_handle to match) using default behavior. In other words, it does the same thing as if you had first called gss_acquire_cred() with the same usage and GSS_C_NO_NAME as desired_name to get an explicit credential handle with default behavior, passed that handle to gss_add_cred(), and then called gss_release_cred() on the first handle π
If GSS_C_NO_CREDENTIAL is passed as the input_cred_handle parameter, a non-NULL output_cred_handle must be supplied. No skipping this one, bestie π
Parameters
minor_status: Integer, modify. Mechanism-specific status code.input_cred_handle:gss_cred_id_t, read, optional. The credential that gets a new credential-element. IfGSS_C_NO_CREDENTIALis given, the routine composes the new credential from default behavior (see above). The credential handle itself isn't modified bygss_add_cred(), but the underlying credential will be modified ifoutput_credential_handleisNULL.desired_name:gss_name_t, read. The name of the principal whose credential should be acquired.desired_mech: Object ID, read. The underlying security mechanism the credential may be used with.cred_usage:gss_cred_usage_t, read. One of:GSS_C_BOTH: the credential may be used to either initiate or accept security contexts.GSS_C_INITIATE: the credential will only be used to initiate security contexts.GSS_C_ACCEPT: the credential will only be used to accept security contexts.
initiator_time_req: Integer, read, optional. The number of seconds the credential should remain valid for initiating security contexts. This argument is ignored if the composed credentials are of typeGSS_C_ACCEPT. SpecifyGSS_C_INDEFINITEto request the maximum permitted initiator lifetime.acceptor_time_req: Integer, read, optional. The number of seconds the credential should remain valid for accepting security contexts. This argument is ignored if the composed credentials are of typeGSS_C_INITIATE. SpecifyGSS_C_INDEFINITEto request the maximum permitted initiator lifetime.output_cred_handle:gss_cred_id_t, modify, optional. The returned credential handle, holding the new credential-element and every credential-element frominput_cred_handle. If a valid pointer to agss_cred_id_tis supplied,gss_add_credcreates a new credential handle containing all the elements frominput_cred_handleplus the newly acquired element. IfNULLis specified, the newly acquired element gets added to the credential identified byinput_cred_handle. The application must release any resources tied to a credential handle returned through this parameter, usinggss_release_cred()after use.actual_mechs: Set of Object IDs, modify, optional. The complete set of mechanisms the new credential is valid for. The application must free the storage for the returned OID-set after use, usinggss_release_oid_set(). SpecifyNULLif this isn't needed.initiator_time_rec: Integer, modify, optional. The actual number of seconds the returned credentials will remain valid for initiating contexts with the specified mechanism. If the implementation or mechanism doesn't support credential expiration,GSS_C_INDEFINITEis returned. SpecifyNULLif not required.acceptor_time_rec: Integer, modify, optional. The actual number of seconds the returned credentials will remain valid for accepting security contexts with the specified mechanism. If the implementation or mechanism doesn't support credential expiration,GSS_C_INDEFINITEis returned. SpecifyNULLif not required.
Function value
GSS status code:
GSS_S_COMPLETE: successful completion πGSS_S_BAD_MECH: the requested mechanism is unavailable π¬GSS_S_BAD_NAMETYPE: the type contained within thedesired_nameparameter isn't supportedGSS_S_BAD_NAME: the value supplied fordesired_nameis ill-formedGSS_S_DUPLICATE_ELEMENT: the credential already has an element for the requested mechanism with overlapping usage and validity period πGSS_S_CREDENTIALS_EXPIRED: the required credentials couldn't be added because they've expiredGSS_S_NO_CRED: no credentials were found for the specified name
5.4. gss_add_oid_set_member π¦
OM_uint32 gss_add_oid_set_member (
OM_uint32 *minor_status,
const gss_OID member_oid,
gss_OID_set *oid_set)
Purpose
so this routine adds an Object Identifier to an Object Identifier set πΈ It's meant to be used together with gss_create_empty_oid_set when you're building a set of mechanism OIDs to feed into gss_acquire_cred. The oid_set parameter has to refer to an OID-set that GSS-API created (for example, one returned by gss_create_empty_oid_set()). GSS-API makes a copy of member_oid and puts that copy into the set, growing the storage for the set's elements array if it needs to π§ The routine may add the new member anywhere within the elements array. Implementations should check that member_oid isn't already in the elements array. If it is already there, the oid_set stays unchanged, no drama π
Parameters
minor_status: Integer, modify. Mechanism-specific status code.member_oid: Object ID, read. The object identifier to be copied into the set.oid_set: Set of Object ID, modify. The set the object identifier should be inserted into.
Function value
GSS status code:
GSS_S_COMPLETE: successful completion β¨
5.5. gss_canonicalize_name β¨
OM_uint32 gss_canonicalize_name (
OM_uint32 *minor_status,
const gss_name_t input_name,
const gss_OID mech_type,
gss_name_t *output_name)
Purpose: okay bestie, this one makes a canonical mechanism name (MN) out of any internal name π¦ The MN is the name a context acceptor would get back after a successful authentication, if the initiator used the input_name in a successful gss_acquire_cred call (with an OID set whose only member is <mech_type>), followed by a gss_init_sec_context call that names <mech_type> as the authentication mechanism. It's giving consistency π
Parameters:
minor_status(Integer, modify): mechanism-specific status code πΈinput_name(gss_name_t, read): the name you want a canonical form of π§mech_type(Object ID, read): the authentication mechanism you want the canonical form for. You have to name it explicitly, because there's no default πoutput_name(gss_name_t, modify): the resulting canonical name. You have to free its storage yourself after you're done with it, usinggss_release_name()π«Ά
Function value: GSS status code
GSS_S_COMPLETE: successful completion β¨GSS_S_BAD_MECH: the mechanism you named isn't supported πGSS_S_BAD_NAMETYPE: the internal name has no elements the specified mechanism can process πGSS_S_BAD_NAME: the internal name is ill-formed π₯
5.6. gss_compare_name π
OM_uint32 gss_compare_name (
OM_uint32 *minor_status,
const gss_name_t name1,
const gss_name_t name2,
int *name_equal)
Purpose: this lets an app check whether two internal-form names point to the same entity π
Heads up: if either name is for an anonymous principal, the routines should indicate that the two names do not refer to the same identity. Anonymous means anonymous, no cap π
Parameters:
minor_status(Integer, modify): mechanism-specific status code πΈname1(gss_name_t, read): an internal-form namename2(gss_name_t, read): an internal-form namename_equal(boolean, modify):non-zeromeans the names refer to the same entity.zeromeans they refer to different entities (or, strictly speaking, the names aren't known to refer to the same identity) π
Function value: GSS status code
GSS_S_COMPLETE: successful completion β¨GSS_S_BAD_NAMETYPE: the two names are of incomparable types πGSS_S_BAD_NAME: one or both ofname1orname2is ill-formed π
5.7. gss_context_time β
OM_uint32 gss_context_time (
OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
OM_uint32 *time_rec)
Purpose: this tells you how many seconds the given context is going to stay valid for β° It's basically a countdown, bestie.
Parameters:
minor_status(Integer, modify): implementation-specific status code πΈcontext_handle(gss_ctx_id_t, read): identifies the context you want to check πtime_rec(Integer, modify): the number of seconds the context will remain valid. If it has already expired, you get zero back π
Function value: GSS status code
GSS_S_COMPLETE: successful completion β¨GSS_S_CONTEXT_EXPIRED: the context has already expired π₯ΊGSS_S_NO_CONTEXT: thecontext_handleparameter didn't identify a valid context π ββοΈ
5.8. gss_create_empty_oid_set π
OM_uint32 gss_create_empty_oid_set (
OM_uint32 *minor_status,
gss_OID_set *oid_set)
Purpose: this makes an object-identifier set with nothing in it yet π«§ You can add members later with gss_add_oid_set_member(). These routines are built for putting together sets of mechanism object identifiers to hand to gss_acquire_cred. Main character setup, honestly π
Parameters:
minor_status(Integer, modify): mechanism-specific status code πΈoid_set(Set of Object IDs, modify): the empty object identifier set. The routine allocates thegss_OID_set_descobject, and the application has to free it afterwards withgss_release_oid_set()π§Ή
Function value: GSS status code
GSS_S_COMPLETE: successful completion β¨
5.9. gss_delete_sec_context π¦
OM_uint32 gss_delete_sec_context (
OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
gss_buffer_t output_token)
Purpose: this deletes a security context. gss_delete_sec_context wipes the local data structures for that context, and it may spit out an output_token. If you pass that token to your peer's gss_process_context_token, it'll do the same cleanup on its end π§Ό If the mechanism doesn't need a token, the GSS-API should set the length field of output_token (if you gave one) to zero. After this, no more security services can be obtained through context_handle π«
Also, gss_delete_sec_context has to be able to delete "half-built" security contexts, the ones left over from an incomplete run of gss_init_sec_context()/gss_accept_sec_context() calls. Iykyk π
The output_token parameter is only kept around for compatibility with version 1 of the GSS-API. It is recommended that both peer applications call gss_delete_sec_context passing GSS_C_NO_BUFFER for output_token, which means "no token needed," and that gss_delete_sec_context just deletes the local context data structures. If an app does pass a valid buffer, mechanisms are encouraged to return a zero-length token. That means no peer action is needed and the app shouldn't transfer any token π
Parameters:
minor_status(Integer, modify): mechanism-specific status code πΈcontext_handle(gss_ctx_id_t, modify): the handle for the context you want to delete. Once it's deleted, the GSS-API sets this handle toGSS_C_NO_CONTEXTπ«‘output_token(buffer, opaque, modify, optional): a token to send to the remote application so it also deletes the context. It is recommended that apps specifyGSS_C_NO_BUFFERhere, which asks for local deletion only. If you do give a buffer, the mechanism may return a token in it. Mechanisms that only do local deletion should set the length field of this token to zero, which tells the app not to send anything to the peer π§
Function value: GSS status code
GSS_S_COMPLETE: successful completion β¨GSS_S_NO_CONTEXT: no valid context was supplied π
5.10. gss_display_name π
OM_uint32 gss_display_name (
OM_uint32 *minor_status,
const gss_name_t input_name,
gss_buffer_t output_name_buffer,
gss_OID *output_name_type)
Purpose: this gives an app a readable text version of an opaque internal-form name, just for showing to people π The syntax of a printable name is up to the GSS-API implementation, so it can look however that implementation wants πΈ
If input_name is for an anonymous principal, the implementation should return GSS_C_NT_ANONYMOUS as the output_name_type, plus a text name in output_name_buffer that's syntactically distinct from every valid printable name the implementation supports. Anon energy, but make it recognizable π
If input_name was made by calling gss_import_name with GSS_C_NO_OID as the name-type, implementations that use lazy conversion between name types may return GSS_C_NO_OID through output_name_type. Lazy but make it make sense π΄
Parameters:
minor_status(Integer, modify): mechanism-specific status code πΈinput_name(gss_name_t, read): the name you want to display π§output_name_buffer(buffer, character-string, modify): the buffer that receives the text name. The app has to free its storage afterwards withgss_release_buffer()π§Ήoutput_name_type(Object ID, modify, optional): the type of the returned name. The returnedgss_OIDpoints into static storage, so treat it as read-only and don't try to free it. Pass NULL if you don't need it π«Ά
Function value: GSS status code
GSS_S_COMPLETE: successful completion β¨GSS_S_BAD_NAME:input_namewas ill-formed π
5.11. gss_display_status
Purpose:
Okay so this one lets an app turn a GSS-API status code into text it can show a user or write to a log πβ¨ Since a single status value can mean more than one thing, you might need to call gss_display_status several times, and each call gives you one text string π§ The message_context parameter is basically the bookkeeping π¦ It tracks which messages have already been pulled out of a given status_value. You have to set message_context to 0 yourself before the first call, and then gss_display_status will hand back a non-zero value in it if there are more messages left to grab π
Also, message_context holds all the state gss_display_status needs to pull out the rest of the messages from status_value. Even when it comes back non-zero, you are not required to call again unless you actually want those extra messages πΈ Here's a snippet that pulls out every message from a status code and prints them to stderr π
OM_uint32 message_context;
OM_uint32 status_code;
OM_uint32 maj_status;
OM_uint32 min_status;
gss_buffer_desc status_string;
...
message_context = 0;
do {
maj_status = gss_display_status (
&min_status,
status_code,
GSS_C_GSS_CODE,
GSS_C_NO_OID,
&message_context,
&status_string)
fprintf(stderr,
"%.*s\n",
(int)status_string.length,
(char *)status_string.value);
gss_release_buffer(&min_status, &status_string);
} while (message_context != 0);
Parameters:
minor_status(Integer, modify): Mechanism specific status code. π§status_value(Integer, read): The status value to be converted. πstatus_type(Integer, read): Pick one of these:GSS_C_GSS_CODEmeans status_value is a GSS status code.GSS_C_MECH_CODEmeans status_value is a mechanism status code.
mech_type(Object ID, read, optional): The underlying mechanism, which is used to interpret a minor status value. SupplyGSS_C_NO_OIDto get the system default. πmessage_context(Integer, read/modify): Should be initialized to zero by the application prior to the first call. On return from gss_display_status(), a non-zero status_value parameter indicates that additional messages may be extracted from the status code via subsequent calls to gss_display_status(), passing the same status_value, status_type, mech_type, and message_context parameters. π¦status_string(buffer, character string, modify): A textual interpretation of the status_value. The storage behind this parameter must be freed by the application after use with a call to gss_release_buffer(). π§Ή
Function value: GSS status code π
GSS_S_COMPLETE: Successful completion β¨GSS_S_BAD_MECH: Indicates that translation in accordance with an unsupported mechanism type was requested πGSS_S_BAD_STATUS: The status value was not recognized, or the status type was neither GSS_C_GSS_CODE nor GSS_C_MECH_CODE. π
5.12. gss_duplicate_name
OM_uint32 gss_duplicate_name (
OM_uint32 *minor_status,
const gss_name_t src_name,
gss_name_t *dest_name)
Purpose:
Make an exact duplicate of the existing internal name src_name. π―ββοΈ The new dest_name is totally independent of src_name. That means both src_name and dest_name have to be released, and releasing one shall not affect whether the other is still valid π«Ά
Parameters:
minor_status(Integer, modify): Mechanism specific status code. π§src_name(gss_name_t, read): The internal name to be duplicated. πdest_name(gss_name_t, modify): The resultant copy of<src_name>. The storage for this name must be freed by the application after use with a call to gss_release_name(). π§Ή
Function value: GSS status code π
GSS_S_COMPLETE: Successful completion β¨GSS_S_BAD_NAME: The src_name parameter was ill-formed. π
5.13. gss_export_name
OM_uint32 gss_export_name (
OM_uint32 *minor_status,
const gss_name_t input_name,
gss_buffer_t exported_name)
Purpose:
This one makes a canonical, contiguous string version of a mechanism name (MN) π¦ It's built so you can compare two of them directly (think memcmp), which is super handy for authorization stuff, like matching entries in an access-control list π The input_name parameter must specify a valid MN, which means an internal name made by either gss_accept_sec_context or gss_canonicalize_name. No other names qualify πΈ
Parameters:
minor_status(Integer, modify): Mechanism specific status code π§input_name(gss_name_t, read): The MN to be exported πexported_name(gss_buffer_t, octet-string, modify): The canonical contiguous string form of<input_name>. The storage for this string must freed by the application after use with gss_release_buffer(). π§Ή
Function value: GSS status code π
GSS_S_COMPLETE: Successful completion β¨GSS_S_NAME_NOT_MN: The provided internal name was not a mechanism name. π«GSS_S_BAD_NAME: The provided internal name was ill-formed. πGSS_S_BAD_NAMETYPE: The internal name was of a type not supported by the GSS-API implementation. π΅
5.14. gss_export_sec_context
OM_uint32 gss_export_sec_context (
OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
gss_buffer_t interprocess_token)
Purpose:
This is for sharing the work between multiple processes π The usual setup: one process is the context-acceptor, meaning it receives incoming connection requests and accepts security contexts over them. Then it passes the established context off to one or more other processes that do the message exchange π§ gss_export_sec_context() deactivates the security context for the process that calls it, and it creates an interprocess token. When that token gets passed to gss_import_sec_context in another process, the context wakes back up in that second process β¨ Only one instance of a given context can be active at any one time. If a context exporter tries to access the exported security context after that, it will fail π ββοΈ
The implementation may limit which processes are allowed to import the interprocess token. That can come from local security policy or from implementation decisions. For instance, some implementations only let contexts be passed between processes running under the same account, or processes in the same process group π
Heads up, the interprocess token may contain security-sensitive stuff, like cryptographic keys π Mechanisms are encouraged to either keep that sensitive info out of interprocess tokens or encrypt the token before handing it back to the application. But in a typical object-library GSS-API implementation, that may not be possible. So the application must take care to protect the interprocess token and make sure any process the token gets transferred to is trustworthy π‘οΈ
If creating the interprocess token works, the implementation shall deallocate all process-wide resources tied to the security context, and set the context_handle to GSS_C_NO_CONTEXT. If an error makes it impossible to finish exporting the security context, the implementation must not return an interprocess token, and should strive to leave the security context referenced by the context_handle parameter untouched. If that's impossible, it is permissible for the implementation to delete the security context, as long as it also sets the context_handle parameter to GSS_C_NO_CONTEXT. π±
Parameters:
minor_status(Integer, modify): Mechanism specific status code π§context_handle(gss_ctx_id_t, modify): The context handle identifying the context to transfer. πinterprocess_token(buffer, opaque, modify): The token to be transferred to the target process. The storage for this token must be freed by the application after use with a call to gss_release_buffer(). π§Ή
Function value: GSS status code π
GSS_S_COMPLETE: Successful completion β¨GSS_S_CONTEXT_EXPIRED: The context has expired β°GSS_S_NO_CONTEXT: The context was invalid π«GSS_S_UNAVAILABLE: The operation is not supported. π«
5.15. gss_get_mic
OM_uint32 gss_get_mic (
OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
gss_qop_t qop_req,
const gss_buffer_t message_buffer,
gss_buffer_t msg_token)
Purpose:
This generates a cryptographic MIC for the message you hand it, then puts that MIC into a token so it can be sent to the peer application π The qop_req parameter lets you choose between several cryptographic algorithms, as long as the chosen mechanism supports them π¦
Some application-level protocols want to use tokens emitted by gss_wrap() to get "secure framing" π Because of that, implementations must support deriving MICs from zero-length messages π
Parameters:
minor_status(Integer, modify): Implementation specific status code. π§context_handle(gss_ctx_id_t, read): Identifies the context on which the message will be sent. πqop_req(gss_qop_t, read, optional): Specifies the requested quality of protection. For portability reasons, callers are encouraged to accept the default quality of protection offered by the chosen mechanism. You can do that by specifying GSS_C_QOP_DEFAULT for this parameter. If an unsupported protection strength is requested, gss_get_mic will return a major_status of GSS_S_BAD_QOP. πΈmessage_buffer(buffer, opaque, read): The message to be protected. πmsg_token(buffer, opaque, modify): The buffer to receive the token. The application must free the storage associated with this buffer after use with a call to gss_release_buffer(). π§Ή
Function value: GSS status code π
GSS_S_COMPLETE: Successful completion β¨GSS_S_CONTEXT_EXPIRED: The context has already expired β°GSS_S_NO_CONTEXT: The context_handle parameter did not identify a valid context π«GSS_S_BAD_QOP: The specified QOP is not supported by the mechanism. π ββοΈ
5.16. gss_import_name β¨
OM_uint32 gss_import_name (
OM_uint32 *minor_status,
const gss_buffer_t input_name_buffer,
const gss_OID input_name_type,
gss_name_t *output_name)
Purpose:
okay so this one takes a plain string name and turns it into the internal form π In general, the internal name you get back in output_name will NOT be an MN π
ββοΈ The one exception is when input_name_type says the string is GSS_C_NT_EXPORT_NAME. Then the internal name comes back as an MN for whichever mechanism exported it π¦
Parameters:
minor_status(Integer, modify): mechanism-specific status code πΈinput_name_buffer(buffer, octet-string, read): the buffer holding the contiguous string name you want to convert πinput_name_type(Object ID, read, optional): the OID that tells the function what kind of printable name it's looking at. You can passGSS_C_NO_OIDto use the mechanism's default printable syntax, or pass an OID the GSS-API implementation recognizes to pick a specific namespace π§output_name(gss_name_t, modify): the name in internal form. The application has to free this storage after use by callinggss_release_name()π
Function value: GSS status code
GSS_S_COMPLETE: successful completion β¨GSS_S_BAD_NAMETYPE: theinput_name_typewasn't recognized πGSS_S_BAD_NAME: theinput_nameparameter couldn't be read as a name of the specified type πGSS_S_BAD_MECH: the name type wasGSS_C_NT_EXPORT_NAME, but the mechanism inside the input name isn't supported π
5.17. gss_import_sec_context
OM_uint32 gss_import_sec_context (
OM_uint32 *minor_status,
const gss_buffer_t interprocess_token,
gss_ctx_id_t *context_handle)
Purpose:
this lets one process import a security context that a different process set up π₯ A given interprocess token can only be imported ONCE, so no double-dipping π
ββοΈ See gss_export_sec_context.
Parameters:
minor_status(Integer, modify): mechanism-specific status code πΈinterprocess_token(buffer, opaque, modify): the token the exporting process handed over πcontext_handle(gss_ctx_id_t, modify): the context handle for the newly reactivated context. The application must release the resources tied to this handle after use by callinggss_delete_sec_context()π§Ή
Function value: GSS status code
GSS_S_COMPLETE: successful completion πGSS_S_NO_CONTEXT: the token didn't contain a valid context reference π₯GSS_S_DEFECTIVE_TOKEN: the token was invalid πGSS_S_UNAVAILABLE: the operation is unavailable πGSS_S_UNAUTHORIZED: local policy stops this process from importing the context π«
5.18. gss_indicate_mechs
OM_uint32 gss_indicate_mechs (
OM_uint32 *minor_status,
gss_OID_set *mech_set)
Purpose:
this is how an application figures out which underlying security mechanisms are actually available on the system π
Parameters:
minor_status(Integer, modify): mechanism-specific status code. πΈmech_set(set of Object IDs, modify): the set of mechanisms the implementation supports. The OID set that comes back is dynamically allocated, so the caller should release it after use by callinggss_release_oid_set()π«Ά
Function value: GSS status code
GSS_S_COMPLETE: successful completion β¨
5.19. gss_init_sec_context
OM_uint32 gss_init_sec_context (
OM_uint32 *minor_status,
const gss_cred_id_t initiator_cred_handle,
gss_ctx_id_t *context_handle,\
const gss_name_t target_name,
const gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
const gss_channel_bindings_t input_chan_bindings,
const gss_buffer_t input_token
gss_OID *actual_mech_type,
gss_buffer_t output_token,
OM_uint32 *ret_flags,
OM_uint32 *time_rec )
Purpose:
okay this is the big one, bestie π¦ It kicks off establishing a security context between your app and a remote peer π
At the start, input_token should be either GSS_C_NO_BUFFER or a pointer to a gss_buffer_desc whose length field is zero πΈ
The routine might hand back an output_token, which you send over to the peer. The peer then gives it to gss_accept_sec_context. If nothing needs to be sent, gss_init_sec_context says so by setting the length field of output_token to zero π
To finish setting up the context, you might need one or more reply tokens from the peer. When that's the case, gss_init_sec_context returns a status with the supplementary info bit GSS_S_CONTINUE_NEEDED π You call it again once the reply token shows up, passing that reply in through input_token β¨
Portable apps should check the token length and the return status to figure out whether to send something or wait for something. So a typical portable caller runs gss_init_sec_context inside a loop, like this:
int context_established = 0;
gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
...
input_token->length = 0;
while (!context_established) {
maj_stat = gss_init_sec_context(&min_stat,
cred_hdl,
&context_hdl,
target_name,
desired_mech,
desired_services,
desired_time,
input_bindings,
input_token,
&actual_mech,
output_token,
&actual_services,
&actual_time);
if (GSS_ERROR(maj_stat)) {
report_error(maj_stat, min_stat);
};
if (output_token->length != 0) {
send_token_to_peer(output_token);
gss_release_buffer(&min_stat, output_token)
};
if (GSS_ERROR(maj_stat)) {
if (context_hdl != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&min_stat,
&context_hdl,
GSS_C_NO_BUFFER);
break;
};
if (maj_stat & GSS_S_CONTINUE_NEEDED) {
receive_token_from_peer(input_token);
} else {
context_established = 1;
};
};
Now, if the routine returns a major status that includes GSS_S_CONTINUE_NEEDED, the context isn't fully established yet π₯Ί That means these rules apply to the output parameters:
- The value in
time_recis undefined, unlessret_flagshas the bitGSS_C_PROT_READY_FLAGset. That bit says per-message services can be applied before a successful completion status shows up π Otherwise, the value inactual_mech_typestays undefined until the routine returnsGSS_S_COMPLETE. - The
GSS_C_DELEG_FLAG,GSS_C_MUTUAL_FLAG,GSS_C_REPLAY_FLAG,GSS_C_SEQUENCE_FLAG,GSS_C_CONF_FLAG,GSS_C_INTEG_FLAGandGSS_C_ANON_FLAGbits inret_flagsshould hold whatever values the implementation expects to be valid if context establishment succeeds. Say the app asked for delegation or anonymous auth inreq_flags, but the underlying mechanism can't offer it. Thengss_init_sec_contextshould generate a token that won't provide that service, and useret_flagsto say the service won't be supported π The app can then callgss_delete_sec_contextto abort if it can't survive without the service, or it can send the token and keep going if the service was just nice-to-have π - The
GSS_C_PROT_READY_FLAGandGSS_C_TRANS_FLAGbits inret_flagsshould show the actual state at the momentgss_init_sec_contextreturns, whether or not the context is fully established β¨ - Implementations that support per-message protection are encouraged to set
GSS_C_PROT_READY_FLAGin the finalret_flagsthey return to a caller (that is, when it comes with aGSS_S_COMPLETEstatus code). But apps shouldn't rely on this, because the flag wasn't defined in Version 1 of the GSS-API π Instead, apps should figure out which per-message services are available after successful context establishment by checking theGSS_C_INTEG_FLAGandGSS_C_CONF_FLAGvalues. - Every other bit in the
ret_flagsargument should be set to zero π§Ό
If the very first call to gss_init_sec_context() fails, the implementation should not create a context object, and should leave context_handle set to GSS_C_NO_CONTEXT to show that π If a later call fails, the implementation is permitted to delete the "half-built" security context (in which case it should set context_handle to GSS_C_NO_CONTEXT). But the preferred behavior is to leave the context alone so the application can delete it itself, using gss_delete_sec_context π«Ά
During context establishment, the informational status bitsGSS_S_OLD_TOKENandGSS_S_DUPLICATE_TOKENmean fatal errors. GSS-API mechanisms should always return them together with a routine error ofGSS_S_FAILURE. This pairing rule didn't exist in version 1 of the GSS-API spec, so apps that want to run on version 1 implementations need to special-case these codes π
Parameters:
minor_status(Integer, modify): mechanism-specific status code πΈinitiator_cred_handle(gss_cred_id_t, read, optional): the handle for the credentials you're claiming. PassGSS_C_NO_CREDENTIALto act as the default initiator principal. If there's no default initiator defined, the function returnsGSS_S_NO_CREDπcontext_handle(gss_ctx_id_t, read/modify): the context handle for the new context. PassGSS_C_NO_CONTEXTon the first call, then use the value the first call returned for continuation calls. The app must release the resources tied to this handle after use by callinggss_delete_sec_context()π§Ήtarget_name(gss_name_t, read): the name of the target π¦
okay so we're still in gss_init_sec_context land, bestie π
let's keep going with the inputs and outputs π
mech_type(OID, read, optional) π¦ this is the mechanism you want. passGSS_C_NO_OIDand you get the implementation specific default β¨req_flags(bit-mask, read) π this is where you ask for service options. every flag is its own independent thing, and the required flags should be logically-ORed together to build the bit-mask value. here's the lineup:GSS_C_DELEG_FLAGπ- True: delegate credentials to the remote peer
- False: don't delegate
GSS_C_MUTUAL_FLAGπ€- True: ask the remote peer to authenticate itself
- False: you only authenticate yourself to the remote peer
GSS_C_REPLAY_FLAGπ- True: turn on replay detection for messages protected with
gss_wraporgss_get_mic - False: don't try to detect replayed messages
- True: turn on replay detection for messages protected with
GSS_C_SEQUENCE_FLAGπ’- True: turn on detection of out-of-sequence protected messages
- False: don't try to detect out-of-sequence messages
GSS_C_CONF_FLAGπ- True: ask for the confidentiality service to be available (via
gss_wrap) - False: no per-message confidentiality service is required
- True: ask for the confidentiality service to be available (via
GSS_C_INTEG_FLAGπ§·- True: ask for the integrity service to be available (via
gss_wraporgss_get_mic) - False: no per-message integrity service is required
- True: ask for the integrity service to be available (via
GSS_C_ANON_FLAGπ- True: don't reveal the initiator's identity to the acceptor
- False: authenticate normally
time_req(Integer, read, optional) β° how many seconds you'd like the context to stay valid. pass 0 and you get a default validity period.input_chan_bindings(channel bindings, read, optional) π§ this is where the app securely binds channel identification info to the security context. if you're not using channel bindings, specifyGSS_C_NO_CHANNEL_BINDINGS.input_token(buffer, opaque, read, optional (see text)) π the token that came in from your peer app. on the initial call, supplyGSS_C_NO_BUFFER, or a pointer to a buffer holdingGSS_C_EMPTY_BUFFER.actual_mech_type(OID, modify, optional) π«Ά the mechanism that actually got used. the OID comes back as a pointer to static storage that's read-only, so the app should not try to free it. specify NULL if you don't need it.output_token(buffer, opaque, modify) πΈ the token to send to the peer app. if the length field of the returned buffer is zero, no token needs to go to the peer. the app has to free the storage for this buffer after use, by callinggss_release_buffer().ret_flags(bit-mask, modify, optional) π this tells you which service options the context actually supports. specify NULL if you don't need it. to check whether an option is supported, logically-AND the matching symbolic names with theret_flagsvalue. here are the flags:GSS_C_DELEG_FLAGπ- True: credentials were delegated to the remote peer
- False: no credentials were delegated
GSS_C_MUTUAL_FLAGπ€- True: the remote peer has authenticated itself
- False: the remote peer has not authenticated itself
GSS_C_REPLAY_FLAGπ- True: replay of protected messages will be detected
- False: replayed messages will not be detected
GSS_C_SEQUENCE_FLAGπ’- True: out-of-sequence protected messages will be detected
- False: out-of-sequence messages will not be detected
GSS_C_CONF_FLAGπ- True: the confidentiality service may be invoked by calling
gss_wrap - False: no confidentiality service (via
gss_wrap) is available.gss_wrapstill gives you message encapsulation, data-origin authentication and integrity services only
- True: the confidentiality service may be invoked by calling
GSS_C_INTEG_FLAGπ§·- True: the integrity service may be invoked by calling either
gss_get_micorgss_wrap - False: per-message integrity service is unavailable
- True: the integrity service may be invoked by calling either
GSS_C_ANON_FLAGπ- True: the initiator's identity has not been revealed, and won't be revealed if any emitted token is passed to the acceptor
- False: the initiator's identity has been, or will be, authenticated normally
GSS_C_PROT_READY_FLAGπ¦- True: the protection services (as set by
GSS_C_CONF_FLAGandGSS_C_INTEG_FLAG) are ready to use if the accompanying major status return value is eitherGSS_S_COMPLETEorGSS_S_CONTINUE_NEEDED - False: the protection services (as set by
GSS_C_CONF_FLAGandGSS_C_INTEG_FLAG) are only available if the accompanying major status return value isGSS_S_COMPLETE
- True: the protection services (as set by
GSS_C_TRANS_FLAGπ§³- True: the resulting security context may be transferred to other processes via a call to
gss_export_sec_context() - False: the security context is not transferable
- True: the resulting security context may be transferred to other processes via a call to
all other bits should be set to zero π§Ή
time_rec(Integer, modify, optional) β the number of seconds the context will stay valid. if the implementation doesn't support context expiration, you getGSS_C_INDEFINITEback. specify NULL if you don't need it.
Function value: GSS status code π£
GSS_S_COMPLETEβ successful completionGSS_S_CONTINUE_NEEDEDπ a token from the peer app is needed to finish the context, andgss_init_sec_contexthas to be called again with that tokenGSS_S_DEFECTIVE_TOKENπ the consistency checks oninput_tokenfailedGSS_S_DEFECTIVE_CREDENTIALπ the consistency checks on the credential failedGSS_S_NO_CREDπ« the supplied credentials weren't valid for context initiation, or the credential handle didn't reference any credentialsGSS_S_CREDENTIALS_EXPIREDβ the referenced credentials have expiredGSS_S_BAD_BINDINGSπ theinput_tokenhas different channel bindings from the ones given ininput_chan_bindingsGSS_S_BAD_SIGπ₯ theinput_tokenhas an invalid MIC, or a MIC that couldn't be verifiedGSS_S_OLD_TOKENπ°οΈ theinput_tokenwas too old. this is a fatal error during context establishmentGSS_S_DUPLICATE_TOKENπ― theinput_tokenis valid, but it's a duplicate of a token that was already processed. this is a fatal error during context establishmentGSS_S_NO_CONTEXTπ«₯ the supplied context handle didn't refer to a valid contextGSS_S_BAD_NAMETYPEπ·οΈ thetarget_nameparameter contained an invalid or unsupported type of nameGSS_S_BAD_NAMEπ§© thetarget_nameparameter was ill-formedGSS_S_BAD_MECHπ the specified mechanism isn't supported by the provided credential, or isn't recognized by the implementation
5.20. gss_inquire_context π β¨
OM_uint32 gss_inquire_context (
OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
gss_name_t *src_name,
gss_name_t *targ_name,
OM_uint32 *lifetime_rec,
gss_OID *mech_type,
OM_uint32 *ctx_flags,
int *locally_initiated,
int *open )
Purpose:
okay so this call is how you ask a security context what it's been up to π΅οΈββοΈ You need a handle that points at the context first, but the context doesn't have to be fully set up yet. Lowkey iconic that it works mid-handshake too πΈ
Parameters:
minor_status(Integer, modify): the mechanism-specific status code π§context_handle(gss_ctx_id_t, read): the handle that points at the security context πsrc_name(gss_name_t, modify, optional): the name of the context initiator π§- If the context was set up with anonymous authentication, and the app calling
gss_inquire_contextis the context acceptor, you get back an anonymous name. π - You have to free the storage for this name yourself after you're done, using
gss_release_name(). π§Ή - Pass NULL if you don't want it.
- If the context was set up with anonymous authentication, and the app calling
targ_name(gss_name_t, modify, optional): the name of the context acceptor π- You free this one yourself too, with
gss_release_name(). π§Ή - If the acceptor didn't authenticate itself, and the initiator didn't give a target name in its
gss_init_sec_context()call, you getGSS_C_NO_NAMEback. π - Pass NULL if you don't need it.
- You free this one yourself too, with
lifetime_rec(Integer, modify, optional): how many seconds the context stays valid β³- If the context has already expired, this comes back as zero. π
- If the implementation doesn't do context expiration at all, you get
GSS_C_INDEFINITE. βΎοΈ - Pass NULL if not required.
mech_type(gss_OID, modify, optional): the security mechanism that's providing the context π¦- The OID you get back points at static storage. Treat it as read-only. Do NOT try to free it, bestie π ββοΈ
- Pass NULL if not required.
ctx_flags(bit-mask, modify, optional): a bunch of independent flags, each one saying the context supports (or, ifctx_openis false, is expected to support) a specific service option π- If you don't need them, pass NULL.
- Each flag has a symbolic name. AND the flags you care about with the
ret_flagsvalue to check whether that option is supported. - The flags are:
GSS_C_DELEG_FLAGπ- True: credentials were delegated from the initiator to the acceptor.
- False: no credentials were delegated.
GSS_C_MUTUAL_FLAGπ€- True: the acceptor was authenticated to the initiator.
- False: the acceptor didn't authenticate itself.
GSS_C_REPLAY_FLAGπ- True: replays of protected messages will be detected.
- False: replayed messages won't be detected.
GSS_C_SEQUENCE_FLAGπ’- True: out-of-sequence protected messages will be detected.
- False: out-of-sequence messages won't be detected.
GSS_C_CONF_FLAGπ- True: the confidentiality service can be invoked by calling the
gss_wraproutine. - False: there's no confidentiality service through
gss_wrap.gss_wraponly gives you message encapsulation, data-origin authentication and integrity. π«Ά
- True: the confidentiality service can be invoked by calling the
GSS_C_INTEG_FLAGπ§±- True: the integrity service can be invoked by calling either
gss_get_micorgss_wrap. - False: per-message integrity isn't available.
- True: the integrity service can be invoked by calling either
GSS_C_ANON_FLAGπΆοΈ- True: the initiator's identity won't be revealed to the acceptor. If you asked for
src_name, it holds an anonymous internal name. - False: the initiator was authenticated normally.
- True: the initiator's identity won't be revealed to the acceptor. If you asked for
GSS_C_PROT_READY_FLAGπ¦- True: the protection services (as set by
GSS_C_CONF_FLAGandGSS_C_INTEG_FLAG) are ready to use. - False: those protection services are only available once the context is fully established (that is, when the
openparameter is non-zero).
- True: the protection services (as set by
GSS_C_TRANS_FLAGπ- True: the resulting security context can be transferred to other processes with a call to
gss_export_sec_context(). - False: the security context can't be transferred.
- True: the resulting security context can be transferred to other processes with a call to
locally_initiated(Boolean, modify): non-zero if the app calling this is the context initiator πββοΈ Pass NULL if not required.open(Boolean, modify): non-zero if the context is fully established. Zero if the app is still waiting on a context-establishment token from its peer π«§ Pass NULL if not required.
Function value: GSS status code
GSS_S_COMPLETE: successful completion βGSS_S_NO_CONTEXT: the referenced context couldn't be accessed π΅
5.21. gss_inquire_cred ππ
OM_uint32 gss_inquire_cred (
OM_uint32 *minor_status,
const gss_cred_id_t cred_handle,
gss_name_t *name,
OM_uint32 *lifetime,
gss_cred_usage_t *cred_usage,
gss_OID_set *mechanisms )
Purpose:
this one lets you peek at a credential and see what it's all about π
Parameters:
minor_status(Integer, modify): the mechanism-specific status code π§cred_handle(gss_cred_id_t, read): the handle that points at the credential you want to check ποΈ- Pass
GSS_C_NO_CREDENTIALif you want to ask about the default initiator principal.
- Pass
name(gss_name_t, modify, optional): the name whose identity the credential is asserting πͺͺ- When you're finished, free the storage with a call to
gss_release_name(). π§Ή - Pass NULL if not required.
- When you're finished, free the storage with a call to
lifetime(Integer, modify, optional): how many seconds the credential stays valid β³- If it has already expired, this comes back as zero.
- If the implementation doesn't do credential expiration, you get
GSS_C_INDEFINITE. βΎοΈ - Pass NULL if not required.
cred_usage(gss_cred_usage_t, modify, optional): how the credential can be used. It's one of these:GSS_C_INITIATEGSS_C_ACCEPTGSS_C_BOTH- Pass NULL if not required.
mechanisms(gss_OID_set, modify, optional): the set of mechanisms the credential supports π§©- Free the storage for this OID set with a call to
gss_release_oid_set()once you're done. π§Ή - Pass NULL if not required.
- Free the storage for this OID set with a call to
Function value: GSS status code
GSS_S_COMPLETE: successful completion βGSS_S_NO_CRED: the referenced credentials couldn't be accessed πGSS_S_DEFECTIVE_CREDENTIAL: the referenced credentials were invalid πGSS_S_CREDENTIALS_EXPIRED: the referenced credentials have expired π- If you didn't pass
lifetimeas NULL, it gets set to 0.
- If you didn't pass
5.22. gss_inquire_cred_by_mech π¦
Signature π :
OM_uint32 gss_inquire_cred_by_mech (
OM_uint32 *minor_status,
const gss_cred_id_t cred_handle,
const gss_OID mech_type,
gss_name_t *name,
OM_uint32 *initiator_lifetime,
OM_uint32 *acceptor_lifetime,
gss_cred_usage_t *cred_usage )
Purpose π: okay so this one lets you ask a credential for per-mechanism details. Think of it as checking one specific mechanism's receipts for your credential β¨
Parameters π§:
minor_status(Integer, modify): mechanism-specific status code.cred_handle(gss_cred_id_t, read): a handle that refers to the target credential. PassGSS_C_NO_CREDENTIALif you want to ask about the default initiator principal π«Άmech_type(gss_OID, read): the mechanism you want info about.name(gss_name_t, modify, optional): the name whose identity the credential asserts. The app has to free this storage after use by callinggss_release_name()π§Ή. Pass NULL if you don't need it.initiator_lifetime(Integer, modify, optional): how many seconds the credential can still start security contexts under the given mechanism. If it can't be used to initiate anymore, or if the usage for this mechanism isGSS_C_ACCEPT, this comes back as zero π. If the implementation doesn't support expiring initiator credentials, you getGSS_C_INDEFINITEback. Pass NULL if you don't need it.acceptor_lifetime(Integer, modify, optional): same energy, but for accepting security contexts. If it can't accept anymore, or the usage for this mechanism isGSS_C_INITIATE, it's zero. If the implementation doesn't support expiring acceptor credentials, the value isGSS_C_INDEFINITE. Pass NULL if you don't need it.cred_usage(gss_cred_usage_t, modify, optional): how the credential may be used with the specified mechanism. It's one ofGSS_C_INITIATE,GSS_C_ACCEPT, orGSS_C_BOTH. Pass NULL if you don't need it.
Function value π: the GSS status code you get back:
GSS_S_COMPLETE: successful completion πGSS_S_NO_CRED: the referenced credentials couldn't be accessed πGSS_S_DEFECTIVE_CREDENTIAL: the referenced credentials were invalid πGSS_S_CREDENTIALS_EXPIRED: the referenced credentials have expired. If you didn't pass NULL for the lifetime parameter, it gets set to 0 β
5.23. gss_inquire_mechs_for_name πΈ
Signature π:
OM_uint32 gss_inquire_mechs_for_name (
OM_uint32 *minor_status,
const gss_name_t input_name,
gss_OID_set *mech_types )
Purpose π: this gives you the list of mechanisms your GSS-API implementation supports that might be able to handle a given name. Every mechanism on the list will recognize at least one element in the name, ngl that's a solid guarantee π₯
It's totally fine for this routine to live in a mechanism-independent GSS-API layer. It can use the type info already in the name, plus registration info that each mechanism provides π§ . Here's the tea though: a mechanism might be listed and still refuse the name in gss_canonicalize_name, gss_init_sec_context, gss_acquire_cred or gss_add_cred. Why? Because of some property of that specific name, not just its name type π€. So treat this routine as a pre-filter before you call the mechanism-specific routine, not as a guarantee π
Parameters π:
minor_status(Integer, modify): implementation-specific status code.input_name(gss_name_t, read): the name the inquiry is about.mech_types(gss_OID_set, modify): the set of mechanisms that may support the specified name. The caller must free the returned OID set after use by callinggss_release_oid_set()π§Ή
Function value π«§:
GSS_S_COMPLETE: successful completion β¨GSS_S_BAD_NAME: theinput_nameparameter was ill-formed πGSS_S_BAD_NAMETYPE: theinput_nameparameter contained an invalid or unsupported type of name π ββοΈ
5.24. gss_inquire_names_for_mech π§
Signature π¦:
OM_uint32 gss_inquire_names_for_mech (
OM_uint32 *minor_status,
const gss_OID mechanism,
gss_OID_set *name_types)
Purpose π: this one returns the set of name types a specific mechanism supports. Basically, "what kinds of names do you even take?" π€·ββοΈ
Parameters π:
minor_status(Integer, modify): implementation-specific status code.mechanism(gss_OID, read): the mechanism to be interrogated.name_types(gss_OID_set, modify): the set of name types the specified mechanism supports. The application must free the returned OID set after use by callinggss_release_oid_set()π§Ή
Function value π:
GSS_S_COMPLETE: successful completion π
5.25. gss_process_context_token π«Ά
Signature π₯:
OM_uint32 gss_process_context_token (
OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
const gss_buffer_t token_buffer)
Purpose β¨: this is how you hand an asynchronous token to the security service. Most context-level tokens get sent and handled synchronously by gss_init_sec_context and gss_accept_sec_context, and the app finds out whether more tokens are expected from the GSS_C_CONTINUE_NEEDED major status bit π
But sometimes a mechanism has to emit a context-level token when the peer isn't expecting one π. Example: the initiator's final call to gss_init_sec_context might emit a token and return GSS_S_COMPLETE, but then the acceptor's call to gss_accept_sec_context fails π. The acceptor's mechanism might want to send an error token back to the initiator, but the initiator thinks the context is fully established, so it's not waiting for anything π. That's exactly what Gss_process_context_token is for: it lets you pass that kind of token to the mechanism at any time π¦
Parameters πΈ:
minor_status(Integer, modify): implementation-specific status code.context_handle(gss_ctx_id_t, read): the context handle of the context on which the token is to be processed.token_buffer(buffer, opaque, read): the token to process.
Function value π :
GSS_S_COMPLETE: successful completion πGSS_S_DEFECTIVE_TOKEN: the consistency checks performed on the token failed πGSS_S_NO_CONTEXT: thecontext_handledidn't refer to a valid context π
5.26. gss_release_buffer π§Ή
Signature π·:
OM_uint32 gss_release_buffer (
OM_uint32 *minor_status,
gss_buffer_t buffer)
Purpose π«§: this frees the storage tied to a buffer. That storage has to have been allocated by a GSS-API routine β¨. Along with freeing it, the routine zeroes the length field in the descriptor the buffer parameter points to. Implementations are encouraged to also set the pointer field in that descriptor to NULL π. Any buffer object returned by a GSS-API routine can be passed to gss_release_buffer, even if there's no storage attached to it π
Parameters π:
minor_status(Integer, modify): mechanism-specific status code.buffer(buffer, modify): the storage associated with the buffer gets deleted. Thegss_buffer_descobject itself won't be freed, but its length field gets zeroed π§Ό
Function value π:
GSS_S_COMPLETE: successful completion β
5.27. gss_release_cred π§
Signature π:
OM_uint32 gss_release_cred (
OM_uint32 *minor_status,
gss_cred_id_t *cred_handle)
Purpose π: this tells GSS-API the app doesn't need this credential handle anymore, and frees the resources tied to it π§Ή. Implementations are encouraged to set cred_handle to GSS_C_NO_CREDENTIAL when the call completes successfully π
Parameters π¦:
cred_handle(gss_cred_id_t, modify, optional): the opaque handle identifying the credential to be released. IfGSS_C_NO_CREDENTIALis supplied, the routine still completes successfully but does nothing π«Άminor_status(Integer, modify): mechanism-specific status code.
Function value β¨:
GSS_S_COMPLETE: successful completion π₯GSS_S_NO_CRED: credentials couldn't be accessed π
5.28. gss_release_name πΈ
Signature π₯:
OM_uint32 gss_release_name (
OM_uint32 *minor_status,
gss_name_t *name)
Purpose π: this frees GSSAPI-allocated storage tied to an internal-form name. Implementations are encouraged to set the name to GSS_C_NO_NAME once the call completes successfully π¦
Parameters π:
minor_status(Integer, modify): mechanism-specific status code.name(gss_name_t, modify): the name to be deleted ποΈ
Function value π:
GSS_S_COMPLETE: successful completion πGSS_S_BAD_NAME: the name parameter didn't contain a valid name π
5.29. gss_release_oid_set π«§
Signature π:
OM_uint32 gss_release_oid_set (
OM_uint32 *minor_status,
gss_OID_set *set)
Purpose π§ : this frees storage tied to a GSSAPI-generated gss_OID_set object. The set parameter has to refer to an OID set that was returned from a GSS-API routine π¦. gss_release_oid_set() frees the storage for each individual member OID, the OID set's elements array, and the gss_OID_set_desc itself π§Ή
Implementations are encouraged to set the gss_OID_set parameter to GSS_C_NO_OID_SET when this routine completes successfully π
Parameters π·:
minor_status(Integer, modify): mechanism-specific status code.set(Set of Object IDs, modify): the storage associated with thegss_OID_setgets deleted ποΈ
Function value π:
GSS_S_COMPLETE: successful completion β¨
5.30. gss_test_oid_set_member π§
Purpose: okay so this one is literally the bouncer at the OID club π You hand it an Object Identifier and a set, and it tells you whether that OID is on the list. It's meant for sets that come back from gss_indicate_mechs(), gss_acquire_cred(), and gss_inquire_cred(), but it works just fine on sets you build yourself π«Ά
OM_uint32 gss_test_oid_set_member (
OM_uint32 *minor_status,
const gss_OID member,
const gss_OID_set set,
int *present)
minor_status Integer, modify
Mechanism specific status code
member Object ID, read
The object identifier whose presence
is to be tested.
set Set of Object ID, read
The Object Identifier set.
present Boolean, modify
non-zero if the specified OID is a member
of the set, zero if not.
Function value: GSS status code
GSS_S_COMPLETE Successful completion
5.31. gss_unwrap π
Purpose: this is the glow-up reversal of gss_wrap π¦ It takes a message that was previously protected and turns it back into something you can actually use, while checking the embedded MIC along the way. The conf_state output tells you whether encryption was involved, and the qop_state output tells you how strong the protection was for the confidentiality and integrity services π
Some application protocols like to use the tokens gss_wrap() spits out as "secure framing" π§ So implementations must support wrapping and unwrapping zero-length messages, no exceptions π
OM_uint32 gss_unwrap (
OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
const gss_buffer_t input_message_buffer,
gss_buffer_t output_message_buffer,
int *conf_state,
gss_qop_t *qop_state)
minor_status Integer, modify
Mechanism specific status code.
context_handle gss_ctx_id_t, read
Identifies the context on which the message
arrived
input_message_buffer buffer, opaque, read
protected message
output_message_buffer buffer, opaque, modify
Buffer to receive unwrapped message.
Storage associated with this buffer must
be freed by the application after use use
with a call to gss_release_buffer().
conf_state boolean, modify, optional
Non-zero - Confidentiality and integrity
protection were used
Zero - Integrity service only was used
Specify NULL if not required
qop_state gss_qop_t, modify, optional
Quality of protection provided.
Specify NULL if not required
Function value: GSS status code
GSS_S_COMPLETE Successful completion
GSS_S_DEFECTIVE_TOKEN The token failed consistency checks
GSS_S_BAD_SIG The MIC was incorrect
GSS_S_DUPLICATE_TOKEN The token was valid, and contained a correct
MIC for the message, but it had already been
processed
GSS_S_OLD_TOKEN The token was valid, and contained a correct MIC
for the message, but it is too old to check for
duplication.
GSS_S_UNSEQ_TOKEN The token was valid, and contained a correct MIC
for the message, but has been verified out of
sequence; a later token has already been
received.
GSS_S_GAP_TOKEN The token was valid, and contained a correct MIC
for the message, but has been verified out of
sequence; an earlier expected token has not yet
been received.
GSS_S_CONTEXT_EXPIRED The context has already expired
GSS_S_NO_CONTEXT The context_handle parameter did not identify
a valid context
5.32. gss_verify_mic π΅οΈββοΈ
Purpose: ngl this one is giving detective energy π΅οΈββοΈ It checks that a cryptographic MIC, sitting in the token parameter, actually matches the message you were handed. The qop_state output lets the recipient see how strong the protection on that message was πΈ
Same deal as gss_unwrap: some application protocols use gss_wrap() tokens for "secure framing", so implementations must support calculating and verifying MICs over zero-length messages π§
OM_uint32 gss_verify_mic (
OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
const gss_buffer_t message_buffer,
const gss_buffer_t token_buffer,
gss_qop_t *qop_state)
minor_status Integer, modify
Mechanism specific status code.
context_handle gss_ctx_id_t, read
Identifies the context on which the message
arrived
message_buffer buffer, opaque, read
Message to be verified
token_buffer buffer, opaque, read
Token associated with message
qop_state gss_qop_t, modify, optional
quality of protection gained from MIC
Specify NULL if not required
Function value: GSS status code
GSS_S_COMPLETE Successful completion
GSS_S_DEFECTIVE_TOKEN The token failed consistency checks
GSS_S_BAD_SIG The MIC was incorrect
GSS_S_DUPLICATE_TOKEN The token was valid, and contained a correct
MIC for the message, but it had already been
processed
GSS_S_OLD_TOKEN The token was valid, and contained a correct MIC
for the message, but it is too old to check for
duplication.
GSS_S_UNSEQ_TOKEN The token was valid, and contained a correct MIC
for the message, but has been verified out of
sequence; a later token has already been received.
GSS_S_GAP_TOKEN The token was valid, and contained a correct MIC
for the message, but has been verified out of
sequence; an earlier expected token has not yet
been received.
GSS_S_CONTEXT_EXPIRED The context has already expired
GSS_S_NO_CONTEXT The context_handle parameter did not identify a
valid context
5.33. gss_wrap π
Purpose: this is the main event π gss_wrap attaches a cryptographic MIC to your message and can optionally encrypt it too. The output_message holds both the MIC and the message together. The qop_req parameter lets you pick between several cryptographic algorithms, as long as the chosen mechanism supports them β¨
Once again, the "secure framing" crowd is a thing, so implementations must support wrapping zero-length messages π«Ά
OM_uint32 gss_wrap (
OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
int conf_req_flag,
gss_qop_t qop_req
const gss_buffer_t input_message_buffer,
int *conf_state,
gss_buffer_t output_message_buffer )
minor_status Integer, modify
Mechanism specific status code.
context_handle gss_ctx_id_t, read
Identifies the context on which the message
will be sent
conf_req_flag boolean, read
Non-zero - Both confidentiality and integrity
services are requested
Zero - Only integrity service is requested
qop_req gss_qop_t, read, optional
Specifies required quality of protection. A
mechanism-specific default may be requested by
setting qop_req to GSS_C_QOP_DEFAULT. If an
unsupported protection strength is requested,
gss_wrap will return a major_status of
GSS_S_BAD_QOP.
input_message_buffer buffer, opaque, read
Message to be protected
conf_state boolean, modify, optional
Non-zero - Confidentiality, data origin
authentication and integrity
services have been applied
Zero - Integrity and data origin services only
has been applied.
Specify NULL if not required
output_message_buffer buffer, opaque, modify
Buffer to receive protected message.
Storage associated with this message must
be freed by the application after use with
a call to gss_release_buffer().
Function value: GSS status code
GSS_S_COMPLETE Successful completion
GSS_S_CONTEXT_EXPIRED The context has already expired
GSS_S_NO_CONTEXT The context_handle parameter did not identify a
valid context
GSS_S_BAD_QOP The specified QOP is not supported by the
mechanism.
5.34. gss_wrap_size_limit π
Purpose: this one is the size-planning queen π It lets an application figure out the biggest message it can hand to gss_wrap, using the same conf_req_flag and qop_req values, and still get an output token that's no more than req_output_size bytes π
It's built for apps that talk over protocols with a maximum message size. You ask first, then chop your messages into fragments before protecting them π§
Implementations are recommended but not required to detect invalid QOP values when gss_wrap_size_limit() is called. This routine only guarantees a maximum message size, not that any specific QOP value will be available for protecting messages π«
Heads up, though: a successful call doesn't promise that gss_wrap will actually protect a message of max_input_size bytes π That depends on system resources being available when gss_wrap runs. And if the implementation has its own upper limit on message length for gss_wrap, the implementation should not return a max_input_bytes value bigger than that limit β¨
OM_uint32 gss_wrap_size_limit (
OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
int conf_req_flag,
gss_qop_t qop_req,
OM_uint32 req_output_size,
OM_uint32 *max_input_size)
minor_status Integer, modify
Mechanism specific status code
context_handle gss_ctx_id_t, read
A handle that refers to the security over
which the messages will be sent.
conf_req_flag Boolean, read
Indicates whether gss_wrap will be asked
to apply confidentiality protection in
addition to integrity protection. See
the routine description for gss_wrap
for more details.
qop_req gss_qop_t, read
Indicates the level of protection that
gss_wrap will be asked to provide. See
the routine description for gss_wrap for
more details.
req_output_size Integer, read
The desired maximum size for tokens emitted
by gss_wrap.
max_input_size Integer, modify
The maximum input message size that may
be presented to gss_wrap in order to
guarantee that the emitted token shall
be no larger than req_output_size bytes.
Function value: GSS status code
GSS_S_COMPLETE Successful completion
GSS_S_NO_CONTEXT The referenced context could not be accessed.
GSS_S_CONTEXT_EXPIRED The context has expired.
GSS_S_BAD_QOP The specified QOP is not supported by the
mechanism.
6. Security Considerations β¨
okay bestie, this part is SO important π«Ά GSS-API is a service interface for security stuff, so security considerations pop up all over the whole spec. But there are a few points that are extra important for anyone implementing GSS-API or building apps on top of it, so let's go through them π
Using the GSS-API interface doesn't give you security services or assurance by itself π Those properties depend on the underlying mechanism(s) that the GSS-API implementation runs on. So the mechanism is doing the heavy lifting, not the interface.
Callers need to be super attentive to the requests they make to GSS-API calls and to the status indicators that come back, because those tell you exactly which security service characteristics GSS-API is going to provide. Don't just vibe with it, check the status π
And when the interprocess context transfer facility is used, appropriate local controls should be applied to constrain access to interprocess tokens and to the sensitive data they contain. Lock that down, periodt ππ
Appendix A. GSS-API C header file gssapi.h β¨
C-language GSS-API implementations should include a copy of the following header file. Here's the whole header, verbatim, because implementers need every single character π
#ifndef GSSAPI_H_
#define GSSAPI_H_
/*
* First, include stddef.h to get size_t defined.
*/
#include <stddef.h>
/*
* If the platform supports the xom.h header file, it should be
* included here.
*/
#include <xom.h>
/*
* Now define the three implementation-dependent types.
*/
typedef <platform-specific> gss_ctx_id_t;
typedef <platform-specific> gss_cred_id_t;
typedef <platform-specific> gss_name_t;
/*
* The following type must be defined as the smallest natural
* unsigned integer supported by the platform that has at least
* 32 bits of precision.
*/
typedef <platform-specific> gss_uint32;
#ifdef OM_STRING
/*
* We have included the xom.h header file. Verify that OM_uint32
* is defined correctly.
*/
#if sizeof(gss_uint32) != sizeof(OM_uint32)
#error Incompatible definition of OM_uint32 from xom.h
#endif
typedef OM_object_identifier gss_OID_desc, *gss_OID;
#else
/*
* We can't use X/Open definitions, so roll our own.
*/
typedef gss_uint32 OM_uint32;
typedef struct gss_OID_desc_struct {
OM_uint32 length;
void *elements;
} gss_OID_desc, *gss_OID;
#endif
typedef struct gss_OID_set_desc_struct {
size_t count;
gss_OID elements;
} gss_OID_set_desc, *gss_OID_set;
typedef struct gss_buffer_desc_struct {
size_t length;
void *value;
} gss_buffer_desc, *gss_buffer_t;
typedef struct gss_channel_bindings_struct {
OM_uint32 initiator_addrtype;
gss_buffer_desc initiator_address;
OM_uint32 acceptor_addrtype;
gss_buffer_desc acceptor_address;
gss_buffer_desc application_data;
} *gss_channel_bindings_t;
/*
* For now, define a QOP-type as an OM_uint32
*/
typedef OM_uint32 gss_qop_t;
typedef int gss_cred_usage_t;
/*
* Flag bits for context-level services.
*/
#define GSS_C_DELEG_FLAG 1
#define GSS_C_MUTUAL_FLAG 2
#define GSS_C_REPLAY_FLAG 4
#define GSS_C_SEQUENCE_FLAG 8
#define GSS_C_CONF_FLAG 16
#define GSS_C_INTEG_FLAG 32
#define GSS_C_ANON_FLAG 64
#define GSS_C_PROT_READY_FLAG 128
#define GSS_C_TRANS_FLAG 256
/*
* Credential usage options
*/
#define GSS_C_BOTH 0
#define GSS_C_INITIATE 1
#define GSS_C_ACCEPT 2
/*
* Status code types for gss_display_status
*/
#define GSS_C_GSS_CODE 1
#define GSS_C_MECH_CODE 2
/*
* The constant definitions for channel-bindings address families
*/
#define GSS_C_AF_UNSPEC 0
#define GSS_C_AF_LOCAL 1
#define GSS_C_AF_INET 2
#define GSS_C_AF_IMPLINK 3
#define GSS_C_AF_PUP 4
#define GSS_C_AF_CHAOS 5
#define GSS_C_AF_NS 6
#define GSS_C_AF_NBS 7
#define GSS_C_AF_ECMA 8
#define GSS_C_AF_DATAKIT 9
#define GSS_C_AF_CCITT 10
#define GSS_C_AF_SNA 11
#define GSS_C_AF_DECnet 12
#define GSS_C_AF_DLI 13
#define GSS_C_AF_LAT 14
#define GSS_C_AF_HYLINK 15
#define GSS_C_AF_APPLETALK 16
#define GSS_C_AF_BSC 17
#define GSS_C_AF_DSS 18
#define GSS_C_AF_OSI 19
#define GSS_C_AF_X25 21
#define GSS_C_AF_NULLADDR 255
/*
* Various Null values
*/
#define GSS_C_NO_NAME ((gss_name_t) 0)
#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
#define GSS_C_NO_OID ((gss_OID) 0)
#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
#define GSS_C_EMPTY_BUFFER {0, NULL}
/*
* Some alternate names for a couple of the above
* values. These are defined for V1 compatibility.
*/
#define GSS_C_NULL_OID GSS_C_NO_OID
#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET
/*
* Define the default Quality of Protection for per-message
* services. Note that an implementation that offers multiple
* levels of QOP may define GSS_C_QOP_DEFAULT to be either zero
* (as done here) to mean "default protection", or to a specific
* explicit QOP value. However, a value of 0 should always be
* interpreted by a GSS-API implementation as a request for the
* default protection level.
*/
#define GSS_C_QOP_DEFAULT 0
/*
* Expiration time of 2^32-1 seconds means infinite lifetime for a
* credential or security context
*/
#define GSS_C_INDEFINITE 0xfffffffful
Next up are the OID constants, which are the fun part where every byte matters π§ Read these carefully, babe π
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
* "\x01\x02\x01\x01"},
* corresponding to an object-identifier value of
* {iso(1) member-body(2) United States(840) mit(113554)
* infosys(1) gssapi(2) generic(1) user_name(1)}. The constant
* GSS_C_NT_USER_NAME should be initialized to point
* to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_USER_NAME;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
* "\x01\x02\x01\x02"},
* corresponding to an object-identifier value of
* {iso(1) member-body(2) United States(840) mit(113554)
* infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
* The constant GSS_C_NT_MACHINE_UID_NAME should be
* initialized to point to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_MACHINE_UID_NAME;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
* "\x01\x02\x01\x03"},
* corresponding to an object-identifier value of
* {iso(1) member-body(2) United States(840) mit(113554)
* infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
* The constant GSS_C_NT_STRING_UID_NAME should be
* initialized to point to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_STRING_UID_NAME;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
* corresponding to an object-identifier value of
* {iso(1) org(3) dod(6) internet(1) security(5)
* nametypes(6) gss-host-based-services(2)). The constant
* GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
* to that gss_OID_desc. This is a deprecated OID value, and
* implementations wishing to support hostbased-service names
* should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
* defined below, to identify such names;
* GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
* for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
* parameter, but should not be emitted by GSS-API
* implementations
*/
extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
* "\x01\x02\x01\x04"}, corresponding to an
* object-identifier value of {iso(1) member-body(2)
* Unites States(840) mit(113554) infosys(1) gssapi(2)
* generic(1) service_name(4)}. The constant
* GSS_C_NT_HOSTBASED_SERVICE should be initialized
* to point to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_HOSTBASED_SERVICE;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {6, (void *)"\x2b\x06\01\x05\x06\x03"},
* corresponding to an object identifier value of
* {1(iso), 3(org), 6(dod), 1(internet), 5(security),
* 6(nametypes), 3(gss-anonymous-name)}. The constant
* and GSS_C_NT_ANONYMOUS should be initialized to point
* to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_ANONYMOUS;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
* corresponding to an object-identifier value of
* {1(iso), 3(org), 6(dod), 1(internet), 5(security),
* 6(nametypes), 4(gss-api-exported-name)}. The constant
* GSS_C_NT_EXPORT_NAME should be initialized to point
* to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_EXPORT_NAME;
/* Major status codes */
#define GSS_S_COMPLETE 0
/*
* Some "helper" definitions to make the status code macros obvious.
*/
#define GSS_C_CALLING_ERROR_OFFSET 24
#define GSS_C_ROUTINE_ERROR_OFFSET 16
#define GSS_C_SUPPLEMENTARY_OFFSET 0
#define GSS_C_CALLING_ERROR_MASK 0377ul
#define GSS_C_ROUTINE_ERROR_MASK 0377ul
#define GSS_C_SUPPLEMENTARY_MASK 0177777ul
/*
* The macros that test status codes for error conditions.
* Note that the GSS_ERROR() macro has changed slightly from
* the V1 GSS-API so that it now evaluates its argument
* only once.
*/
#define GSS_CALLING_ERROR(x) \
(x & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
#define GSS_ROUTINE_ERROR(x) \
(x & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
#define GSS_SUPPLEMENTARY_INFO(x) \
(x & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
#define GSS_ERROR(x) \
(x & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
(GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
/*
* Now the actual status code definitions
*/
/*
* Calling errors:
*/
#define GSS_S_CALL_INACCESSIBLE_READ \
(1ul << GSS_C_CALLING_ERROR_OFFSET)
#define GSS_S_CALL_INACCESSIBLE_WRITE \
(2ul << GSS_C_CALLING_ERROR_OFFSET)
#define GSS_S_CALL_BAD_STRUCTURE \
(3ul << GSS_C_CALLING_ERROR_OFFSET)
/*
- Routine errors: */ #define GSS_S_BAD_MECH (1ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_BAD_NAME (2ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_BAD_NAMETYPE (3ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_BAD_BINDINGS (4ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_BAD_STATUS (5ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_BAD_SIG (6ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_BAD_MIC GSS_S_BAD_SIG #define GSS_S_NO_CRED (7ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_NO_CONTEXT (8ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_DEFECTIVE_TOKEN (9ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_DEFECTIVE_CREDENTIAL (10ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_CREDENTIALS_EXPIRED (11ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_CONTEXT_EXPIRED (12ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_FAILURE (13ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_BAD_QOP (14ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_UNAUTHORIZED (15ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_UNAVAILABLE (16ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_DUPLICATE_ELEMENT (17ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_NAME_NOT_MN (18ul << GSS_C_ROUTINE_ERROR_OFFSET)
/*
- Supplementary info bits: */ #define GSS_S_CONTINUE_NEEDED \ (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0)) #define GSS_S_DUPLICATE_TOKEN \ (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1)) #define GSS_S_OLD_TOKEN \ (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2)) #define GSS_S_UNSEQ_TOKEN \ (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3)) #define GSS_S_GAP_TOKEN \ (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
/*
- Finally, function prototypes for the GSS-API routines. */
OM_uint32 gss_acquire_cred (OM_uint32 , /* minor_status / const gss_name_t, / desired_name / OM_uint32, / time_req / const gss_OID_set, / desired_mechs / gss_cred_usage_t, / cred_usage / gss_cred_id_t , / output_cred_handle / gss_OID_set , / actual_mechs / OM_uint32 * / time_rec */ );
OM_uint32 gss_release_cred (OM_uint32 , /* minor_status / gss_cred_id_t * / cred_handle */ );
OM_uint32 gss_init_sec_context (OM_uint32 , /* minor_status / const gss_cred_id_t, / initiator_cred_handle / gss_ctx_id_t , / context_handle / const gss_name_t, / target_name / const gss_OID, / mech_type / OM_uint32, / req_flags / OM_uint32, / time_req / const gss_channel_bindings_t, / input_chan_bindings / const gss_buffer_t, / input_token / gss_OID , / actual_mech_type / gss_buffer_t, / output_token / OM_uint32 , / ret_flags / OM_uint32 * / time_rec */ );
OM_uint32 gss_accept_sec_context (OM_uint32 , /* minor_status / gss_ctx_id_t , / context_handle / const gss_cred_id_t, / acceptor_cred_handle / const gss_buffer_t, / input_token_buffer / const gss_channel_bindings_t, / input_chan_bindings / gss_name_t , / src_name / gss_OID , / mech_type / gss_buffer_t, / output_token / OM_uint32 , / ret_flags / OM_uint32 , / time_rec / gss_cred_id_t * / delegated_cred_handle */ );
OM_uint32 gss_process_context_token (OM_uint32 , /* minor_status / const gss_ctx_id_t, / context_handle / const gss_buffer_t / token_buffer */ );
OM_uint32 gss_delete_sec_context (OM_uint32 , /* minor_status / gss_ctx_id_t , / context_handle / gss_buffer_t / output_token */ );
OM_uint32 gss_context_time (OM_uint32 , /* minor_status / const gss_ctx_id_t, / context_handle / OM_uint32 * / time_rec */ );
OM_uint32 gss_get_mic (OM_uint32 , /* minor_status / const gss_ctx_id_t, / context_handle / gss_qop_t, / qop_req / const gss_buffer_t, / message_buffer / gss_buffer_t / message_token */ );
OM_uint32 gss_verify_mic (OM_uint32 , /* minor_status / const gss_ctx_id_t, / context_handle / const gss_buffer_t, / message_buffer / const gss_buffer_t, / token_buffer / gss_qop_t * / qop_state */ );
OM_uint32 gss_wrap (OM_uint32 , /* minor_status / const gss_ctx_id_t, / context_handle / int, / conf_req_flag / gss_qop_t, / qop_req / const gss_buffer_t, / input_message_buffer / int , / conf_state / gss_buffer_t / output_message_buffer */ );
OM_uint32 gss_unwrap (OM_uint32 , /* minor_status / const gss_ctx_id_t, / context_handle / const gss_buffer_t, / input_message_buffer / gss_buffer_t, / output_message_buffer / int , / conf_state / gss_qop_t * / qop_state */ );
OM_uint32 gss_display_status (OM_uint32 , /* minor_status / OM_uint32, / status_value / int, / status_type / const gss_OID, / mech_type / OM_uint32 , / message_context / gss_buffer_t / status_string */ );
OM_uint32 gss_indicate_mechs (OM_uint32 , /* minor_status / gss_OID_set * / mech_set */ );
OM_uint32 gss_compare_name (OM_uint32 , /* minor_status / const gss_name_t, / name1 / const gss_name_t, / name2 / int * / name_equal */ );
OM_uint32 gss_display_name (OM_uint32 , /* minor_status / const gss_name_t, / input_name / gss_buffer_t, / output_name_buffer / gss_OID * / output_name_type */ );
OM_uint32 gss_import_name (OM_uint32 , /* minor_status / const gss_buffer_t, / input_name_buffer / const gss_OID, / input_name_type / gss_name_t * / output_name */ );
OM_uint32 gss_export_name (OM_uint32, /* minor_status / const gss_name_t, / input_name / gss_buffer_t / exported_name */ );
OM_uint32 gss_release_name (OM_uint32 , / minor_status / gss_name_t * / input_name */ );
OM_uint32 gss_release_buffer (OM_uint32 , /* minor_status / gss_buffer_t / buffer */ );
OM_uint32 gss_release_oid_set (OM_uint32 , /* minor_status / gss_OID_set * / set */ );
OM_uint32 gss_inquire_cred (OM_uint32 , /* minor_status / const gss_cred_id_t, / cred_handle / gss_name_t , / name / OM_uint32 , / lifetime / gss_cred_usage_t , / cred_usage / gss_OID_set * / mechanisms */ );
OM_uint32 gss_inquire_context ( OM_uint32 , /* minor_status / const gss_ctx_id_t, / context_handle / gss_name_t , / src_name / gss_name_t , / targ_name / OM_uint32 , / lifetime_rec / gss_OID , / mech_type / OM_uint32 , / ctx_flags / int , / locally_initiated / int * / open */ );
OM_uint32 gss_wrap_size_limit ( OM_uint32 , /* minor_status / const gss_ctx_id_t, / context_handle / int, / conf_req_flag / gss_qop_t, / qop_req / OM_uint32, / req_output_size / OM_uint32 * / max_input_size */ );
OM_uint32 gss_add_cred ( OM_uint32 , /* minor_status / const gss_cred_id_t, / input_cred_handle / const gss_name_t, / desired_name / const gss_OID, / desired_mech / gss_cred_usage_t, / cred_usage / OM_uint32, / initiator_time_req / OM_uint32, / acceptor_time_req / gss_cred_id_t , / output_cred_handle / gss_OID_set , / actual_mechs / OM_uint32 , / initiator_time_rec / OM_uint32 * / acceptor_time_rec */ );
OM_uint32 gss_inquire_cred_by_mech ( OM_uint32 , /* minor_status / const gss_cred_id_t, / cred_handle / const gss_OID, / mech_type / gss_name_t , / name / OM_uint32 , / initiator_lifetime / OM_uint32 , / acceptor_lifetime / gss_cred_usage_t * / cred_usage */ );
OM_uint32 gss_export_sec_context ( OM_uint32 , /* minor_status / gss_ctx_id_t , / context_handle / gss_buffer_t / interprocess_token */ );
OM_uint32 gss_import_sec_context (
OM_uint32 , /* minor_status */
const gss_buffer_t, /* interprocess_token */
gss_ctx_id_t * /* context_handle */
);
OM_uint32 gss_create_empty_oid_set (
OM_uint32 , /* minor_status */
gss_OID_set * /* oid_set */
);
OM_uint32 gss_add_oid_set_member (
OM_uint32 , /* minor_status */
const gss_OID, /* member_oid */
gss_OID_set * /* oid_set */
);
OM_uint32 gss_test_oid_set_member (
OM_uint32 , /* minor_status */
const gss_OID, /* member */
const gss_OID_set, /* set */
int * /* present */
);
OM_uint32 gss_inquire_names_for_mech (
OM_uint32 , /* minor_status */
const gss_OID, /* mechanism */
gss_OID_set * /* name_types */
);
OM_uint32 gss_inquire_mechs_for_name (
OM_uint32 , /* minor_status */
const gss_name_t, /* input_name */
gss_OID_set * /* mech_types */
);
OM_uint32 gss_canonicalize_name (
OM_uint32 , /* minor_status */
const gss_name_t, /* input_name */
const gss_OID, /* mech_type */
gss_name_t * /* output_name */
);
OM_uint32 gss_duplicate_name (
OM_uint32 , /* minor_status */
const gss_name_t, /* src_name */
gss_name_t * /* dest_name */
);
/*
* The following routines are obsolete variants of gss_get_mic,
* gss_verify_mic, gss_wrap and gss_unwrap. They should be
* provided by GSS-API V2 implementations for backwards
* compatibility with V1 applications. Distinct entrypoints
* (as opposed to #defines) should be provided, both to allow
* GSS-API V1 applications to link against GSS-API V2
implementations,
* and to retain the slight parameter type differences between the
* obsolete versions of these routines and their current forms.
*/
OM_uint32 gss_sign
(OM_uint32 , /* minor_status */
gss_ctx_id_t, /* context_handle */
int, /* qop_req */
gss_buffer_t, /* message_buffer */
gss_buffer_t /* message_token */
);
OM_uint32 gss_verify
(OM_uint32 , /* minor_status */
gss_ctx_id_t, /* context_handle */
gss_buffer_t, /* message_buffer */
gss_buffer_t, /* token_buffer */
int * /* qop_state */
);
OM_uint32 gss_seal
(OM_uint32 , /* minor_status */
gss_ctx_id_t, /* context_handle */
int, /* conf_req_flag */
int, /* qop_req */
gss_buffer_t, /* input_message_buffer */
int , /* conf_state */
gss_buffer_t /* output_message_buffer */
);
OM_uint32 gss_unseal
(OM_uint32 , /* minor_status */
gss_ctx_id_t, /* context_handle */
gss_buffer_t, /* input_message_buffer */
gss_buffer_t, /* output_message_buffer */
int , /* conf_state */
int * /* qop_state */
);
#endif /* GSSAPI_H_ */
Appendix B. Additional constraints for application binary portability β¨
okay so this appendix is all about binary portability, which is a whole other level of "it works on my machine" π
The purpose of this C-bindings document is to encourage source-level portability of applications across GSS-API implementations on different platforms and atop different mechanisms. Additional goals that have not been explicitly addressed by this document are link-time and run-time portability. πΈ
Link-time portability provides the ability to compile an application against one implementation of GSS-API, and then link it against a different implementation on the same platform. It is a stricter requirement than source-level portability. π
Run-time portability differs from link-time portability only on those platforms that implement dynamically loadable GSS-API implementations, but do not offer load-time symbol resolution. On such platforms, run-time portability is a stricter requirement than link-time portability, and will typically include the precise placement of the various GSS-API routines within library entrypoint vectors. π§
Individual platforms will impose their own rules that must be followed to achieve link-time (and run-time, if different) portability. In order to ensure either form of binary portability, an ABI specification must be written for GSS-API implementations on that platform. However, it is recognized that there are some issues that are likely to be common to all such ABI specifications. This appendix is intended to be a repository for such common issues, and contains some suggestions that individual ABI specifications may choose to reference. Since machine architectures vary greatly, it may not be possible or desirable to follow these suggestions on all platforms. π¦
B.1. Pointers π
While ANSI-C provides a single pointer type for each declared type, plus a single (void *) type, some platforms (notably those using segmented memory architectures) augment this with various modified pointer types (e.g. far pointers, near pointers). These language bindings assume ANSI-C, and thus do not address such non-standard implementations. GSS-API implementations for such platforms must choose an appropriate memory model, and should use it consistently throughout. For example, if a memory model is chosen that requires the use of far pointers when passing routine parameters, then far pointers should also be used within the structures defined by GSS-API. π
B.2. Internal structure alignment π
GSS-API defines several data-structures containing differently-sized fields. An ABI specification should include a detailed description of how the fields of such structures are aligned, and if there is any internal padding in these data structures. The use of compiler defaults for the platform is recommended. β¨
B.3. Handle types π«Ά
The C bindings specify that the gss_cred_id_t and gss_ctx_id_t types should be implemented as either pointer or arithmetic types, and that if pointer types are used, care should be taken to ensure that two handles may be compared with the == operator. Note that ANSI-C does not guarantee that two pointer values may be compared with the == operator unless either the two pointers point to members of a single array, or at least one of the pointers contains a NULL value. π
For binary portability, additional constraints are required. The following is an attempt at defining platform-independent constraints. π
The size of the handle type must be the same as sizeof(void *), using the appropriate memory model.
The == operator for the chosen type must be a simple bit-wise comparison. That is, for two in-memory handle objects h1 and h2, the boolean value of the expression
(h1 == h2)
should always be the same as the boolean value of the expression
(memcmp(&h1, &h2, sizeof(h1)) == 0)
The actual use of the type (void *) for handle types is discouraged, not for binary portability reasons, but since it effectively disables much of the compile-time type-checking that the compiler can otherwise perform, and is therefore not "programmer-friendly". If a pointer implementation is desired, and if the platform's implementation of pointers permits, the handles should be implemented as pointers to distinct implementation-defined types. π
B.4. The gss_name_t type π
The gss_name_t type, representing the internal name object, should be implemented as a pointer type. The use of the (void *) type is discouraged as it does not allow the compiler to perform strong type-checking. However, the pointer type chosen should be of the same size as the (void *) type. Provided this rule is obeyed, ABI specifications need not further constrain the implementation of gss_name_t objects. π
B.5. The int and size_t types π₯
Some platforms may support differently sized implementations of the "int" and "size_t" types, perhaps chosen through compiler switches, and perhaps dependent on memory model. An ABI specification for such a platform should include required implementations for these types. It is recommended that the default implementation (for the chosen memory model, if appropriate) is chosen. β
B.6. Procedure-calling conventions πΈ
Some platforms support a variety of different binary conventions for calling procedures. Such conventions cover things like the format of the stack frame, the order in which the routine parameters are pushed onto the stack, whether or not a parameter count is pushed onto the stack, whether some argument(s) or return values are to be passed in registers, and whether the called routine or the caller is responsible for removing the stack frame on return. For such platforms, an ABI specification should specify which calling convention is to be used for GSS-API implementations. π§
References π
- [GSSAPI] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000.
- [XOM] OSI Object Management API Specification, Version 2.0 t", X.400 API Association & X/Open Company Limited, August 24, 1990 Specification of datatypes and routines for manipulating information objects.
Author's Address π¦
John Wray
Iris Associates
5 Technology Park Drive,
Westford, MA 01886
USA
Phone: +1-978-392-6689
EMail: John_Wray@Iris.com
Full Copyright Statement π
Copyright (C) The Internet Society (2000). All Rights Reserved. π
Okay bestie, so the Internet Society owns the copyright here, and they're being really generous about sharing it. π«Ά You can copy this document and pass it around to your friends. You can also write derivative works that comment on it, explain it, or help people actually build with it, and you can publish and distribute those too, in whole or in part, with no real restrictions. β¨ The one big catch is that the copyright notice and this paragraph have to show up on every copy and every derivative work. π
The original document itself is a different story. You can't edit it in any way. That means no deleting the copyright notice, and no swapping out the references to the Internet Society or other Internet organizations. π The only exceptions are when you need it to develop Internet standards, where you have to follow the copyright procedures in the Internet Standards process, or when you need to translate it into a language other than English. π
These permissions are perpetual. The Internet Society and its successors or assigns will never take them back. π¦
Now the legal part, and I promise it's short. π This document and the information in it are provided "AS IS." THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, including, but not limited to, any warranty that using the information here won't infringe anyone's rights, and any implied warranties of merchantability or fitness for a particular purpose. So basically they're not promising it'll work for everything, and that's just how it is. π
Acknowledgement πΈ
Funding for the RFC Editor function is currently provided by the Internet Society. That's the whole acknowledgement, and it's giving thank-you-for-the-snacks energy. π§
π¦ where this page comes from
- ietf: rfc2744 2000-01
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms