Internet Engineering Task Force (IETF)                          B. Kaduk
Request for Comments: 7546                                           MIT
Category: Informational                                         May 2015
ISSN: 2070-1721
        
Internet Engineering Task Force (IETF)                          B. Kaduk
Request for Comments: 7546                                           MIT
Category: Informational                                         May 2015
ISSN: 2070-1721
        

Structure of the Generic Security Service (GSS) Negotiation Loop

通用安全服务(GSS)协商循环的结构

Abstract

摘要

This document specifies the generic structure of the negotiation loop to establish a Generic Security Service (GSS) security context between initiator and acceptor. The control flow of the loop is indicated for both parties, including error conditions, and indications are given for where application-specific behavior must be specified.

本文档指定协商循环的通用结构,以在发起方和接受方之间建立通用安全服务(GSS)安全上下文。回路的控制流为双方指明,包括错误条件,并指明必须指定应用程序特定行为的位置。

Status of This Memo

关于下段备忘

This document is not an Internet Standards Track specification; it is published for informational purposes.

本文件不是互联网标准跟踪规范;它是为了提供信息而发布的。

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Not all documents approved by the IESG are a candidate for any level of Internet Standard; see Section 2 of RFC 5741.

本文件是互联网工程任务组(IETF)的产品。它代表了IETF社区的共识。它已经接受了公众审查,并已被互联网工程指导小组(IESG)批准出版。并非IESG批准的所有文件都适用于任何级别的互联网标准;见RFC 5741第2节。

Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at http://www.rfc-editor.org/info/rfc7546.

有关本文件当前状态、任何勘误表以及如何提供反馈的信息,请访问http://www.rfc-editor.org/info/rfc7546.

Copyright Notice

版权公告

Copyright (c) 2015 IETF Trust and the persons identified as the document authors. All rights reserved.

版权所有(c)2015 IETF信托基金和确定为文件作者的人员。版权所有。

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.

本文件受BCP 78和IETF信托有关IETF文件的法律规定的约束(http://trustee.ietf.org/license-info)自本文件出版之日起生效。请仔细阅读这些文件,因为它们描述了您对本文件的权利和限制。从本文件中提取的代码组件必须包括信托法律条款第4.e节中所述的简化BSD许可证文本,并提供简化BSD许可证中所述的无担保。

Table of Contents

目录

   1. Introduction ....................................................2
   2. Application Protocol Requirements ...............................3
   3. Loop Structure ..................................................4
      3.1. Anonymous Initiators .......................................5
      3.2. GSS_Init_sec_context .......................................5
      3.3. Sending from Initiator to Acceptor .........................6
      3.4. Acceptor Sanity Checking ...................................6
      3.5. GSS_Accept_sec_context .....................................7
      3.6. Sending from Acceptor to Initiator .........................8
      3.7. Initiator Input Validation .................................9
      3.8. Continue the Loop ..........................................9
   4. After Security Context Negotiation ..............................9
      4.1. Authorization Checks ......................................10
      4.2. Using Partially Complete Security Contexts ................10
      4.3. Additional Context Tokens .................................11
   5. Sample Code ....................................................12
      5.1. GSS Application Sample Code ...............................13
   6. Security Considerations ........................................19
   7. References .....................................................20
      7.1. Normative References ......................................20
      7.2. Informative References ....................................20
   Acknowledgements ..................................................21
   Author's Address ..................................................21
        
   1. Introduction ....................................................2
   2. Application Protocol Requirements ...............................3
   3. Loop Structure ..................................................4
      3.1. Anonymous Initiators .......................................5
      3.2. GSS_Init_sec_context .......................................5
      3.3. Sending from Initiator to Acceptor .........................6
      3.4. Acceptor Sanity Checking ...................................6
      3.5. GSS_Accept_sec_context .....................................7
      3.6. Sending from Acceptor to Initiator .........................8
      3.7. Initiator Input Validation .................................9
      3.8. Continue the Loop ..........................................9
   4. After Security Context Negotiation ..............................9
      4.1. Authorization Checks ......................................10
      4.2. Using Partially Complete Security Contexts ................10
      4.3. Additional Context Tokens .................................11
   5. Sample Code ....................................................12
      5.1. GSS Application Sample Code ...............................13
   6. Security Considerations ........................................19
   7. References .....................................................20
      7.1. Normative References ......................................20
      7.2. Informative References ....................................20
   Acknowledgements ..................................................21
   Author's Address ..................................................21
        
1. Introduction
1. 介绍

"Generic Security Service Application Program Interface Version 2, Update 1" [RFC2743] provides a generic interface for security services in the form of an abstraction layer over the underlying security mechanisms that an application may use. A GSS initiator and acceptor exchange messages, called "tokens", until a security context is established. Such a security context allows for each party to authenticate the other, the passing of confidential and/or integrity-protected messages between the initiator and acceptor, the generation of identical pseudorandom bit strings by both participants [RFC4401], and more.

“通用安全服务应用程序接口版本2,更新1”[RFC2743]以应用程序可能使用的底层安全机制上的抽象层的形式为安全服务提供通用接口。GSS发起方和接收方交换消息,称为“令牌”,直到建立安全上下文。这样的安全上下文允许每一方对另一方进行身份验证,在发起方和接受方之间传递机密和/或完整性保护消息,由两个参与者生成相同的伪随机比特串[RFC4401],等等。

During context establishment, security context tokens are exchanged synchronously, one at a time; the initiator sends the first context token. The number of tokens that must be exchanged between the initiator and acceptor in order to establish the security context is dependent on the underlying mechanism as well as the desired 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; the loop terminates upon successful establishment of a

在上下文建立期间,同步交换安全上下文令牌,一次交换一个;启动器发送第一个上下文令牌。为了建立安全上下文,必须在发起方和接受方之间交换的令牌数量取决于底层机制以及安全上下文的所需属性,通常应用程序不知道。因此,应用程序的控制流必须包括一个循环,在该循环中交换GSS安全上下文令牌;循环在成功建立循环后终止

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.

安全上下文或错误条件。GSS-API及其安全机制规定了上下文标记本身的格式和编码,但应用程序协议必须为应用程序指定必要的帧,以确定哪些八位组字符串构成GSS安全上下文标记,并酌情将其传递到GSS-API实现中。

The GSS-API C-bindings [RFC2744] provide some example code for such a negotiation loop, but this code does not specify the application's behavior on unexpected or error conditions. As such, individual application protocol specifications have had to specify the structure of their GSS negotiation loops, including error handling, on a per-protocol basis (see [RFC4462], [RFC3645], [RFC5801], [RFC4752], and [RFC2203]). This represents a substantial duplication of effort, and the various specifications go into different levels of detail and describe different possible error conditions. Therefore, it is preferable to have the structure of the GSS negotiation loop, including error conditions and token passing, described in a single specification that can then be referred to from other documents in lieu of repeating the structure of the loop each time. This document fills that role.

GSS-API C-bindings[RFC2744]为这种协商循环提供了一些示例代码,但这些代码没有指定应用程序在意外或错误条件下的行为。因此,各个应用程序协议规范必须在每个协议的基础上指定其GSS协商循环的结构,包括错误处理(请参阅[RFC4462]、[RFC3645]、[RFC5801]、[RFC4752]和[RFC2203])。这意味着大量的工作重复,不同的规范深入到不同的细节层次,并描述了不同的可能错误情况。因此,优选在单个规范中描述GSS协商循环的结构,包括错误条件和令牌传递,然后可以从其他文档中引用该规范,而不是每次重复循环的结构。此文档填补了该角色。

The necessary requirements for correctly performing a GSS negotiation loop are essentially all included in [RFC2743], but they are scattered in many different places. This document brings all the requirements together into one place for the convenience of implementors, even though the normative requirements remain in [RFC2743]. In a few places, this document notes additional behavior that is useful for applications but is not mandated by [RFC2743].

正确执行GSS协商循环的必要要求基本上都包含在[RFC2743]中,但它们分散在许多不同的地方。本文件将所有要求集中在一个地方,以方便实施者,即使规范性要求仍保留在[RFC2743]中。在一些地方,本文档记录了对应用程序有用但[RFC2743]未强制要求的其他行为。

2. Application Protocol Requirements
2. 应用程序协议要求

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 consists of features that are necessary or useful in such an application protocol:

本文档的部分目的是指导使用GSS-API开发新的应用程序协议,以及使用此类协议开发新的应用程序软件。以下列表包含在此类应用协议中必要或有用的功能:

o Protocols require a way to frame and identify security context negotiation tokens during the GSS negotiation loop.

o 在GSS协商循环期间,协议需要一种框架和标识安全上下文协商令牌的方法。

o Error tokens should generally also get special framing, as the recipient may have no other way to distinguish unexpected error context tokens from per-message tokens.

o 错误标记通常也应该得到特殊的帧,因为收件人可能没有其他方法来区分意外的错误上下文标记和每消息标记。

o Protocols may benefit from a generic means of indicating an error, possibly accompanied by a descriptive string, to be used if error tokens are not available or not usable due to constraints of the application protocol.

o 如果由于应用协议的限制,错误令牌不可用或不可用,则协议可受益于指示错误的通用方法(可能伴随描述性字符串)。

o 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 Message Identity Code (MIC) token and indicate that it is a MIC token and to what cleartext it corresponds.

o 协议可将协商的GSS安全上下文用于每消息操作;在这种情况下,协议将需要一种方法来框架和识别这些每消息令牌及其内容的性质。例如,协议消息可能伴随着该消息上GSS_GetMIC()的输出;协议必须识别该消息标识码(MIC)令牌的位置和大小,并指示它是一个MIC令牌以及它对应的明文。

o Applications are responsible for authorization of the authenticated peer principal names that are supplied by the GSS-API. Such names are mechanism specific and may come from a different portion of a federated identity scheme. Application protocols may need to supply additional information to support the authorization of access to a given resource, such as the Secure Shell version 2 (SSHv2) "username" parameter.

o 应用程序负责授权GSS-API提供的经过身份验证的对等主体名称。这些名称是特定于机制的,可能来自联邦身份方案的不同部分。应用程序协议可能需要提供额外的信息来支持对给定资源的访问授权,例如Secure Shell version 2(SSHv2)“username”参数。

3. Loop Structure
3. 环结构

The loop is begun by the appropriately named initiator, which calls GSS_Init_sec_context() with an empty (zero-length) input_token and a fixed set of input flags containing the desired attributes for the security context. The initiator should not change any of the input parameters to GSS_Init_sec_context() between calls to it during the loop, with the exception of the input_token parameter, which will contain a message from the acceptor after the initial call, and the input_context_handle, which must be the result returned in the 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 only a single read/modify context_handle argument, so the same variable should be passed for each call in the loop.) RFC 2743 only requires that the claimant_cred_handle argument remain constant over all calls in the loop, but the other non-excepted arguments should also remain fixed for reliable operation.

