draft-ietf-kitten-gss-loop-00.txt   draft-ietf-kitten-gss-loop-01.txt 
Network Working Group B. Kaduk Network Working Group B. Kaduk
Internet-Draft MIT Internet-Draft MIT
Intended status: Informational May 8, 2014 Intended status: Informational November 19, 2014
Expires: November 9, 2014 Expires: May 23, 2015
Structure of the GSS Negotiation Loop Structure of the GSS Negotiation Loop
draft-ietf-kitten-gss-loop-00 draft-ietf-kitten-gss-loop-01
Abstract Abstract
This document specifies the generic structure of the negotiation loop This document specifies the generic structure of the negotiation loop
to establish a GSS security context between initiator and acceptor. to establish a GSS security context between initiator and acceptor.
The control flow of the loop is indicated for both parties, including The control flow of the loop is indicated for both parties, including
error conditions, and indications are given for where application- error conditions, and indications are given for where application-
specific behavior must be specified. specific behavior must be specified.
Status of This Memo Status of This Memo
skipping to change at page 1, line 34 skipping to change at page 1, line 34
Internet-Drafts are working documents of the Internet Engineering Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet- working documents as Internet-Drafts. The list of current Internet-
Drafts is at http://datatracker.ietf.org/drafts/current/. Drafts is at http://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress." material or to cite them other than as "work in progress."
This Internet-Draft will expire on November 9, 2014. This Internet-Draft will expire on May 23, 2015.
Copyright Notice Copyright Notice
Copyright (c) 2014 IETF Trust and the persons identified as the Copyright (c) 2014 IETF Trust and the persons identified as the
document authors. All rights reserved. document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents Provisions Relating to IETF Documents
(http://trustee.ietf.org/license-info) in effect on the date of (http://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with respect carefully, as they describe your rights and restrictions with respect
to this document. Code Components extracted from this document must to this document. Code Components extracted from this document must
include Simplified BSD License text as described in Section 4.e of include Simplified BSD License text as described in Section 4.e of
the Trust Legal Provisions and are provided without warranty as the Trust Legal Provisions and are provided without warranty as
described in the Simplified BSD License. described in the Simplified BSD License.
1. Introduction 1. Introduction
The Generic Security Service Application Program Intervace version 2 The Generic Security Service Application Program Interface version 2
[RFC2743] provides a generic interface for security services, in the [RFC2743] provides a generic interface for security services, in the
form of an abstraction layer over the underlying security mechanisms form of an abstraction layer over the underlying security mechanisms
that an application may use. A GSS initiator and acceptor exchange that an application may use. A GSS initiator and acceptor exchange
messages, called tokens, until a security context is established. messages, called tokens, until a security context is established.
Such a security context allows for mutual authentication of the two Such a security context allows for each party to authenticate the
parties, the passing of confidential or integrity-protected messages other, the passing of confidential and/or integrity-protected
between the initiator and acceptor, the generation of identical messages between the initiator and acceptor, the generation of
pseudo-random bit strings by both participants [RFC4401], and more. identical pseudo-random bit strings by both participants [RFC4401],
The number of tokens which must be exchanged between initiator and and more.
acceptor in order to establish the security context is dependent on
the underlying mechanism as well as the desired properties of the During context establishment, security context tokens are exchanged
security context, and is in general not known to the application. synchronously, one at a time; the initiator sends the first context
Accordingly, the application's control flow must include a loop token. The number of tokens which must be exchanged between
within which GSS security context tokens are exchanged, which initiator and acceptor in order to establish the security context is
terminates upon successful establishment of a security context (or an dependent on the underlying mechanism as well as the desired
error condition). properties of the security context, and is in general not known to
the application. Accordingly, the application's control flow must
include a loop within which GSS security context tokens are
exchanged, which terminates upon successful establishment of a
security context or an error condition. The GSS-API, together with
its security mechanisms, specifies the format and encoding of the
context tokens themselves, but the application protocol must specify
the necessary framing for the application to determine what octet
strings constitute GSS security context tokens and pass them into the
GSS-API implementation as appropriate.
The GSS-API C bindings [RFC2744] provide some example code for such a The GSS-API C bindings [RFC2744] provide some example code for such a
negotiation loop, but this code does not specify the application's negotiation loop, but this code does not specify the application's
behavior on unexpected or error conditions. As such, individual behavior on unexpected or error conditions. As such, individual
application protocol specifications have had to specify the structure application protocol specifications have had to specify the structure
of their GSS negotiation loops, including error handling, on a per- of their GSS negotiation loops, including error handling, on a per-
protocol basis. [RFC4462], [RFC3645], [RFC5801], [RFC4752], protocol basis. [RFC4462], [RFC3645], [RFC5801], [RFC4752],
[RFC2203] This represents a substantial duplication of effort, and [RFC2203] This represents a substantial duplication of effort, and
the various specifications go into different levels of detail and the various specifications go into different levels of detail and
describe different possible error conditions. It is therefore describe different possible error conditions. It is therefore
skipping to change at page 2, line 48 skipping to change at page 3, line 8
will perform that role. will perform that role.
The necessary requirements for correctly performing a GSS negotiation The necessary requirements for correctly performing a GSS negotiation
loop are essentially all included in [RFC2743], but they are loop are essentially all included in [RFC2743], but they are
scattered in many different places. This document brings all the scattered in many different places. This document brings all the
requirements together into one place for the convenience of requirements together into one place for the convenience of
implementors, even though the normative requirements remain in implementors, even though the normative requirements remain in
[RFC2743]. In a few places, this document notes additional behavior [RFC2743]. In a few places, this document notes additional behavior
which is useful for applications but is not mandated by [RFC2743]. which is useful for applications but is not mandated by [RFC2743].
2. Loop Structure 2. Application Protocol Requirements
Part of the purpose of this document is to guide the development of
new application protocols using the GSS-API, as well as the
development of new application software using such protocols. The
following list is features which are necessary or useful in such an
application protocol:
A way to frame and identify the initial context negotiation tokens
in the loop.
A way to frame and identify subsequent context-level tokens (e.g.,
error tokens) after a GSS_S_COMPLETE return.
Failing that, a way to indicate error status from one peer to the
other, possibly accompanied by a descriptive string.
A protocol may use the negotiated GSS security context for per-
message operations; in such cases, the protocol will need a way to
frame and identify those per-message tokens and the nature of
their contents. For example, a protocol message may be
accompanied by the output of GSS_GetMIC() over that message; the
protocol must identify the location and size of that MIC token,
and indicate that it is a MIC token and what cleartext it
corresponds to.
The application (not the protocol) should provide for
authorization checks in the acceptor. The GSS-API authenticates
the initiator, but does not make any claim about whether the
initiator is authorized for any given operation. In particular,
the initiator may be from a different portion of a federated
identity scheme.
3. Loop Structure
The loop is begun by the appropriately named initiator, which calls The loop is begun by the appropriately named initiator, which calls
GSS_Init_sec_context() with an empty (zero-length) input_token and a GSS_Init_sec_context() with an empty (zero-length) input_token and a
fixed set of input flags containing the desired attributes for the fixed set of input flags containing the desired attributes for the
security context. The initiator should not change any of the input security context. The initiator should not change any of the input
parameters to GSS_Init_sec_context() between calls to it during the parameters to GSS_Init_sec_context() between calls to it during the
loop, with the exception of the input_token parameter, which will loop, with the exception of the input_token parameter, which will
contain a message from the acceptor after the initial call, and the contain a message from the acceptor after the initial call, and the
input_context_handle, which must be the result returned in the input_context_handle, which must be the result returned in the
output_context_handle of the previous call to GSS_Init_sec_context() output_context_handle of the previous call to GSS_Init_sec_context()
(GSS_C_NO_CONTEXT for the first call). (In the C bindings, there is (GSS_C_NO_CONTEXT for the first call). (In the C bindings, there is
only a single read/modify context_handle argument, so the same only a single read/modify context_handle argument, so the same
variable should be passed for each call in the loop.) RFC 2743 only variable should be passed for each call in the loop.) RFC 2743 only
requires that the claimant_cred_handle argument remain constant over requires that the claimant_cred_handle argument remain constant over
all calls in the loop, but the other non-excepted arguments should all calls in the loop, but the other non-excepted arguments should
also remain fixed for reliable operation. also remain fixed for reliable operation.
The following subsections will describe the various steps of the The following subsections will describe the various steps of the
loop, without special consideration to whether a call to loop, without special consideration to whether a call to
GSS_Init_sec_context() or GSS_Accept_sec_context() is the first such GSS_Init_sec_context() or GSS_Accept_sec_context() is the first such
call in the loop. For the first call to each routine in the loop, call in the loop.
the major status code from the previous call to
GSS_Init_sec_context() or GSS_Accept_sec_context() should be taken as
GSS_S_CONTINUE_NEEDED.
2.1. Anonymous Initiators 3.1. Anonymous Initiators
If the initiator is requesting anonymity by setting the anon_req_flag If the initiator is requesting anonymity by setting the anon_req_flag
input to GSS_Init_sec_context(), then on non-error returns from input to GSS_Init_sec_context(), then on non-error returns from
GSS_Init_sec_context() (that is, when the major status is GSS_Init_sec_context() (that is, when the major status is
GSS_S_COMPLETE or GSS_S_CONTINUE_NEEDED), the initiator must verify GSS_S_COMPLETE or GSS_S_CONTINUE_NEEDED), the initiator must verify
that the output value of anon_state from GSS_Init_sec_context() is that the output value of anon_state from GSS_Init_sec_context() is
true before sending the security context token to the acceptor. true before sending the security context token to the acceptor.
Failing to perform this check could cause the initiator to lose Failing to perform this check could cause the initiator to lose
anonymity. anonymity.
2.2. GSS_Init_sec_context 3.2. GSS_Init_sec_context
The initiator calls GSS_Init_sec_context(), using the The initiator calls GSS_Init_sec_context(), using the
input_context_handle for the current proto-security-context and its input_context_handle for the current proto-security-context and its
fixed set of input parameters, and the input_token received from the fixed set of input parameters, and the input_token received from the
acceptor (if not the first iteration of the loop). The presence of a acceptor (if not the first iteration of the loop). The presence of a
nonempty output_token and the value of the major status code are the nonempty output_token and the value of the major status code are the
indicators for how to proceed: indicators for how to proceed:
If the major status code is GSS_S_COMPLETE and the output_token is If the major status code is GSS_S_COMPLETE and the output_token is
empty, then the context negotiation is fully complete and ready empty, then the context negotiation is fully complete and ready
skipping to change at page 4, line 24 skipping to change at page 5, line 17
is not compliant with [RFC2743]. However, there are some known is not compliant with [RFC2743]. However, there are some known
implementations of certain mechanisms which do produce empty implementations of certain mechanisms which do produce empty
context negotiation tokens. For maximum interoperability, context negotiation tokens. For maximum interoperability,
applications should be prepared to accept such tokens, and should applications should be prepared to accept such tokens, and should
transmit them to the acceptor if they are generated. transmit them to the acceptor if they are generated.
If the major status code is any other value, the context If the major status code is any other value, the context
negotiation has failed. If the output_token is nonempty, it is an negotiation has failed. If the output_token is nonempty, it is an
error token, and the initiator should send it to the acceptor. If error token, and the initiator should send it to the acceptor. If
the output_token is empty, then the initiator should indicate the the output_token is empty, then the initiator should indicate the
failure to the acceptor if an appropriate channel to do so is failure to the acceptor if an appropriate application-protocol
available. channel to do so is available.
2.3. Sending from Initiator to Acceptor 3.3. Sending from Initiator to Acceptor
The establishment of a GSS security context between initiator and The establishment of a GSS security context between initiator and
acceptor requires some communication channel by which to exchange the acceptor requires some communication channel by which to exchange the
context negotiation tokens. The nature of this channel is not context negotiation tokens. The nature of this channel is not
specified by the GSS specification -- it could be a synchronous TCP specified by the GSS specification -- it could be a dedicated TCP
channel, a UDP-based RPC protocol, or any other sort of channel. In channel, a UDP-based RPC protocol, or any other sort of channel. In
many cases, the channel will be multiplexed with non-GSS application many cases, the channel will be multiplexed with non-GSS application
data; the application protocol must provide some means by which the data; the application protocol must always provide some means by
GSS context tokens can be identified and passed through to the which the GSS context tokens can be identified (e.g., length and
mechanism accordingly. It is in such cases where the application start location) and passed through to the mechanism accordingly. The
protocol has a means to indicate error conditions that the initiator application protocol may also include a facility for indicating
could indicate a failure to the acceptor, as mentioned in some of the errors from one party to the other, which can be used to convey
above cases conditional on "an appropriate channel to do so". errors resulting from GSS-API calls, when appropriate (such as when
no error token was generated by the GSS-API implementation). Note
that GSS major and minor status codes are specified by language
bindings, not the abstract API; sending a major status code and
optionally the display form of the two error codes may be the best
that can be done in this case.
However, even the presence of a communication channel does not However, even the presence of a communication channel does not
necessarily indicate that it is appropriate for the initiator to necessarily indicate that it is appropriate for the initiator to
indicate such errors. For example, if the acceptor is a stateless or indicate such errors. For example, if the acceptor is a stateless or
near-stateless UDP server, there is probably no need for the near-stateless UDP server, there is probably no need for the
initiator to explicitly indicate its failure to the acceptor. initiator to explicitly indicate its failure to the acceptor.
Conditions such as this can be treated in individual application Conditions such as this can be treated in individual application
protocol specifications. protocol specifications.
If a regular security context output_token is produced by the call to If a regular security context output_token is produced by the call to
GSS_Init_sec_context(), the initiator must transmit this token to the GSS_Init_sec_context(), the initiator must transmit this token to the
acceptor over the application's communication channel. If the call acceptor over the application's communication channel. If the call
to GSS_Init_sec_context() returns an error token as output_token, it to GSS_Init_sec_context() returns an error token as output_token, it
is recommended that the intiator transmit this token to the acceptor is recommended that the intiator transmit this token to the acceptor
over the application's communication channel. over the application's communication channel.
2.4. Acceptor Sanity Checking 3.4. Acceptor Sanity Checking
The acceptor's half of the negotiation loop is triggered by the The acceptor's half of the negotiation loop is triggered by the
receipt of a context token from the initiator. Before calling receipt of a context token from the initiator. Before calling
GSS_Accept_sec_context(), the acceptor may find it useful to perform GSS_Accept_sec_context(), the acceptor may find it useful to perform
some sanity checks on the state of the negotiation loop. some sanity checks on the state of the negotiation loop.
If the acceptor receives a context token but was not expecting such a If the acceptor receives a context token but was not expecting such a
token (for example, if the acceptor's previous call to token (for example, if the acceptor's previous call to
GSS_Accept_sec_context() returned GSS_S_COMPLETE), this is probably GSS_Accept_sec_context() returned GSS_S_COMPLETE), this is probably
an error condition indicating that the initiator's state is invalid. an error condition indicating that the initiator's state is invalid.
See Section 3.2 for some exceptional cases. It is likely appropriate See Section 4.3 for some exceptional cases. It is likely appropriate
for the acceptor to report this error condition to the acceptor via for the acceptor to report this error condition to the acceptor via
the application's communication channel. the application's communication channel.
If the acceptor is expecting a context token (e.g., if the previous If the acceptor is expecting a context token (e.g., if the previous
call to GSS_Accept_sec_context() returned GSS_S_CONTINUE_NEEDED), but call to GSS_Accept_sec_context() returned GSS_S_CONTINUE_NEEDED), but
does not receive such a token within a reasonable amount of time does not receive such a token within a reasonable amount of time
after transmitting the previous output_token to the initiator, the after transmitting the previous output_token to the initiator, the
acceptor should assume that the initiator's state is invalid and fail acceptor should assume that the initiator's state is invalid (time
the GSS negotiation. Again, it is likely appropriate for the out) and fail the GSS negotiation. Again, it is likely appropriate
acceptor to report this error condition to the initiator via the for the acceptor to report this error condition to the initiator via
application's communication channel. the application's communication channel.
2.5. GSS_Accept_sec_context 3.5. GSS_Accept_sec_context
The GSS acceptor responds to the actions of an initiator; as such, The GSS acceptor responds to the actions of an initiator; as such,
there should always be a nonempty input_token to calls to there should always be a nonempty input_token to calls to
GSS_Accept_sec_context(). The input_context_handle parameter will GSS_Accept_sec_context(). The input_context_handle parameter will
always be given as the output_context_handle from the previous call always be given as the output_context_handle from the previous call
to GSS_Accept_sec_context() in a given negotiation loop (or to GSS_Accept_sec_context() in a given negotiation loop, or
GSS_C_NO_CONTEXT on the first call), but the acceptor_cred_handle and GSS_C_NO_CONTEXT on the first call, but the acceptor_cred_handle and
chan_bindings arguments should remain fixed over the course of a chan_bindings arguments should remain fixed over the course of a
given GSS negotiation loop. [RFC2743] only requires that the given GSS negotiation loop. [RFC2743] only requires that the
acceptor_cred_handle remain fixed throughout the loop, but the acceptor_cred_handle remain fixed throughout the loop, but the
chan_bindings argument should also remain fixed for reliable chan_bindings argument should also remain fixed for reliable
operation. operation.
The GSS acceptor calls GSS_Accept_sec_context(), using the The GSS acceptor calls GSS_Accept_sec_context(), using the
input_context_handle for the current proto-security-context and the input_context_handle for the current proto-security-context and the
input_token received from the initiator. The presence of a nonempty input_token received from the initiator. The presence of a nonempty
output_token and the value of the major status code are the output_token and the value of the major status code are the
skipping to change at page 6, line 32 skipping to change at page 7, line 32
is not compliant with [RFC2743]. However, there are some known is not compliant with [RFC2743]. However, there are some known
implementations of certain mechanisms which do produce empty implementations of certain mechanisms which do produce empty
context negotiation tokens. For maximum interoperability, context negotiation tokens. For maximum interoperability,
applications should be prepared to accept such tokens, and should applications should be prepared to accept such tokens, and should
transmit them to the initiator if they are generated. transmit them to the initiator if they are generated.
If the major status code is any other value, the context If the major status code is any other value, the context
negotiation has failed. If the output_token is nonempty, it is an negotiation has failed. If the output_token is nonempty, it is an
error token, and the acceptor should send it to the initiator. If error token, and the acceptor should send it to the initiator. If
the output_token is empty, then the acceptor should indicate the the output_token is empty, then the acceptor should indicate the
failure to the initiator if an appropriate channel to do so is failure to the initiator if an appropriate application-protocol
available. channel to do so is available.
2.6. Sending from Acceptor to Initiator 3.6. Sending from Acceptor to Initiator
The mechanism for sending the context token from acceptor to The mechanism for sending the context token from acceptor to
initiator will depend on the nature of the communication channel initiator will depend on the nature of the communication channel
between the two parties. For a synchronous bidirectional channel, it between the two parties. For a synchronous bidirectional channel, it
can be just another piece of data sent over the link, but for a can be just another piece of data sent over the link, but for a
stateless UDP RPC acceptor, the token will probably end up being sent stateless UDP RPC acceptor, the token will probably end up being sent
as an RPC output parameter. Application protocol specifications will as an RPC output parameter. Application protocol specifications will
need to specify the nature of this behavior. need to specify the nature of this behavior.
If the application protocol has the initiator driving the If the application protocol has the initiator driving the
application's control flow (with the acceptor just responding to application's control flow, it is particularly helpful for the
actions from the initiator), it is particularly helpful for the
acceptor to indicate a failure to the initiator, as mentioned in some acceptor to indicate a failure to the initiator, as mentioned in some
of the above cases conditional on "an appropriate channel to do so". of the above cases conditional on "an appropriate application-
protocol channel to do so".
If a regular security context output_token is produced by the call to If a regular security context output_token is produced by the call to
GSS_Accept_sec_context(), the acceptor must transmit this token to GSS_Accept_sec_context(), the acceptor must transmit this token to
the initiator over the application's communication channel. If the the initiator over the application's communication channel. If the
call to GSS_Accept_sec_context() returns an error token as call to GSS_Accept_sec_context() returns an error token as
output_token, it is recommended that the acceptor transmit this token output_token, it is recommended that the acceptor transmit this token
to the initiator over the application's communication channel. to the initiator over the application's communication channel.
2.7. Initiator input validation 3.7. Initiator input validation
The initiator's half of the negotiation loop is triggered (after the The initiator's half of the negotiation loop is triggered (after the
first call) by receipt of a context token from the acceptor. Before first call) by receipt of a context token from the acceptor. Before
calling GSS_Init_sec_context(), the initiator may find it useful to calling GSS_Init_sec_context(), the initiator may find it useful to
perform some sanity checks on the state of the negotiation loop. perform some sanity checks on the state of the negotiation loop.
If the initiator receives a context token but was not expecting such If the initiator receives a context token but was not expecting such
a token (for example, if the initiator's previous call to a token (for example, if the initiator's previous call to
GSS_Init_sec_context() returned GSS_S_COMPLETE), this is probably an GSS_Init_sec_context() returned GSS_S_COMPLETE), this is probably an
error condition indicating that the acceptor's state is invalid. See error condition indicating that the acceptor's state is invalid. See
Section 3.2 for some exceptional cases. It may be appropriate for Section 4.3 for some exceptional cases. It may be appropriate for
the initiator to report this error condition to the acceptor via the the initiator to report this error condition to the acceptor via the
application's communication channel. application's communication channel.
If the initiator is expecting a context token (that is, the previous If the initiator is expecting a context token (that is, the previous
call to GSS_Init_sec_context() returned GSS_S_CONTINUE_NEEDED), but call to GSS_Init_sec_context() returned GSS_S_CONTINUE_NEEDED), but
does not receive such a token within a reasonable amount of time does not receive such a token within a reasonable amount of time
after transmitting the previous output_token to the acceptor, the after transmitting the previous output_token to the acceptor, the
initiator should assume that the acceptor's state is invalid and fail initiator should assume that the acceptor's state is invalid and fail
the GSS negotiation. Again, it may be appropriate for the initiator the GSS negotiation. Again, it may be appropriate for the initiator
to report this error condition to the acceptor via the application's to report this error condition to the acceptor via the application's
communication channel. communication channel.
2.8. Continue the Loop 3.8. Continue the Loop
If the loop is in neither a success or failure condition, then the If the loop is in neither a success or failure condition, then the
loop must continue. Control flow returns to Section 2.2. loop must continue. Control flow returns to Section 3.2.
3. After Security Context Negotiation 4. After Security Context Negotiation
Once a party has completed its half of the security context and Once a party has completed its half of the security context and
fulfilled its obligations to the other party, the context is fulfilled its obligations to the other party, the context is
complete, but it is not necessarily ready and appropriate for use. complete, but it is not necessarily ready and appropriate for use.
(In some cases the context may be ready for use earlier than this, In particular, the security context flags may not be appropriate for
see Section 3.1.) In particular, the security context flags may not the given application's use. In some cases the context may be ready
be appropriate for the given application's use. for use before the negotiation is complete, see Section 4.2.
The initiator specifies as part of its fixed set of inputs to The initiator specifies as part of its fixed set of inputs to
GSS_Init_sec_context() values for the following booleans: GSS_Init_sec_context() values for all defined request flag booleans,
deleg_req_flag, mutual_req_flag, replay_det_req_flag, among them: deleg_req_flag, mutual_req_flag, replay_det_req_flag,
sequence_req_flag, conf_req_flag, and integ_req_flag. Upon sequence_req_flag, conf_req_flag, and integ_req_flag. Upon
completion of security context negotiation, the initiator must verify completion of the security context negotiation, the initiator must
that the values of the deleg_state, mutual_state, replay_det_state, verify that the values of the deleg_state, mutual_state,
sequence_state, conf_avail, and integ_avail flags from the last call replay_det_state, sequence_state, conf_avail, and integ_avail (and
to GSS_Init_sec_context() corresponding to the requested flags. If a any additional flags added by extensions) from the last call to
flag was requested but is not available, and that feature is GSS_Init_sec_context() correspond to the requested flags. If a flag
necessary for the appplication protocol, the initiator must destroy was requested but is not available, and that feature is necessary for
the security context and not use the security context for application the appplication protocol, the initiator must destroy the security
traffic. context and not use the security context for application traffic.
Application protocol specifications citing this document should Application protocol specifications citing this document should
indicate which context flags are required for their application indicate which context flags are required for their application
protocol. protocol.
The acceptor receives as output the following booleans: deleg_state, The acceptor receives as output the following booleans: deleg_state,
mutual_state, replay_det_state, sequence_state, anon_state, mutual_state, replay_det_state, sequence_state, anon_state,
trans_state, conf_avail, and integ_avail. The acceptor must verify trans_state, conf_avail, and integ_avail, and any additional flags
that any flags necessary for the application protocol are set. If a added by extensions to the GSS-API. The acceptor must verify that
any flags necessary for the application protocol are set. If a
necessary flag is not set, the acceptor must destroy the security necessary flag is not set, the acceptor must destroy the security
context and not use the security context for application traffic. context and not use the security context for application traffic.
3.1. Using Partially Complete Security Contexts 4.1. Authorization Checks
The acceptor receives as one of the outputs of
GSS_Accpet_sec_context() the name of the initiator which has
authenticated during the security context negotiation. Applications
need to implement authorization checks on this received name
('client_name' in the sample code) before providing access to
restricted resources. In particular, security context negotiation
can be successful when the client is anonymous or is from a different
identity realm than the acceptor, depending on the details of the
mechanism used by the GSS-API to establish the security context.
Acceptor applications can check which target name was used by the
initiator, but the details are out of scope for this document. See
[RFC2743] sections 2.2.6 and 1.1.5. Additional information can be
available in GSS-API Naming Extensions, [RFC6680].
4.2. Using Partially Complete Security Contexts
For mechanism/flag combinations that require multiple token For mechanism/flag combinations that require multiple token
exchanges, an application protocol may find it desirable to begin exchanges, the GSS-API specification [RFC2743] provides a
sending application data protected with GSS per-message operations prot_ready_state output value from GSS_Init_sec_context() and
while continuing to exchange security context tokens to complete the GSS_Accept_sec_context(), which indicates when per-message operations
security context negotiation. For example, an application may wish are available. However, many mechanism implementations do not
to reduce the number of round trips before application data is provide this functionality, and the analysis of the security
transmitted. The prot_ready_state output value from consequences of its use is rather complicated, so it is not expected
GSS_Init_sec_context() and GSS_Accept_sec_context() indicates when to be useful in most application protocols.
per-message operations are avaialble. Applications using per-message
operations on a partially complete security context must ensure that
there is some mechanism in place to prevent replays of those
messages.
Applications requiring confidentiality and/or integrity protection In particular, mutual authentication (if requested) is not guaranteed
from such messages must check the value of the conf_avail and/or until GSS_S_COMPLETE is returned. That is, an attacker could cause
integ_avail output flags from GSS_Init_sec_context()/ messages to be protected to the attacker instead of the actual
GSS_Accept_sec_context() as well as the conf_state output of target, followed by a context establishment failure. Accordingly,
GSS_Wrap() (if GSS_Wrap() is used). application protocols should not put sensitive information into
messages sent during security context establishment.
3.2. Additional Context Tokens 4.3. Additional Context Tokens
Under some (rare) conditions, a context token will be received by a Under some conditions, a context token will be received by a party to
party to a security context negotiation after that party has a security context negotiation after that party has completed the
completed the negotiation (i.e., after GSS_Init_sec_context() or negotiation (i.e., after GSS_Init_sec_context() or
GSS_Accept_sec_context() has returned GSS_S_COMPLETE). Such tokens GSS_Accept_sec_context() has returned GSS_S_COMPLETE). Such tokens
must be passed to GSS_Process_context_token() for processing. must be passed to GSS_Process_context_token() for processing. It may
not always be necessary for a mechanism implementation to generate an
error token on the intiator side, or for an initiator application to
transmit that token to the acceptor, but such decisions are out of
scope for this document. Both peers should always be prepared to
process such tokens, and application protocols should provide means
by which they can be transmitted.
The most common cause of such tokens is security context deletion Such tokens can be security context deletion tokens, emitted when the
tokens, emitted when the remote party called GSS_Delete_sec_context() remote party called GSS_Delete_sec_context() with a non-null
with a non-null output_context_token parameter. With the GSS-API output_context_token parameter, or error tokens, emitted when the
version 2, it is not recommended to use security context deletion remote party experiences an error processing the last token in a
tokens. security context negotiation exchange. Errors experienced when
processing tokens earlier in the negotiation would be transmitted as
normal security context tokens and processed by
GSS_Init_sec_context() or GSS_Accept_sec_context(), as appropriate.
With the GSS-API version 2, it is not recommended to use security
context deletion tokens, so error tokens are expected to be the most
common form of additional context token, for new application
protocols.
Extra security context tokens can also be emitted if the selected GSS_Process_context_token() may indicate an error in its major_status
mechanism specifies some functionality (such as per-message field if an error is encountered locally during token processing, or
confidentiality protection) as optional-to-implement, and the to indicate that an error was encountered on the peer and conveyed in
acceptor's implementation does not implement the optional an error token. Regardless of the major_status output of
functionality, but the functionality was requested by the initiator. GSS_Process_context_token(), GSS_Inquire_context() should be used
In this case, the acceptor's GSS implementation is required to emit after processing the extra token, to query the status of the security
at least one context token (even when one would not otherwise be context and whether it can supply the features necessary for the
needed to complete the context negotiation), and this can result in application protocol.
an "extra" token.
In the rare case when an application receives an extra context token, At present, all tokens which should be handled by
GSS_Inquire_context() should be used after processing the extra token GSS_Process_context_token() will lead to the security context being
to re-verify that the context does support the features necessary for effectively unusable. Future extensions to the GSS-API may allow for
the application protocol. This will also indicate whether the token applications to continue to function after a call to
was a deletion token, in which case the major status will be GSS_Process_context_token(), and it is expected that the outputs of
GSS_S_NO_CONTEXT. GSS_Inquire_context() will indicate whether it is safe to do so.
However, since there are no such extensions at present (error tokens
and deletion tokens both result in the security context being
essentially unusable), there is no guidance to give to applications
regarding this possibility at this time.
4. Sample Code Even if GSS_Process_context_token() processes an error or deletion
token which renders the context essentially unusable, the resources
associated with the context must eventually be freed with a call to
GSS_Delete_sec_context(), just as would be needed if
GSS_Init_sec_context() or GSS_Accept_sec_context() had returned an
error while processing an input context token and the
input_context_handle was not GSS_C_NO_CONTEXT. RFC 2743 has some
text which is slightly ambiguous in this regard, but the best
practice is to always call GSS_Delete_sec_context().
5. Sample Code
This section gives sample code for the GSS negotiation loop, both for This section gives sample code for the GSS negotiation loop, both for
a regular application and for an application where the initiator a regular application and for an application where the initiator
wishes to remain anonymous. Since the code for the two cases is very wishes to remain anonymous. Since the code for the two cases is very
similar, the anonymous-specific additions are wrapped in a similar, the anonymous-specific additions are wrapped in a
conditional check; that check and the conditional code may be ignored conditional check; that check and the conditional code may be ignored
if anonymous processing is not needed. if anonymous processing is not needed.
Since the communication channel between the initiator and acceptor is Since the communication channel between the initiator and acceptor is
a matter for individual application protocols, it is inherently a matter for individual application protocols, it is inherently
skipping to change at page 10, line 4 skipping to change at page 11, line 44
correct and general code to frame and transmit tokens requires a correct and general code to frame and transmit tokens requires a
substantial amount of error checking and would detract from the core substantial amount of error checking and would detract from the core
purpose of this document, so we only present the function signature purpose of this document, so we only present the function signature
for one example of what such functions might be, and leave some for one example of what such functions might be, and leave some
comments in the otherwise-empty function bodies. comments in the otherwise-empty function bodies.
This sample code is written in C, using the GSS-API C bindings This sample code is written in C, using the GSS-API C bindings
[RFC2744]. It uses the macro GSS_ERROR() to help unpack the various [RFC2744]. It uses the macro GSS_ERROR() to help unpack the various
sorts of information which can be stored in the major status field; sorts of information which can be stored in the major status field;
supplementary information does not necessarily indicate an error. supplementary information does not necessarily indicate an error.
Applications written in other languages will need to exercise care Applications written in other languages will need to exercise care
that checks against the major status value are written correctly. that checks against the major status value are written correctly.
This sample code should be compilable as a standalone program, linked This sample code should be compilable as a standalone program, linked
against a GSS-API library. In addition to supplying implementations against a GSS-API library. In addition to supplying implementations
for the token transmission/receipt routines, in order for the program for the token transmission/receipt routines, in order for the program
to successfully run when linked against most GSS-API libraries, the to successfully run when linked against most GSS-API libraries, the
initiator will need to specify an explicit target name for the initiator will need to specify an explicit target name for the
acceptor (which must match the credentials available to the acceptor, which must match the credentials available to the acceptor.
acceptor). A skeleton for how this may be done is provided, using a A skeleton for how this may be done is provided, using a dummy name.
dummy name.
This sample code assumes v2 of the GSS-API. Applications wishing to This sample code assumes v2 of the GSS-API. Applications wishing to
remain compatible with v1 of the GSS-API may need to perform remain compatible with v1 of the GSS-API may need to perform
additional checks in some locations. additional checks in some locations.
4.1. GSS Application Sample Code 5.1. GSS Application Sample Code
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include <err.h> #include <err.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <gssapi/gssapi.h> #include <gssapi/gssapi.h>
/* /*
* This helper is used only on buffers that we allocate ourselves (e.g., * This helper is used only on buffers that we allocate ourselves (e.g.,
* from receive_token()). Buffers allocated by GSS routines must use * from receive_token()). Buffers allocated by GSS routines must use
* gss_release_buffer(). * gss_release_buffer().
skipping to change at page 10, line 48 skipping to change at page 12, line 37
{ {
free(buf->value); free(buf->value);
buf->value = NULL; buf->value = NULL;
buf->length = 0; buf->length = 0;
} }
/* /*
* Helper to send a token on the specified fd. * Helper to send a token on the specified fd.
* *
* If errors are encountered, this routine must not directly cause * If errors are encountered, this routine must not directly cause
* termination of the process (i.e., by errx()), because compliant GSS * termination of the process, because compliant GSS applications
* applications must release resources allocated by the GSS library * must release resources allocated by the GSS library before
* before exiting. (These resources may be non-local to the current * exiting.
* process.)
*/ */
static int static int
send_token(int fd, gss_buffer_t token) send_token(int fd, gss_buffer_t token)
{ {
/* /*
* Supply token framing and transmission code here. * Supply token framing and transmission code here.
* *
* It is advisable for the application protocol to specify the * It is advisable for the application protocol to specify the
* length of the token being transmitted, unless the underlying * length of the token being transmitted, unless the underlying
* transit does so implicitly. * transit does so implicitly.
* *
skipping to change at page 11, line 26 skipping to change at page 13, line 14
* syscall(s) are used to send data, applications should have * syscall(s) are used to send data, applications should have
* a loop to handle EINTR returns. * a loop to handle EINTR returns.
*/ */
return 1; return 1;
} }
/* /*
* Helper to receive a token on the specified fd. * Helper to receive a token on the specified fd.
* *
* If errors are encountered, this routine must not directly cause * If errors are encountered, this routine must not directly cause
* termination of the process (i.e., by errx()), because compliant GSS * termination of the process, because compliant GSS applications
* applications must release resources allocated by the GSS library * must release resources allocated by the GSS library before
* before exiting. (These resources may be non-local to the current * exiting.
* process.)
*/ */
static int static int
receive_token(int fd, gss_buffer_t token) receive_token(int fd, gss_buffer_t token)
{ {
/* /*
* Supply token framing and transmission code here. * Supply token framing and transmission code here.
* *
* In addition to checking for error returns from whichever * In addition to checking for error returns from whichever
* syscall(s) are used to receive data, applications should have * syscall(s) are used to receive data, applications should have
* a loop to handle EINTR returns. * a loop to handle EINTR returns.
skipping to change at page 12, line 4 skipping to change at page 13, line 40
*/ */
return 1; return 1;
} }
static void static void
do_initiator(int readfd, int writefd, int anon) do_initiator(int readfd, int writefd, int anon)
{ {
int initiator_established = 0, ret; int initiator_established = 0, ret;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
OM_uint32 major, minor, req_flags, ret_flags; OM_uint32 major, minor, req_flags, ret_flags;
gss_buffer_desc input_token, output_token, name_buf; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER;
gss_name_t target_name = GSS_C_NO_NAME; gss_name_t target_name = GSS_C_NO_NAME;
memset(&input_token, 0, sizeof(input_token));
memset(&output_token, 0, sizeof(output_token));
memset(&name_buf, 0, sizeof(name_buf));
/* Applications should set target_name to a real value. */ /* Applications should set target_name to a real value. */
name_buf.value = "<service>@<hostname.domain>"; name_buf.value = "<service>@<hostname.domain>";
name_buf.length = strlen(name_buf.value); name_buf.length = strlen(name_buf.value);
major = gss_import_name(&minor, &name_buf, major = gss_import_name(&minor, &name_buf,
GSS_C_NT_HOSTBASED_SERVICE, &target_name); GSS_C_NT_HOSTBASED_SERVICE, &target_name);
if (GSS_ERROR(major)) {
warnx(1, "Could not import name\n");
goto cleanup;
}
/* Mutual authentication will require a token from acceptor to /* Mutual authentication will require a token from acceptor to
* initiator, and thus a second call to gss_init_sec_context(). */ * initiator, and thus a second call to gss_init_sec_context(). */
req_flags = GSS_C_MUTUAL_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG; req_flags = GSS_C_MUTUAL_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG;
if (anon) if (anon)
req_flags |= GSS_C_ANON_FLAG; req_flags |= GSS_C_ANON_FLAG;
while (!initiator_established) { while (!initiator_established) {
/* The initiator_cred_handle, mech_type, time_req, /* The initiator_cred_handle, mech_type, time_req,
* input_chan_bindings, actual_mech_type, and time_rec * input_chan_bindings, actual_mech_type, and time_rec
skipping to change at page 13, line 46 skipping to change at page 15, line 36
/* We are required to release storage for nonzero-length output /* We are required to release storage for nonzero-length output
* tokens. gss_release_buffer() zeros the length, so we are * tokens. gss_release_buffer() zeros the length, so we are
* will not attempt to release the same buffer twice. */ * will not attempt to release the same buffer twice. */
if (output_token.length > 0) if (output_token.length > 0)
(void)gss_release_buffer(&minor, &output_token); (void)gss_release_buffer(&minor, &output_token);
/* Do not request a context deletion token; pass NULL. */ /* Do not request a context deletion token; pass NULL. */
(void)gss_delete_sec_context(&minor, &ctx, NULL); (void)gss_delete_sec_context(&minor, &ctx, NULL);
(void)gss_release_name(&minor, &target_name); (void)gss_release_name(&minor, &target_name);
} }
/*
* Perform authorization checks on the initiator's GSS name object.
*
* Returns 0 on success (the initiator is authorized) and nonzero
* when the initiator is not authorized.
*/
static int
check_authz(gss_name_t *client_name)
{
/*
* Supply authorization checking code here.
*
* Options include bitwise comparison of the exported name against
* a local database, and introspection against name attributes.
*/
return 0;
}
static void static void
do_acceptor(int readfd, int writefd) do_acceptor(int readfd, int writefd)
{ {
int acceptor_established = 0, ret; int acceptor_established = 0, ret;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
OM_uint32 major, minor, ret_flags; OM_uint32 major, minor, ret_flags;
gss_buffer_desc input_token, output_token; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
gss_name_t client_name; gss_name_t client_name;
memset(&input_token, 0, sizeof(input_token));
memset(&output_token, 0, sizeof(output_token));
major = GSS_S_CONTINUE_NEEDED; major = GSS_S_CONTINUE_NEEDED;
while(!acceptor_established) { while(!acceptor_established) {
if (major & GSS_S_CONTINUE_NEEDED) { if (major & GSS_S_CONTINUE_NEEDED) {
ret = receive_token(readfd, &input_token); ret = receive_token(readfd, &input_token);
if (ret != 0) if (ret != 0)
goto cleanup; goto cleanup;
} else if (major == GSS_S_COMPLETE) { } else if (major == GSS_S_COMPLETE) {
acceptor_established = 1; acceptor_established = 1;
break; break;
skipping to change at page 15, line 20 skipping to change at page 17, line 25
* gss_release_buffer() is safe to call on the output buffer * gss_release_buffer() is safe to call on the output buffer
* from gss_accept_sec_context(), even if there is no storage * from gss_accept_sec_context(), even if there is no storage
* associated with that buffer. */ * associated with that buffer. */
(void)gss_release_buffer(&minor, &output_token); (void)gss_release_buffer(&minor, &output_token);
} /* while(!acceptor_established) */ } /* while(!acceptor_established) */
if (!(ret_flags & GSS_C_INTEG_FLAG)) { if (!(ret_flags & GSS_C_INTEG_FLAG)) {
warnx("Negotiated context does not support integrity\n"); warnx("Negotiated context does not support integrity\n");
goto cleanup; goto cleanup;
} }
printf("Acceptor's context negotiation successful\n"); printf("Acceptor's context negotiation successful\n");
ret = check_authz(&client_name);
if (ret != 0)
printf("Client is not authorized; rejecting access\n");
cleanup: cleanup:
release_buffer(&input_token); release_buffer(&input_token);
/* We are required to release storage for nonzero-length output /* We are required to release storage for nonzero-length output
* tokens. gss_release_buffer() zeros the length, so we are * tokens. gss_release_buffer() zeros the length, so we are
* will not attempt to release the same buffer twice. */ * will not attempt to release the same buffer twice. */
if (output_token.length > 0) if (output_token.length > 0)
(void)gss_release_buffer(&minor, &output_token); (void)gss_release_buffer(&minor, &output_token);
/* Do not request a context deletion token, pass NULL. */ /* Do not request a context deletion token, pass NULL. */
(void)gss_delete_sec_context(&minor, &ctx, NULL); (void)gss_delete_sec_context(&minor, &ctx, NULL);
(void)gss_release_name(&minor, &client_name); (void)gss_release_name(&minor, &client_name);
skipping to change at page 15, line 44 skipping to change at page 18, line 4
{ {
pid_t pid; pid_t pid;
int fd1 = -1, fd2 = -1; int fd1 = -1, fd2 = -1;
/* Create fds for reading/writing here. */ /* Create fds for reading/writing here. */
pid = fork(); pid = fork();
if (pid == 0) if (pid == 0)
do_initiator(fd1, fd2, 0); do_initiator(fd1, fd2, 0);
else if (pid > 0) else if (pid > 0)
do_acceptor(fd2, fd1); do_acceptor(fd2, fd1);
else else
err(1, "fork() failed\n"); err(1, "fork() failed\n");
exit(0); exit(0);
} }
5. Security Considerations
6. Security Considerations
This document provides a (reasonably) concise description and example This document provides a (reasonably) concise description and example
for correct construction of the GSS-API security context negotiation for correct construction of the GSS-API security context negotiation
loop. Since everything relating to the construction and use of a GSS loop. Since everything relating to the construction and use of a GSS
security context is security-related, there are security-relevant security context is security-related, there are security-relevant
considerations throughout the document. It is useful to call out a considerations throughout the document. It is useful to call out a
few things in this section, though. few things in this section, though.
The GSS-API uses a request-and-check model for features. An The GSS-API uses a request-and-check model for features. An
application using the GSS-API requests that certain features application using the GSS-API requests that certain features
(confidentiality protection for messages, or anonymity), but such a (confidentiality protection for messages, or anonymity), but such a
request does not require the GSS implementation to provide that request does not require the GSS implementation to provide that
feature. The application must check the returned flags to verify feature. The application must check the returned flags to verify
whether a requested feature is present; if the feature was non- whether a requested feature is present; if the feature was non-
optional for the application, the application must generate an error. optional for the application, the application must generate an error.
Phrased differently, the GSS-API will not generate an error if it is Phrased differently, the GSS-API will not generate an error if it is
unable to satisfy the features requested by the application. unable to satisfy the features requested by the application.
6. References In many cases it is convenient for GSS acceptors to accept security
context using multiple acceptor names (such as by using the default
credential set, as happens when GSS_C_NO_CREDENTIAL is passed to
GSS_Accept_sec_context()). This allows acceptors to use any
credentials to which it has access for accepting security contexts,
which may not be the desired behavior for a given application. (For
example, sshd may only wish to accept only using GSS_C_NT_HOSTBASED
credentials of the form host@<hostname>, and not nfs@<hostname>.)
Acceptor applications can check which target name was used by the
initiator, but the details are out of scope for this document. See
[RFC2743] sections 2.2.6 and 1.1.5.
6.1. Normative References The C sample code uses the macro GSS_ERROR() to assess the return
value of gss_init_sec_context() and gss_accept_sec_context(). This
is done to indicate where checks are needed in writing code for other
languages and what the nature of those checks might be. The C code
could be made simpler by omitting that macro. Use of the GSS_ERROR()
macro on the results of GSS-API per-message operations has resulted
in security vulnerabilities in existing software! In applications
expecting to receive protected octet streams, this macro should not
be used on the result of per-message operations, as it omits checking
for supplementary status values such as GSS_S_DUPLICATE_TOKEN,
GSS_S_OLD_TOKEN, etc..
7. References
7.1. Normative References
[RFC2743] Linn, J., "Generic Security Service Application Program [RFC2743] Linn, J., "Generic Security Service Application Program
Interface Version 2, Update 1", RFC 2743, January 2000. Interface Version 2, Update 1", RFC 2743, January 2000.
[RFC2744] Wray, J., "Generic Security Service API Version 2 : [RFC2744] Wray, J., "Generic Security Service API Version 2 :
C-bindings", RFC 2744, January 2000. C-bindings", RFC 2744, January 2000.
6.2. Informational References 7.2. Informational References
[RFC4462] Hutzelman, J., Salowey, J., Galbraith, J., and V. Welch, [RFC4462] Hutzelman, J., Salowey, J., Galbraith, J., and V. Welch,
"Generic Security Service Application Program Interface "Generic Security Service Application Program Interface
(GSS-API) Authentication and Key Exchange for the Secure (GSS-API) Authentication and Key Exchange for the Secure
Shell (SSH) Protocol", RFC 4462, May 2006. Shell (SSH) Protocol", RFC 4462, May 2006.
[RFC4401] Williams, N., "A Pseudo-Random Function (PRF) API [RFC4401] Williams, N., "A Pseudo-Random Function (PRF) API
Extension for the Generic Security Service Application Extension for the Generic Security Service Application
Program Interface (GSS-API)", RFC 4401, February 2006. Program Interface (GSS-API)", RFC 4401, February 2006.
skipping to change at page 17, line 17 skipping to change at page 19, line 43
in Simple Authentication and Security Layer (SASL): The in Simple Authentication and Security Layer (SASL): The
GS2 Mechanism Family", RFC 5801, July 2010. GS2 Mechanism Family", RFC 5801, July 2010.
[RFC4752] Melnikov, A., "The Kerberos V5 ("GSSAPI") Simple [RFC4752] Melnikov, A., "The Kerberos V5 ("GSSAPI") Simple
Authentication and Security Layer (SASL) Mechanism", RFC Authentication and Security Layer (SASL) Mechanism", RFC
4752, November 2006. 4752, November 2006.
[RFC2203] Eisler, M., Chiu, A., and L. Ling, "RPCSEC_GSS Protocol [RFC2203] Eisler, M., Chiu, A., and L. Ling, "RPCSEC_GSS Protocol
Specification", RFC 2203, September 1997. Specification", RFC 2203, September 1997.
[RFC6680] Williams, N., Johansson, L., Hartman, S., and S.
Josefsson, "Generic Security Service Application
Programming Interface (GSS-API) Naming Extensions", RFC
6680, August 2012.
Appendix A. Acknowledgements Appendix A. Acknowledgements
Thanks to Nico Williams and Jeff Hutzleman for prompting me to write Thanks to Nico Williams and Jeff Hutzleman for prompting me to write
this document. this document.
Author's Address Author's Address
Benjamin Kaduk Benjamin Kaduk
MIT Kerberos Consortium MIT Kerberos Consortium
 End of changes. 61 change blocks. 
140 lines changed or deleted 271 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/