循环由适当命名的启动器开始,该启动器使用空(零长度)输入标记和包含安全上下文所需属性的固定输入标志集调用GSS_Init_sec_context()。在循环期间对发起程序的调用之间,发起程序不应将任何输入参数更改为GSS_Init_sec_context(),但input_令牌参数除外,该参数将在初始调用后包含来自接收方的消息,以及input_context_句柄,它必须是上一次调用GSS_Init_sec_context()的输出_context_句柄中返回的结果(第一次调用的GSS_C_NO_context)。(在C绑定中,只有一个read/modify context_handle参数,因此应该为循环中的每个调用传递相同的变量。)RFC 2743只要求claimer_cred_handle参数在循环中的所有调用上保持不变,但其他非例外参数也应该保持不变,以便可靠操作。

The following subsections will describe the various steps of the loop, without special consideration to whether a call to GSS_Init_sec_context() or GSS_Accept_sec_context() is the first such call in the loop.

以下小节将描述循环的各个步骤,不特别考虑对GSS_Init_sec_context()或GSS_Accept_sec_context()的调用是否是循环中的第一个此类调用。

3.1. Anonymous Initiators
3.1. 匿名发起人

If the initiator is requesting anonymity by setting the anon_req_flag input to GSS_Init_sec_context(), then on non-error returns from GSS_Init_sec_context() (that is, when the major status is 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 true before sending the security context token to the acceptor. Failing to perform this check could cause the initiator to lose anonymity.

如果启动器通过将anon_req_标志输入设置为GSS_Init_sec_context(),请求匿名,则在非错误情况下从GSS_Init_sec_context()返回(即,当主要状态为GSS_S_COMPLETE或需要GSS_S_CONTINUE_时),启动器必须验证GSS_Init_sec_context()的anon_状态的输出值在将安全上下文令牌发送给接受者之前为true。未能执行此检查可能会导致启动器失去匿名性。

3.2. GSS_Init_sec_context
3.2. GSS_初始_秒_上下文

The initiator calls GSS_Init_sec_context() using the input_context_handle for the current security context being established and its fixed set of input parameters and the input_token received from the acceptor (if this is not the first iteration of the loop). The presence or absence of a nonempty output_token and the value of the major status code are the indicators for how to proceed:

发起者使用正在建立的当前安全上下文的输入上下文句柄及其固定的输入参数集和从接受者接收的输入令牌(如果这不是循环的第一次迭代),调用GSS_Init_sec_context()。非空输出令牌的存在或不存在以及主要状态代码的值是如何继续的指示器:

o If the major status code is GSS_S_COMPLETE and the output_token is empty, then the context negotiation is fully complete and ready for use by the initiator with no further actions.

o 如果主要状态代码为GSS_S_COMPLETE,且输出_令牌为空,则上下文协商已完全完成,并且已准备好供启动器使用,无需进一步操作。

o If the major status code is GSS_S_COMPLETE and the output_token is nonempty, then the initiator's portion of the security context negotiation is complete but the acceptor's is not. The initiator must send the output_token to the acceptor so that the acceptor can establish its half of the security context.

o 如果主状态代码为GSS_S_COMPLETE,且输出_令牌为非空,则安全上下文协商的发起方部分已完成,但接受方部分未完成。发起者必须将输出令牌发送给接受者,以便接受者可以建立其一半的安全上下文。

o If the major status code is GSS_S_CONTINUE_NEEDED and the output_token is nonempty, the context negotiation is incomplete. The initiator must send the output_token to the acceptor and await another input_token from the acceptor.

o 如果主要状态代码为GSS_S_CONTINUE_NEEDED,且输出标记为非空,则上下文协商不完整。发起者必须将输出\u令牌发送给接受者,并等待接受者的另一个输入\u令牌。

o If the major status code is GSS_S_CONTINUE_NEEDED and the output_token is empty, the mechanism has produced an output that is not compliant with [RFC2743]. However, there are some known implementations of certain mechanisms such as NT LAN Manager Security Support Provider [NTLMSSP] that do produce empty context negotiation tokens. For maximum interoperability, applications should be prepared to accept such tokens and should transmit them to the acceptor if they are generated.

o 如果主要状态代码为GSS_S_CONTINUE_NEEDED且输出_令牌为空,则该机制产生的输出不符合[RFC2743]。然而,某些机制(如NT LAN Manager安全支持提供程序[NTLMSSP])的一些已知实现确实会产生空的上下文协商令牌。为了实现最大的互操作性,应用程序应准备好接受此类令牌,并在生成令牌时将其传输给接受者。

o If the major status code is any other value, the context negotiation has failed. If the output_token is nonempty, it is an error token and the initiator should send it to the acceptor. If the output_token is empty, then the initiator should indicate the failure to the acceptor if an appropriate application-protocol channel to do so is available.

o 如果主状态代码为任何其他值,则上下文协商失败。如果输出令牌为非空,则它是一个错误令牌,发起者应将其发送给接受者。如果输出_令牌为空,则发起方应在适当的应用程序协议通道可用时向接收方指示失败。

3.3. Sending from Initiator to Acceptor
3.3. 从发起者发送到接受者

The establishment of a GSS security context between initiator and acceptor requires some communication channel by which to exchange the context negotiation tokens. The nature of this channel is not specified by the GSS specification -- it could be a dedicated TCP channel, a UDP-based Remote Procedure Call (RPC) protocol, or any other sort of channel. In many cases, the channel will be multiplexed with non-GSS application data; the application protocol must always provide some means by which the GSS context tokens can be identified (e.g., length and start location) and passed through to the mechanism accordingly. The application protocol may also include a facility for indicating errors from one party to the other, which can be used to convey 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.

在发起方和接受方之间建立GSS安全上下文需要一些通信通道来交换上下文协商令牌。GSS规范没有指定此通道的性质——它可以是专用TCP通道、基于UDP的远程过程调用(RPC)协议或任何其他类型的通道。在许多情况下,信道将与非GSS应用数据复用;应用程序协议必须始终提供一些方法,通过这些方法可以识别GSS上下文令牌(例如,长度和开始位置),并相应地传递给机制。应用协议还可包括用于从一方向另一方指示错误的设施,其可用于在适当时(例如当GSS-API实现未生成错误令牌时)传递由GSS-API调用产生的错误。请注意,GSS主要和次要状态代码是由语言绑定指定的,而不是抽象API;在这种情况下,发送主要状态代码和两个错误代码的显示形式(可选)可能是最好的选择。

However, even the presence of a communication channel does not necessarily indicate that it is appropriate for the initiator to indicate such errors. For example, if the acceptor is a stateless or near-stateless UDP server, there is probably no need for the initiator to explicitly indicate its failure to the acceptor. Conditions such as this can be treated in individual application protocol specifications.

然而,即使存在通信信道也不一定表示发起方指示此类错误是适当的。例如,如果接受程序是无状态或接近无状态的UDP服务器,则发起程序可能不需要向接受程序显式指示其失败。此类情况可在单独的应用协议规范中处理。

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 acceptor over the application's communication channel. If the call to GSS_Init_sec_context() returns an error token as output_token, it is recommended that the initiator transmit this token to the acceptor over the application's communication channel.

如果通过调用GSS_Init_sec_context()生成常规安全上下文输出_令牌,则发起方必须通过应用程序的通信通道将该令牌传输给接收方。如果对GSS_Init_sec_context()的调用返回一个错误令牌作为输出令牌,建议启动器通过应用程序的通信通道将该令牌传输给接受者。

3.4. Acceptor Sanity Checking
3.4. 接受者健全性检查

The acceptor's half of the negotiation loop is triggered by the receipt of a context token from the initiator. Before calling GSS_Accept_sec_context(), the acceptor may find it useful to perform some sanity checks on the state of the negotiation loop.

接受方的协商循环的一半由从发起方接收上下文令牌触发。在调用GSS_Accept_sec_context()之前,接受者可能会发现对协商循环的状态执行一些健全性检查很有用。

If the acceptor receives a context token but was not expecting such a token (for example, if the acceptor's previous call to GSS_Accept_sec_context() returned GSS_S_COMPLETE), this is probably an error condition indicating that the initiator's state is invalid. See Section 4.3 for some exceptional cases. It is likely appropriate for the acceptor to report this error condition to the initiator via the application's communication channel.

如果接受者接收到一个上下文令牌,但不希望得到这样的令牌(例如,如果接受者之前对GSS_Accept_sec_context()的调用返回了GSS_s_COMPLETE),这可能是一个错误条件,指示启动器的状态无效。一些例外情况见第4.3节。对于接受者来说,通过应用程序的通信通道向启动器报告此错误情况可能是合适的。

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 does not receive such a token within a reasonable amount of time after transmitting the previous output_token to the initiator, the acceptor should assume that the initiator's state is invalid (timeout) and fail the GSS negotiation. Again, it is likely appropriate for the acceptor to report this error condition to the initiator via the application's communication channel.

如果接受方希望得到上下文令牌(例如,如果先前对GSS_Accept_sec_context()的调用返回GSS_S_CONTINUE_NEEDED),但在将先前的输出_令牌发送给发起方后的合理时间内没有收到这样的令牌,则接受方应假定发起方的状态无效(超时)并使GSS谈判失败。同样,接受方可能通过应用程序的通信通道向发起方报告此错误情况。

3.5. GSS_Accept_sec_context
3.5. GSS_接受_秒_上下文

The GSS acceptor responds to the actions of an initiator; as such, there should always be a nonempty input_token to calls to GSS_Accept_sec_context(). The input_context_handle parameter will always be given as the output_context_handle from the previous call 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 chan_bindings arguments should remain fixed over the course of a given GSS negotiation loop. [RFC2743] only requires that the acceptor_cred_handle remain fixed throughout the loop, but the chan_bindings argument should also remain fixed for reliable operation.

GSS受体对发起者的动作作出响应;因此,对GSS_Accept_sec_context()的调用应该始终有一个非空的input_令牌。输入上下文句柄参数将始终作为给定协商循环中对GSS_Accept_sec_context()的上一次调用的输出上下文句柄,或第一次调用的GSS_C_NO_context,但在给定的GSS协商循环过程中,接受者cred_句柄和chan_绑定参数应保持不变。[RFC2743]只要求在整个循环中保持接收器\u cred\u句柄固定,但chan\u bindings参数也应保持固定,以便可靠运行。

The GSS acceptor calls GSS_Accept_sec_context(), using the input_context_handle for the current security context being established and the input_token received from the initiator. The presence or absence of a nonempty output_token and the value of the major status code are the indicators for how to proceed:

GSS接受器调用GSS_Accept_sec_context(),使用正在建立的当前安全上下文的输入_context_句柄和从启动器接收的输入_令牌。非空输出令牌的存在或不存在以及主要状态代码的值是如何继续的指示器:

o If the major status code is GSS_S_COMPLETE and the output_token is empty, then the context negotiation is fully complete and ready for use by the acceptor with no further actions.

o 如果主要状态代码为GSS_S_COMPLETE,且输出_令牌为空,则上下文协商已完全完成,并且已准备好供接受者使用,无需进一步操作。

o If the major status code is GSS_S_COMPLETE and the output_token is nonempty, then the acceptor's portion of the security context negotiation is complete but the initiator's is not. The acceptor must send the output_token to the initiator so that the initiator can establish its half of the security context.

o 如果主要状态代码为GSS_S_COMPLETE,且输出_令牌为非空,则安全上下文协商的接受方部分已完成,但发起方部分未完成。接受者必须向发起者发送输出令牌,以便发起者可以建立其一半的安全上下文。

o If the major status code is GSS_S_CONTINUE_NEEDED and the output_token is nonempty, the context negotiation is incomplete. The acceptor must send the output_token to the initiator and await another input_token from the initiator.

o 如果主要状态代码为GSS_S_CONTINUE_NEEDED,且输出标记为非空,则上下文协商不完整。接受者必须向发起者发送输出\u令牌,并等待发起者的另一个输入\u令牌。

o If the major status code is GSS_S_CONTINUE_NEEDED and the output_token is empty, the mechanism has produced an output that is not compliant with [RFC2743]. However, there are some known implementations of certain mechanisms such as NTLMSSP [NTLMSSP] that do produce empty context negotiation tokens. For maximum interoperability, applications should be prepared to accept such tokens and should transmit them to the initiator if they are generated.

o 如果主要状态代码为GSS_S_CONTINUE_NEEDED且输出_令牌为空,则该机制产生的输出不符合[RFC2743]。然而,某些机制(如NTLMSSP[NTLMSSP])的一些已知实现确实会产生空的上下文协商令牌。为了实现最大的互操作性,应用程序应准备好接受此类令牌,并在生成令牌时将其传输给启动器。

o If the major status code is any other value, the context negotiation has failed. If the output_token is nonempty, it is an error token and the acceptor should send it to the initiator. If the output_token is empty, then the acceptor should indicate the failure to the initiator if an appropriate application-protocol channel to do so is available.

o 如果主状态代码为任何其他值,则上下文协商失败。如果输出令牌为非空,则它是一个错误令牌,接受方应将其发送给发起方。如果输出_令牌为空,则如果有适当的应用程序协议通道可用,则接受者应向启动器指示失败。

3.6. Sending from Acceptor to Initiator
3.6. 从接受方发送到发起方

The mechanism for sending the context token from acceptor to initiator will depend on the nature of the communication channel between the two parties. For a synchronous bidirectional channel, it 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 as an RPC output parameter. Application protocol specifications will need to specify the nature of this behavior.

从接受者向发起者发送上下文令牌的机制将取决于双方之间通信信道的性质。对于同步双向通道,它可能只是通过链路发送的另一段数据,但对于无状态UDP RPC接收器,令牌可能最终作为RPC输出参数发送。应用程序协议规范将需要指定此行为的性质。

If the application protocol has the initiator driving the application's control flow, it is particularly helpful for the acceptor to indicate a failure to the initiator, as mentioned in some 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 GSS_Accept_sec_context(), the acceptor must transmit this token to the initiator over the application's communication channel. If the call to GSS_Accept_sec_context() returns an error token as output_token, it is recommended that the acceptor transmit this token to the initiator over the application's communication channel.

如果通过调用GSS_Accept_sec_context()生成常规安全上下文输出_令牌,则接收方必须通过应用程序的通信通道将此令牌传输给启动器。如果对GSS_Accept_sec_context()的调用返回一个错误令牌作为输出令牌,建议接受者通过应用程序的通信通道将该令牌传输给启动器。

3.7. Initiator Input Validation
3.7. 启动器输入验证

The initiator's half of the negotiation loop is triggered (after the first call) by receipt of a context token from the acceptor. Before calling GSS_Init_sec_context(), the initiator may find it useful to perform some sanity checks on the state of the negotiation loop.

发起方的协商循环的一半(在第一次调用之后)通过从接受方接收上下文令牌来触发。在调用GSS_Init_sec_context()之前,发起者可能会发现对协商循环的状态执行一些健全性检查很有用。

If the initiator receives a context token but was not expecting such a token (for example, if the initiator's previous call to GSS_Init_sec_context() returned GSS_S_COMPLETE), this is probably an error condition indicating that the acceptor's state is invalid. See Section 4.3 for some exceptional cases. It may be appropriate for the initiator to report this error condition to the acceptor via the application's communication channel.

如果发起者接收到上下文令牌,但不希望得到这样的令牌(例如,如果发起者之前对GSS_Init_sec_context()的调用返回了GSS_s_COMPLETE),这可能是一个错误条件,指示接受者的状态无效。一些例外情况见第4.3节。发起者可以通过应用程序的通信信道向接受者报告此错误情况。

If the initiator is expecting a context token (that is, the previous call to GSS_Init_sec_context() returned GSS_S_CONTINUE_NEEDED) but does not receive such a token within a reasonable amount of time after transmitting the previous output_token to the acceptor, the initiator should assume that the acceptor's state is invalid and fail the GSS negotiation. Again, it may be appropriate for the initiator to report this error condition to the acceptor via the application's communication channel.

如果发起者期望上下文令牌(即,对GSS_Init_sec_context()的上一次调用返回GSS_S_CONTINUE_NEEDED),但在将上一个输出_令牌发送给接受者后的合理时间内没有收到这样的令牌,发起者应该假设接受者的状态无效,并使GSS协商失败。同样,发起者可以通过应用程序的通信信道向接受者报告该错误状况。

3.8. Continue the Loop
3.8. 继续循环

If the loop is in neither a success nor a failure condition, then the loop must continue. Control flow returns to Section 3.2.

如果循环既不成功也不失败,则循环必须继续。控制流返回第3.2节。

4. After Security Context Negotiation
4. 安全上下文协商后

Once a party has completed its half of the security context and fulfilled its obligations to the other party, the context is complete, but it is not necessarily ready and appropriate for use. In particular, the security context flags may not be appropriate for the given application's use. In some cases, the context may be ready for use before the negotiation is complete, see Section 4.2.

一旦一方完成了其一半的安全上下文并履行了其对另一方的义务,上下文就完成了,但不一定准备好并适合使用。特别是,安全上下文标志可能不适合给定应用程序的使用。在某些情况下,在谈判完成之前,上下文可能已经准备好使用,见第4.2节。

The initiator specifies, as part of its fixed set of inputs to GSS_Init_sec_context(), values for all defined request flag booleans, among them: deleg_req_flag, mutual_req_flag, replay_det_req_flag, sequence_req_flag, conf_req_flag, and integ_req_flag. Upon completion of the security context negotiation, the initiator must verify that the values of deleg_state, mutual_state, replay_det_state, sequence_state, conf_avail, and integ_avail (and any additional flags added by extensions) from the last call to GSS_Init_sec_context() correspond to the requested flags. If a flag

作为GSS_Init_sec_context()固定输入集的一部分,启动器指定所有已定义的请求标志布尔值,其中包括:deleg_req_标志、mutual_req_标志、RELAY_det_req_标志、sequence_req_标志、conf_req_标志和INTEGI_req_标志。安全上下文协商完成后,发起者必须验证上次调用GSS_Init_sec_context()时的deleg_state、mutual_state、replay_det_state、sequence_state、conf_avail和integ_avail(以及通过扩展添加的任何附加标志)值是否与请求的标志相对应。如果有国旗

was requested but is not available and that feature is necessary for the application protocol, the initiator must destroy the security context and not use the security context for application traffic.

已请求,但不可用,并且该功能是应用程序协议所必需的,发起程序必须销毁安全上下文,而不是将安全上下文用于应用程序通信。

Application protocol specifications citing this document should indicate which context flags are required for their application protocol.

引用本文档的应用程序协议规范应指明其应用程序协议需要哪些上下文标志。

The acceptor receives as output the following booleans: deleg_state, mutual_state, replay_det_state, sequence_state, anon_state, trans_state, conf_avail, and integ_avail, and any additional flags 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 context and not use the security context for application traffic.

接受器接收以下布尔值作为输出:deleg_状态、mutual_状态、replay_det_状态、sequence_状态、anon_状态、trans_状态、conf_avail和integ_avail,以及GSS-API扩展添加的任何附加标志。接受方必须验证是否设置了应用程序协议所需的任何标志。如果未设置必要的标志,则接受者必须销毁安全上下文,并且不得将安全上下文用于应用程序通信。

4.1. Authorization Checks
4.1. 授权检查

The acceptor receives as one of the outputs of GSS_Accept_sec_context() the name of the initiator that 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 Sections 2.2.6 and 1.1.5 of [RFC2743]. Additional information can be available in GSS-API Naming Extensions [RFC6680].

作为GSS_Accept_sec_context()的输出之一,接受方接收在安全上下文协商期间经过身份验证的发起方的名称。在提供对受限资源的访问之前,应用程序需要对收到的名称(“示例代码中的客户端名称”)执行授权检查。特别是,当客户机是匿名的或来自与接受方不同的身份领域时,安全上下文协商可以成功,这取决于GSS-API用于建立安全上下文的机制的细节。接受方应用程序可以检查发起方使用了哪个目标名称,但详细信息超出了本文档的范围。见[RFC2743]第2.2.6节和第1.1.5节。GSS-API命名扩展[RFC6680]中提供了更多信息。

4.2. Using Partially Complete Security Contexts
4.2. 使用部分完整的安全上下文

For mechanism/flag combinations that require multiple token exchanges, the GSS-API specification [RFC2743] provides a prot_ready_state output value from GSS_Init_sec_context() and GSS_Accept_sec_context(), which indicates when per-message operations are available. However, many mechanism implementations do not provide this functionality and the analysis of the security consequences of its use is rather complicated, so it is not expected to be useful in most application protocols.

对于需要多个令牌交换的机制/标志组合,GSS-API规范[RFC2743]提供了来自GSS_Init_sec_context()和GSS_Accept_sec_context()的prot_ready_状态输出值,指示每消息操作何时可用。然而,许多机制实现不提供此功能,并且对其使用的安全后果的分析相当复杂,因此预计它在大多数应用程序协议中不会有用。

In particular, mutual authentication, replay protection, and other services (if requested) are services that will be active when GSS_S_COMPLETE is returned but that are not necessarily active before the security context is fully established.

特别是,相互身份验证、重播保护和其他服务(如果请求)是在返回GSS_S_COMPLETE时处于活动状态的服务,但在完全建立安全上下文之前不一定处于活动状态。

4.3. Additional Context Tokens
4.3. 其他上下文标记

Under some conditions, a context token will be received by a party to a security context negotiation after that party has completed the negotiation (i.e., after GSS_Init_sec_context() or GSS_Accept_sec_context() has returned GSS_S_COMPLETE). Such tokens 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 initiator side or for an initiator application to transmit that token to the acceptor; 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.

在某些情况下,安全上下文协商的一方在完成协商后(即,GSS_Init_secu_context()或GSS_Accept_secu_context()返回GSS_secu COMPLETE)将收到上下文令牌。此类令牌必须传递给GSS_进程_上下文_令牌()进行处理。机制实现可能并不总是需要在发起方侧生成错误令牌,或者发起方应用程序并不总是需要将该令牌发送给接收方;此类决定超出了本文件的范围。两个对等方应始终准备好处理此类令牌,应用程序协议应提供传输这些令牌的方法。

Such tokens can be security context deletion tokens, emitted when the remote party called GSS_Delete_sec_context() with a non-null output_context_token parameter, or error tokens, emitted when the remote party experiences an error processing the last token in a 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.

这些令牌可以是安全上下文删除令牌,当远程方调用带有非空输出上下文令牌参数的GSS_Delete_sec_context()时发出,也可以是错误令牌,当远程方在安全上下文协商交换中处理最后一个令牌时发出。在协商之前处理令牌时遇到的错误将作为正常安全上下文令牌传输,并酌情由GSS_Init_sec_context()或GSS_Accept_sec_context()处理。对于GSS-API版本2,不建议使用安全上下文删除令牌,因此错误令牌有望成为新应用程序协议最常见的附加上下文令牌形式。

GSS_Process_context_token() may indicate an error in its major_status field if an error is encountered locally during token processing or to indicate that an error was encountered on the peer and conveyed in an error token. See [Err4151] of [RFC2743]. Regardless of the major_status output of GSS_Process_context_token(), GSS_Inquire_context() should be used after processing the extra token, to query the status of the security context and whether it can supply the features necessary for the application protocol.

如果在令牌处理过程中本地遇到错误,则GSS_Process_context_token()可能会在其主_status字段中指示错误,或者指示在对等机上遇到错误并在错误令牌中传输。参见[RFC2743]中的[Err4151]。不管GSS_Process_context_token()的主要_状态输出是什么,在处理额外的令牌之后,都应该使用GSS_Inquire_context()来查询安全上下文的状态,以及它是否可以提供应用程序协议所需的功能。

At present, all tokens that should be handled by GSS_Process_context_token() will lead to the security context being effectively unusable. Future extensions to the GSS-API may allow for applications to continue to function after a call to GSS_Process_context_token(), and it is expected that the outputs of 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.

目前,所有应该由GSS_Process_context_token()处理的令牌将导致安全上下文实际上不可用。GSS-API的未来扩展可能允许应用程序在调用GSS_Process_context_token()后继续运行,预计GSS_Inquire_context()的输出将指示这样做是否安全。但是,由于目前没有此类扩展(错误令牌和删除令牌都会导致安全上下文基本上不可用),因此目前没有关于这种可能性的指导给应用程序。

Even if GSS_Process_context_token() processes an error or deletion token that 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 that is slightly ambiguous in this regard, but the best practice is to always call GSS_Delete_sec_context().

即使GSS_Process_context_token()处理的错误或删除标记使上下文基本上不可用,也必须通过调用GSS_Delete_sec_context()最终释放与上下文相关的资源,就像GSS_Init_sec_context()或GSS_Accept_sec_context()一样处理输入上下文令牌时返回错误,且输入上下文句柄不是GSS\U C\U NO\U上下文。RFC 2743有一些文本在这方面有点含糊不清,但最佳实践是始终调用GSS_Delete_sec_context()。

5. Sample Code
5. 示例代码

This section gives sample code for the GSS negotiation loop, both for a regular application and for an application where the initiator wishes to remain anonymous. Since the code for the two cases is very similar, the anonymous-specific additions are wrapped in a conditional check; that check and the conditional code may be ignored if anonymous processing is not needed.

本节给出了GSS协商循环的示例代码,既适用于常规应用程序,也适用于启动器希望保持匿名的应用程序。由于这两个案例的代码非常相似,匿名特定的添加被包装在一个条件检查中;如果不需要匿名处理,则可以忽略该检查和条件代码。

Since the communication channel between the initiator and acceptor is a matter for individual application protocols, it is inherently unspecified at the GSS-API level, which can lead to examples that are less satisfying than may be desired. For example, the sample code in [RFC2744] uses an unspecified send_token_to_peer() routine. Fully correct and general code to frame and transmit tokens requires a substantial amount of error checking and would detract from the core purpose of this document, so we only present the function signature for one example of what such functions might be and leave some comments in the otherwise empty function bodies.

由于发起者和接受者之间的通信信道是单个应用程序协议的问题,因此它在GSS-API级别上本质上是未指定的,这可能导致示例不如预期的令人满意。例如,[RFC2744]中的示例代码使用未指定的send_token_to_peer()例程。完全正确且通用的代码来帧和传输令牌需要大量的错误检查,这将有损于本文档的核心目的,因此我们仅提供函数签名作为此类函数的一个示例,并在其他空函数体中留下一些注释。

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 sorts of information that can be stored in the major status field; supplementary information does not necessarily indicate an error. Applications written in other languages will need to exercise care that checks against the major status value are written correctly.

此示例代码是使用GSS-API C-bindings[RFC2744]用C编写的。它使用宏GSS_ERROR()帮助解包可以存储在主状态字段中的各种信息;补充信息不一定表示错误。使用其他语言编写的应用程序需要小心,以确保对主状态值的检查正确编写。

This sample code should be compilable as a standalone program, linked against a GSS-API library. In addition to supplying implementations for the token transmission/receipt routines, in order for the program to successfully run when linked against most GSS-API libraries, the initiator will need to specify an explicit target name for the acceptor, which must match the credentials available to the acceptor. A skeleton for how this may be done is provided, using a dummy name.

此示例代码应可作为独立程序编译,并与GSS-API库链接。除了为令牌传输/接收例程提供实现外,为了使程序在链接到大多数GSS-API库时成功运行,发起方还需要为接受方指定一个明确的目标名称,该名称必须与接受方可用的凭据相匹配。使用虚拟名称提供了如何实现这一点的框架。

This sample code assumes use of v2 of the GSS-API. Applications wishing to remain compatible with v1 of the GSS-API may need to perform additional checks in some locations.

此示例代码假定使用GSS-API的v2。希望与GSS-API v1保持兼容的应用程序可能需要在某些位置执行额外的检查。

5.1. GSS Application Sample Code
5.1. GSS应用程序示例代码
#include <unistd.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gssapi/gssapi.h>
        
#include <unistd.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gssapi/gssapi.h>
        
/*
 * This helper is used only on buffers that we allocate ourselves (e.g.,
 * from receive_token()).  Buffers allocated by GSS routines must use
 * gss_release_buffer().
 */
static void
release_buffer(gss_buffer_t buf)
{
    free(buf->value);
    buf->value = NULL;
    buf->length = 0;
}
        
/*
 * This helper is used only on buffers that we allocate ourselves (e.g.,
 * from receive_token()).  Buffers allocated by GSS routines must use
 * gss_release_buffer().
 */
static void
release_buffer(gss_buffer_t buf)
{
    free(buf->value);
    buf->value = NULL;
    buf->length = 0;
}
        
/*
 * Helper to send a token on the specified file descriptor.
 *
 * If errors are encountered, this routine must not directly cause
 * termination of the process because compliant GSS applications
 * must release resources allocated by the GSS library before
 * exiting.
 *
 * Returns 0 on success, nonzero on failure.
 */
static int
send_token(int fd, gss_buffer_t token)
{
    /*
     * Supply token framing and transmission code here.
     *
     * It is advisable for the application protocol to specify the
     * length of the token being transmitted unless the underlying
     * transit does so implicitly.
     *
     * In addition to checking for error returns from whichever
     * syscall(s) are used to send data, applications should have
     * a loop to handle EINTR returns.
     */
    return 1;
}
        
/*
 * Helper to send a token on the specified file descriptor.
 *
 * If errors are encountered, this routine must not directly cause
 * termination of the process because compliant GSS applications
 * must release resources allocated by the GSS library before
 * exiting.
 *
 * Returns 0 on success, nonzero on failure.
 */
static int
send_token(int fd, gss_buffer_t token)
{
    /*
     * Supply token framing and transmission code here.
     *
     * It is advisable for the application protocol to specify the
     * length of the token being transmitted unless the underlying
     * transit does so implicitly.
     *
     * In addition to checking for error returns from whichever
     * syscall(s) are used to send data, applications should have
     * a loop to handle EINTR returns.
     */
    return 1;
}
        
/*
 * Helper to receive a token on the specified file descriptor.
 *
 * If errors are encountered, this routine must not directly cause
 * termination of the process because compliant GSS applications
 * must release resources allocated by the GSS library before
 * exiting.
 *
 * Returns 0 on success, nonzero on failure.
 */
static int
receive_token(int fd, gss_buffer_t token)
{
    /*
     * Supply token framing and transmission code here.
     *
     * In addition to checking for error returns from whichever
     * syscall(s) are used to receive data, applications should have
     * a loop to handle EINTR returns.
     *
     * This routine is assumed to allocate memory for the local copy
     * of the received token, which must be freed with release_buffer().
     */
    return 1;
}
        
/*
 * Helper to receive a token on the specified file descriptor.
 *
 * If errors are encountered, this routine must not directly cause
 * termination of the process because compliant GSS applications
 * must release resources allocated by the GSS library before
 * exiting.
 *
 * Returns 0 on success, nonzero on failure.
 */
static int
receive_token(int fd, gss_buffer_t token)
{
    /*
     * Supply token framing and transmission code here.
     *
     * In addition to checking for error returns from whichever
     * syscall(s) are used to receive data, applications should have
     * a loop to handle EINTR returns.
     *
     * This routine is assumed to allocate memory for the local copy
     * of the received token, which must be freed with release_buffer().
     */
    return 1;
}
        
static void
do_initiator(int readfd, int writefd, int anon)
{
    int initiator_established = 0, ret;
    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
    OM_uint32 major, minor, req_flags, ret_flags;
    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;
        
static void
do_initiator(int readfd, int writefd, int anon)
{
    int initiator_established = 0, ret;
    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
    OM_uint32 major, minor, req_flags, ret_flags;
    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;
        
    /* Applications should set target_name to a real value. */
    name_buf.value = "<service>@<hostname.domain>";
    name_buf.length = strlen(name_buf.value);
    major = gss_import_name(&minor, &name_buf,
                            GSS_C_NT_HOSTBASED_SERVICE, &target_name);
    if (GSS_ERROR(major)) {
        warnx(1, "Could not import name\n");
        goto cleanup;
    }
        
    /* Applications should set target_name to a real value. */
    name_buf.value = "<service>@<hostname.domain>";
    name_buf.length = strlen(name_buf.value);
    major = gss_import_name(&minor, &name_buf,
                            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
     * 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;
    if (anon)
        req_flags |= GSS_C_ANON_FLAG;
        
    /* Mutual authentication will require a token from acceptor to
     * 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;
    if (anon)
        req_flags |= GSS_C_ANON_FLAG;
        
    while (!initiator_established) {
        /* The initiator_cred_handle, mech_type, time_req,
         * input_chan_bindings, actual_mech_type, and time_rec
         * parameters are not needed in many cases.  We pass
         * GSS_C_NO_CREDENTIAL, GSS_C_NO_OID, 0, NULL, NULL, and NULL
         * for them, respectively. */
        major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &ctx,
                                     target_name, GSS_C_NO_OID,
                                     req_flags, 0, NULL, &input_token,
                                     NULL, &output_token, &ret_flags,
                                     NULL);
        /* This was allocated by receive_token() and is no longer
         * needed.  Free it now to avoid leaks if the loop continues. */
        release_buffer(&input_token);
        if (anon) {
            /* Initiators that wish to remain anonymous must check
             * whether their request has been honored before sending
             * each token. */
            if (!(ret_flags & GSS_C_ANON_FLAG)) {
                warnx("Anonymous requested but not available\n");
                goto cleanup;
            }
        }
        /* Always send a token if we are expecting another input token
         * (GSS_S_CONTINUE_NEEDED is set) or if it is nonempty. */
        if ((major & GSS_S_CONTINUE_NEEDED) ||
            output_token.length > 0) {
            ret = send_token(writefd, &output_token);
            if (ret != 0)
                goto cleanup;
        }
        /* Check for errors after sending the token so that we will send
         * error tokens. */
        if (GSS_ERROR(major)) {
            warnx("gss_init_sec_context() error major 0x%x\n", major);
            goto cleanup;
        }
        /* Free the output token's storage; we don't need it anymore.
         * gss_release_buffer() is safe to call on the output buffer
         * from gss_int_sec_context(), even if there is no storage
         * associated with that buffer. */
        (void)gss_release_buffer(&minor, &output_token);
        
    while (!initiator_established) {
        /* The initiator_cred_handle, mech_type, time_req,
         * input_chan_bindings, actual_mech_type, and time_rec
         * parameters are not needed in many cases.  We pass
         * GSS_C_NO_CREDENTIAL, GSS_C_NO_OID, 0, NULL, NULL, and NULL
         * for them, respectively. */
        major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &ctx,
                                     target_name, GSS_C_NO_OID,
                                     req_flags, 0, NULL, &input_token,
                                     NULL, &output_token, &ret_flags,
                                     NULL);
        /* This was allocated by receive_token() and is no longer
         * needed.  Free it now to avoid leaks if the loop continues. */
        release_buffer(&input_token);
        if (anon) {
            /* Initiators that wish to remain anonymous must check
             * whether their request has been honored before sending
             * each token. */
            if (!(ret_flags & GSS_C_ANON_FLAG)) {
                warnx("Anonymous requested but not available\n");
                goto cleanup;
            }
        }
        /* Always send a token if we are expecting another input token
         * (GSS_S_CONTINUE_NEEDED is set) or if it is nonempty. */
        if ((major & GSS_S_CONTINUE_NEEDED) ||
            output_token.length > 0) {
            ret = send_token(writefd, &output_token);
            if (ret != 0)
                goto cleanup;
        }
        /* Check for errors after sending the token so that we will send
         * error tokens. */
        if (GSS_ERROR(major)) {
            warnx("gss_init_sec_context() error major 0x%x\n", major);
            goto cleanup;
        }
        /* Free the output token's storage; we don't need it anymore.
         * gss_release_buffer() is safe to call on the output buffer
         * from gss_int_sec_context(), even if there is no storage
         * associated with that buffer. */
        (void)gss_release_buffer(&minor, &output_token);
        
        if (major & GSS_S_CONTINUE_NEEDED) {
            ret = receive_token(readfd, &input_token);
            if (ret != 0)
                goto cleanup;
        } else if (major == GSS_S_COMPLETE) {
            initiator_established = 1;
        } else {
            /* This situation is forbidden by RFC 2743.  Bail out. */
            warnx("major not complete or continue but not error\n");
            goto cleanup;
        }
    }   /* while (!initiator_established) */
    if ((ret_flags & req_flags) != req_flags) {
        warnx("Negotiated context does not support requested flags\n");
        goto cleanup;
    }
    printf("Initiator's context negotiation successful\n");
cleanup:
    /* We are required to release storage for nonzero-length output
     * tokens.  gss_release_buffer() zeros the length, so we
     * will not attempt to release the same buffer twice. */
    if (output_token.length > 0)
        (void)gss_release_buffer(&minor, &output_token);
    /* Do not request a context deletion token; pass NULL. */
    (void)gss_delete_sec_context(&minor, &ctx, NULL);
    (void)gss_release_name(&minor, &target_name);
}
        
        if (major & GSS_S_CONTINUE_NEEDED) {
            ret = receive_token(readfd, &input_token);
            if (ret != 0)
                goto cleanup;
        } else if (major == GSS_S_COMPLETE) {
            initiator_established = 1;
        } else {
            /* This situation is forbidden by RFC 2743.  Bail out. */
            warnx("major not complete or continue but not error\n");
            goto cleanup;
        }
    }   /* while (!initiator_established) */
    if ((ret_flags & req_flags) != req_flags) {
        warnx("Negotiated context does not support requested flags\n");
        goto cleanup;
    }
    printf("Initiator's context negotiation successful\n");
cleanup:
    /* We are required to release storage for nonzero-length output
     * tokens.  gss_release_buffer() zeros the length, so we
     * will not attempt to release the same buffer twice. */
    if (output_token.length > 0)
        (void)gss_release_buffer(&minor, &output_token);
    /* Do not request a context deletion token; pass NULL. */
    (void)gss_delete_sec_context(&minor, &ctx, NULL);
    (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;
}
        
/*
 * 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
do_acceptor(int readfd, int writefd)
{
    int acceptor_established = 0, ret;
    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
    OM_uint32 major, minor, ret_flags;
    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
    gss_name_t client_name;
        
static void
do_acceptor(int readfd, int writefd)
{
    int acceptor_established = 0, ret;
    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
    OM_uint32 major, minor, ret_flags;
    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
    gss_name_t client_name;
        

major = GSS_S_CONTINUE_NEEDED;

主要=需要GSS\U S\U继续\U;

    while (!acceptor_established) {
        if (major & GSS_S_CONTINUE_NEEDED) {
            ret = receive_token(readfd, &input_token);
            if (ret != 0)
                goto cleanup;
        } else if (major == GSS_S_COMPLETE) {
            acceptor_established = 1;
            break;
        } else {
            /* This situation is forbidden by RFC 2743.  Bail out. */
            warnx("major not complete or continue but not error\n");
            goto cleanup;
        }
        /* We can use the default behavior or do not need the returned
         * information for the parameters acceptor_cred_handle,
         * input_chan_bindings, mech_type, time_rec, and
         * delegated_cred_handle, and pass the values
         * GSS_C_NO_CREDENTIAL, NULL, NULL, NULL, and NULL,
         * respectively.  In some cases the src_name will not be
         * needed, but most likely it will be needed for some
         * authorization or logging functionality. */
        major = gss_accept_sec_context(&minor, &ctx,
                                       GSS_C_NO_CREDENTIAL,
                                       &input_token, NULL,
                                       &client_name, NULL,
                                       &output_token, &ret_flags, NULL,
                                       NULL);
        /* This was allocated by receive_token() and is no longer
         * needed.  Free it now to avoid leaks if the loop continues. */
        release_buffer(&input_token);
        /* Always send a token if we are expecting another input token
         * (GSS_S_CONTINUE_NEEDED is set) or if it is nonempty. */
        if ((major & GSS_S_CONTINUE_NEEDED) ||
            output_token.length > 0) {
            ret = send_token(writefd, &output_token);
            if (ret != 0)
        
    while (!acceptor_established) {
        if (major & GSS_S_CONTINUE_NEEDED) {
            ret = receive_token(readfd, &input_token);
            if (ret != 0)
                goto cleanup;
        } else if (major == GSS_S_COMPLETE) {
            acceptor_established = 1;
            break;
        } else {
            /* This situation is forbidden by RFC 2743.  Bail out. */
            warnx("major not complete or continue but not error\n");
            goto cleanup;
        }
        /* We can use the default behavior or do not need the returned
         * information for the parameters acceptor_cred_handle,
         * input_chan_bindings, mech_type, time_rec, and
         * delegated_cred_handle, and pass the values
         * GSS_C_NO_CREDENTIAL, NULL, NULL, NULL, and NULL,
         * respectively.  In some cases the src_name will not be
         * needed, but most likely it will be needed for some
         * authorization or logging functionality. */
        major = gss_accept_sec_context(&minor, &ctx,
                                       GSS_C_NO_CREDENTIAL,
                                       &input_token, NULL,
                                       &client_name, NULL,
                                       &output_token, &ret_flags, NULL,
                                       NULL);
        /* This was allocated by receive_token() and is no longer
         * needed.  Free it now to avoid leaks if the loop continues. */
        release_buffer(&input_token);
        /* Always send a token if we are expecting another input token
         * (GSS_S_CONTINUE_NEEDED is set) or if it is nonempty. */
        if ((major & GSS_S_CONTINUE_NEEDED) ||
            output_token.length > 0) {
            ret = send_token(writefd, &output_token);
            if (ret != 0)
        
                goto cleanup;
        }
        /* Check for errors after sending the token so that we will send
         * error tokens. */
        if (GSS_ERROR(major)) {
            warnx("gss_accept_sec_context() error major 0x%x\n", major);
            goto cleanup;
        }
        /* Free the output token's storage; we don't need it anymore.
         * gss_release_buffer() is safe to call on the output buffer
         * from gss_accept_sec_context(), even if there is no storage
         * associated with that buffer. */
        (void)gss_release_buffer(&minor, &output_token);
    }   /* while (!acceptor_established) */
    if (!(ret_flags & GSS_C_INTEG_FLAG)) {
        warnx("Negotiated context does not support integrity\n");
        goto cleanup;
    }
    printf("Acceptor's context negotiation successful\n");
    ret = check_authz(client_name);
    if (ret != 0)
        printf("Client is not authorized; rejecting access\n");
cleanup:
    release_buffer(&input_token);
    /* We are required to release storage for nonzero-length output
     * tokens.  gss_release_buffer() zeros the length, so we
     * will not attempt to release the same buffer twice. */
    if (output_token.length > 0)
        (void)gss_release_buffer(&minor, &output_token);
    /* Do not request a context deletion token, pass NULL. */
    (void)gss_delete_sec_context(&minor, &ctx, NULL);
    (void)gss_release_name(&minor, &client_name);
}
        
                goto cleanup;
        }
        /* Check for errors after sending the token so that we will send
         * error tokens. */
        if (GSS_ERROR(major)) {
            warnx("gss_accept_sec_context() error major 0x%x\n", major);
            goto cleanup;
        }
        /* Free the output token's storage; we don't need it anymore.
         * gss_release_buffer() is safe to call on the output buffer
         * from gss_accept_sec_context(), even if there is no storage
         * associated with that buffer. */
        (void)gss_release_buffer(&minor, &output_token);
    }   /* while (!acceptor_established) */
    if (!(ret_flags & GSS_C_INTEG_FLAG)) {
        warnx("Negotiated context does not support integrity\n");
        goto cleanup;
    }
    printf("Acceptor's context negotiation successful\n");
    ret = check_authz(client_name);
    if (ret != 0)
        printf("Client is not authorized; rejecting access\n");
cleanup:
    release_buffer(&input_token);
    /* We are required to release storage for nonzero-length output
     * tokens.  gss_release_buffer() zeros the length, so we
     * will not attempt to release the same buffer twice. */
    if (output_token.length > 0)
        (void)gss_release_buffer(&minor, &output_token);
    /* Do not request a context deletion token, pass NULL. */
    (void)gss_delete_sec_context(&minor, &ctx, NULL);
    (void)gss_release_name(&minor, &client_name);
}
        
int
main(void)
{
    pid_t pid;
    int fd1 = -1, fd2 = -1;
        
int
main(void)
{
    pid_t pid;
    int fd1 = -1, fd2 = -1;
        
    /* Create file descriptors for reading/writing here. */
    pid = fork();
    if (pid == 0)
        do_initiator(fd1, fd2, 0);
    else if (pid > 0)
        do_acceptor(fd2, fd1);
    else
        err(1, "fork() failed\n");
        
    /* Create file descriptors for reading/writing here. */
    pid = fork();
    if (pid == 0)
        do_initiator(fd1, fd2, 0);
    else if (pid > 0)
        do_acceptor(fd2, fd1);
    else
        err(1, "fork() failed\n");
        
    exit(0);
}
        
    exit(0);
}
        
6. Security Considerations
6. 安全考虑

This document provides a (reasonably) concise description and example for correct construction of the GSS-API security context negotiation loop. Since everything relating to the construction and use of a GSS security context is security related, there are security-relevant considerations throughout the document. It is useful to call out a few things in this section, though.

本文档为GSS-API安全上下文协商循环的正确构造提供了(合理的)简明描述和示例。由于与GSS安全上下文的构造和使用相关的所有内容都与安全相关,因此在整个文档中都有与安全相关的注意事项。不过,在本节中列出一些内容是有用的。

The GSS-API uses a request-and-check model for features. An application using the GSS-API requests certain features (e.g., confidentiality protection for messages or anonymity), but such a request does not require the GSS implementation to provide that feature. The application must check the returned flags to verify whether a requested feature is present; if the feature was non-optional for the application, the application must generate an error. Phrased differently, the GSS-API will not generate an error if it is unable to satisfy the features requested by the application.

GSS-API为特性使用请求和检查模型。使用GSS-API的应用程序请求某些功能(例如,消息的机密性保护或匿名性),但此类请求不要求GSS实现提供该功能。应用程序必须检查返回的标志,以验证请求的功能是否存在;如果该功能对于应用程序是非可选的,则应用程序必须生成错误。如果GSS-API不能满足应用程序所请求的特性,则它不会生成错误。

In many cases, it is convenient for GSS acceptors to accept security contexts 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 they have access for accepting security contexts, which may not be the desired behavior for a given application. (For example, the Secure Shell daemon (sshd) may 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 Sections 2.2.6 and 1.1.5 of [RFC2743]

在许多情况下,GSS接受者可以方便地使用多个接受者名称接受安全上下文(例如,通过使用默认凭据集,当GSS_C_NO_凭据传递给GSS_accept_sec_context()时就会发生这种情况)。这允许接受者使用他们有权访问的任何凭证来接受安全上下文,这可能不是给定应用程序所需的行为。(例如,Secure Shell daemon(sshd)可能希望仅接受使用基于GSS_C_NT_host的凭据的形式主机@<hostname>,而不是nfs@<hostname>)接受程序应用程序可以检查启动器使用的目标名称,但详细信息不在本文档的范围内。见[RFC2743]第2.2.6节和第1.1.5节

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. 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. Use of the GSS_ERROR() macro on the results of GSS-API per-message operations has resulted in security vulnerabilities in existing software.

C示例代码使用宏GSS_ERROR()来评估GSS_init_sec_context()和GSS_accept_sec_context()的返回值。这样做是为了指出在为其他语言编写代码时需要检查的地方以及这些检查的性质。省略该宏可以简化C代码。在希望接收受保护的八位字节流的应用程序中,不应在每条消息操作的结果上使用此宏,因为它忽略了检查补充状态值,例如GSS_S_DUPLICATE_令牌、GSS_S_OLD_令牌等。使用GSS_ERROR()GSS-API每条消息操作结果的宏已导致现有软件存在安全漏洞。

The security considerations from RFCs 2743 and 2744 remain applicable to consumers of this document.

RFCs 2743和2744中的安全注意事项仍然适用于本文档的使用者。

7. References
7. 工具书类
7.1. Normative References
7.1. 规范性引用文件

[RFC2743] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, DOI 10.17487/RFC2743, January 2000, <http://www.rfc-editor.org/info/rfc2743>.

[RFC2743]Linn,J.,“通用安全服务应用程序接口版本2,更新1”,RFC 2743,DOI 10.17487/RFC2743,2000年1月<http://www.rfc-editor.org/info/rfc2743>.

[RFC2744] Wray, J., "Generic Security Service API Version 2 : C-bindings", RFC 2744, DOI 10.17487/RFC2744, January 2000, <http://www.rfc-editor.org/info/rfc2744>.

[RFC2744]Wray,J.,“通用安全服务API第2版:C-绑定”,RFC 2744,DOI 10.17487/RFC2744,2000年1月<http://www.rfc-editor.org/info/rfc2744>.

7.2. Informative References
7.2. 资料性引用

[Err4151] RFC Errata, Erratum ID 4151, RFC 2743.

[Err4151]RFC勘误表,勘误表ID 4151,RFC 2743。

[NTLMSSP] Microsoft Corporation, "[MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol", May 2014, <https://msdn.microsoft.com/en-us/library/cc236621.aspx>.

[NTLMSSP]微软公司,[MS-NLMP]:NT LAN Manager(NTLM)认证协议,2014年5月<https://msdn.microsoft.com/en-us/library/cc236621.aspx>.

[RFC2203] Eisler, M., Chiu, A., and L. Ling, "RPCSEC_GSS Protocol Specification", RFC 2203, DOI 10.17487/RFC2203, September 1997, <http://www.rfc-editor.org/info/rfc2203>.

[RFC2203]Eisler,M.,Chiu,A.,和L.Ling,“RPCSEC_GSS协议规范”,RFC 2203,DOI 10.17487/RFC2203,1997年9月<http://www.rfc-editor.org/info/rfc2203>.

[RFC3645] Kwan, S., Garg, P., Gilroy, J., Esibov, L., Westhead, J., and R. Hall, "Generic Security Service Algorithm for Secret Key Transaction Authentication for DNS (GSS-TSIG)", RFC 3645, DOI 10.17487/RFC3645, October 2003, <http://www.rfc-editor.org/info/rfc3645>.

[RFC3645]Kwan,S.,Garg,P.,Gilroy,J.,Esibov,L.,Westhead,J.,和R.Hall,“DNS密钥交易认证的通用安全服务算法(GSS-TSIG)”,RFC 3645,DOI 10.17487/RFC3645,2003年10月<http://www.rfc-editor.org/info/rfc3645>.

[RFC4401] Williams, N., "A Pseudo-Random Function (PRF) API Extension for the Generic Security Service Application Program Interface (GSS-API)", RFC 4401, DOI 10.17487/RFC4401, February 2006, <http://www.rfc-editor.org/info/rfc4401>.

[RFC4401]Williams,N.,“通用安全服务应用程序接口(GSS-API)的伪随机函数(PRF)API扩展”,RFC 4401,DOI 10.17487/RFC4401,2006年2月<http://www.rfc-editor.org/info/rfc4401>.

[RFC4462] Hutzelman, J., Salowey, J., Galbraith, J., and V. Welch, "Generic Security Service Application Program Interface (GSS-API) Authentication and Key Exchange for the Secure Shell (SSH) Protocol", RFC 4462, DOI 10.17487/RFC4462, May 2006, <http://www.rfc-editor.org/info/rfc4462>.

[RFC4462]Hutzelman,J.,Salowey,J.,Galbraith,J.,和V.Welch,“安全壳(SSH)协议的通用安全服务应用程序接口(GSS-API)认证和密钥交换”,RFC 4462,DOI 10.17487/RFC4462,2006年5月<http://www.rfc-editor.org/info/rfc4462>.

[RFC4752] Melnikov, A., Ed., "The Kerberos V5 ("GSSAPI") Simple Authentication and Security Layer (SASL) Mechanism", RFC 4752, DOI 10.17487/RFC4752, November 2006, <http://www.rfc-editor.org/info/rfc4752>.

[RFC4752]Melnikov,A.,Ed.,“Kerberos V5(“GSSAPI”)简单身份验证和安全层(SASL)机制”,RFC 4752,DOI 10.17487/RFC4752,2006年11月<http://www.rfc-editor.org/info/rfc4752>.

[RFC5801] Josefsson, S. and N. Williams, "Using Generic Security Service Application Program Interface (GSS-API) Mechanisms in Simple Authentication and Security Layer (SASL): The GS2 Mechanism Family", RFC 5801, DOI 10.17487/RFC5801, July 2010, <http://www.rfc-editor.org/info/rfc5801>.

[RFC5801]Josefsson,S.和N.Williams,“在简单身份验证和安全层(SASL)中使用通用安全服务应用程序接口(GSS-API)机制:GS2机制系列”,RFC 5801,DOI 10.17487/RFC5801,2010年7月<http://www.rfc-editor.org/info/rfc5801>.

[RFC6680] Williams, N., Johansson, L., Hartman, S., and S. Josefsson, "Generic Security Service Application Programming Interface (GSS-API) Naming Extensions", RFC 6680, DOI 10.17487/RFC6680, August 2012, <http://www.rfc-editor.org/info/rfc6680>.

[RFC6680]Williams,N.,Johansson,L.,Hartman,S.,和S.Josefsson,“通用安全服务应用程序编程接口(GSS-API)命名扩展”,RFC 6680,DOI 10.17487/RFC6680,2012年8月<http://www.rfc-editor.org/info/rfc6680>.

Acknowledgements

致谢

Thanks to Nico Williams and Jeff Hutzleman for prompting me to write this document.

感谢Nico Williams和Jeff Hutzleman促使我编写本文档。

Author's Address

作者地址

Benjamin Kaduk MIT Kerberos Consortium

Benjamin Kaduk麻省理工学院Kerberos联合会

   EMail: kaduk@mit.edu
        
   EMail: kaduk@mit.edu