InitializeSecurityContext(常规)函数

InitializeSecurityContext(常规)函数从凭据句柄启动客户端出站安全上下文。 该函数用于在客户端应用程序和远程对等机之间生成安全上下文InitializeSecurityContext(常规)返回客户端必须传递给远程对等机的令牌,而对等机又通过 AcceptSecurityContext(常规)调用提交到本地安全实现。 所有调用方都应将生成的令牌视为不透明。

通常,InitializeSecurityContext(常规)函数在循环中调用,直到建立足够的安全上下文

有关将此函数用于特定安全支持提供程序 (SSP) 的信息,请参阅以下主题。

主题 说明
InitializeSecurityContext (CredSSP) 使用凭据安全支持提供程序 (CredSSP) 安全数据包从凭据句柄启动客户端出站安全上下文
InitializeSecurityContext(摘要) 使用 Digest 安全数据包从凭据句柄启动客户端出站安全上下文
InitializeSecurityContext (Kerberos) 使用 Kerberos 安全数据包从凭据句柄启动客户端出站安全上下文
InitializeSecurityContext (Negotiate) 使用 Negotiate 安全数据包从凭据句柄启动客户端出站安全上下文
InitializeSecurityContext (NTLM) 使用 NTLM 安全数据包从凭据句柄启动客户端出站安全上下文
InitializeSecurityContext (Schannel) 使用 Schannel 安全数据包从凭据句柄启动客户端出站安全上下文

语法

SECURITY_STATUS SEC_Entry InitializeSecurityContext(
  _In_opt_    PCredHandle    phCredential,
  _In_opt_    PCtxtHandle    phContext,
  _In_opt_    SEC_CHAR       *pszTargetName,
  _In_        ULONG          fContextReq,
  _In_        ULONG          Reserved1,
  _In_        ULONG          TargetDataRep,
  _In_opt_    PSecBufferDesc pInput,
  _In_        ULONG          Reserved2,
  _Inout_opt_ PCtxtHandle    phNewContext,
  _Inout_opt_ PSecBufferDesc pOutput,
  _Out_       PULONG         pfContextAttr,
  _Out_opt_   PTimeStamp     ptsExpiry
);

参数

phCredential[in, optional]

AcquireCredentialsHandle(常规)返回的凭据的句柄。 此句柄用于生成安全上下文InitializeSecurityContext(常规)函数至少需要出站凭据。

phContext[in, optional]

指向 CtxtHandle 结构的指针。 在第一次调用 InitializeSecurityContext (常规)时,此指针为 NULL。 在第二次调用中,此参数是指向第一次调用在 phNewContext 参数中返回的部分格式上下文的句柄的指针。

此参数是 Microsoft Digest SSP 的可选参数,可设置为 NULL

使用 Schannel SSP 时,在第一次调用 InitializeSecurityContext(常规)时,指定 NULL。 在将来的调用中,指定在第一次调用此函数后 phNewContext 参数中收到的令牌。

警告

不要在对 InitializeSecurityContext(常规)的并发调用中使用相同的上下文句柄。 安全服务提供商中的 API 实现的线程不安全。

pTargetName[in, optional]

指向以 null 结尾的字符串的指针,指示上下文的目标。 字符串内容特定于安全数据包,如下表所述。 此列表并未囊括所有方式。 可以向系统添加其他系统 SSP 和第三方 SSP。

正在使用的 SSP 含义
摘要 唯一标识所请求资源的 URI 的以 Null 结尾的字符串。 字符串必须由 URI 中允许的字符组成,并且必须由美国 ASCII 代码集表示。 百分比编码可用于表示美国 ASCII 代码集之外的字符。
Kerberos 或 Negotiate 服务主体名称 (SPN) 或目标服务器的安全上下文
NTLM 服务主体名称 (SPN) 或目标服务器的安全上下文
Schannel/SSL 唯一标识目标服务器的以 Null 结尾的字符串。 Schannel 使用此值验证服务器证书。 Schannel 还使用此值在重新建立连接时在会话缓存中查找会话。 仅当满足以下所有条件时,才使用缓存会话:
-目标名称相同。
-缓存项未过期。
-调用函数的应用程序进程相同。
-登录会话相同。
-凭据句柄相同。

fContextReq[in]

指示上下文请求的位标志。 并非所有包都支持所有要求。 用于此参数的标志以 ISC_REQ_ 为前缀,例如 ISC_REQ_DELEGATE。 此参数可以是以下一个或多个属性标志。

含义
ISC_REQ_ALLOCATE_MEMORY 安全包为你分配输出缓冲区。 使用完输出缓冲区后,通过调用 FreeContextBuffer 函数释放它们。
ISC_REQ_CONFIDENTIALITY 使用 EncryptMessage 函数加密消息。
ISC_REQ_CONNECTION 安全上下文不会处理格式化消息。 此值是 Kerberos、Negotiate 和 NTLM 约束委派的默认值。
ISC_REQ_DELEGATE 服务器可以使用上下文作为客户端向其他服务器进行身份验证。 必须设置 ISC_REQ_MUTUAL_AUTH 标志才能运行此标志。 对 Kerberos 有效。 为约束委派忽略此标志。
ISC_REQ_EXTENDED_ERROR 发生错误时,将通知远程方。
ISC_REQ_HTTP 对 HTTP 使用摘要。 省略此标志以使用 Digest 作为 SASL 机制。
ISC_REQ_INTEGRITY 使用 EncryptMessageMakeSignature 函数对消息进行签名并验证签名。
ISC_REQ_MANUAL_CRED_VALIDATION Schannel 不得自动对服务器进行身份验证。
ISC_REQ_MUTUAL_AUTH 将满足服务的相互身份验证策略。
警告:这不一定意味着执行相互身份验证,只是满足服务的身份验证策略。 若要确保执行相互身份验证,请调用 QueryContextAttributes(常规)函数。
ISC_REQ_NO_INTEGRITY 如果设置了此标志,则忽略 ISC_REQ_INTEGRITY 标志。
此值仅受 Negotiate 和 Kerberos 约束委派的支持。
ISC_REQ_REPLAY_DETECT 使用 EncryptMessageMakeSignature 函数检测已编码的重播消息。
ISC_REQ_SEQUENCE_DETECT 检测按顺序接收的消息。
ISC_REQ_STREAM 支持面向流的连接。
ISC_REQ_USE_SESSION_KEY 必须协商新的会话密钥
此值仅受 Kerberos 约束委派支持。
ISC_REQ_USE_SUPPLIED_CREDS Schannel 不得自动尝试为客户端提供凭据。

客户端可能不支持请求的属性。 有关详细信息,请参阅 pfContextAttr 参数。

有关各种属性的进一步说明,请参阅上下文要求

Reserved1[in]

此参数是保留的,必须为零。

TargetDataRep[in]

目标上的数据表示形式,例如字节顺序。 此参数可以是 SECURITY_NATIVE_DREP 或 SECURITY_NETWORK_DREP。

此参数不与 Digest 或 Schannel 一起使用。 将其设置为零。

pInput[in, optional]

指向 SecBufferDesc 结构的指针,该结构包含指向作为包输入提供的缓冲区的指针。 除非客户端上下文由服务器启动,否则此参数在对函数的第一次调用中时必须为 NULL。 在对函数的后续调用或服务器启动客户端上下文时,此参数的值是指向分配有足够内存的缓冲区的指针,用于保存远程计算机返回的令牌。

Reserved2[in]

此参数是保留的,必须为零。

phNewContext[in, out, optional]

指向 CtxtHandle 结构的指针。 在第一次调用 InitializeSecurityContext(常规)时,此指针接收新的上下文句柄。 第二次调用时,phNewContext 可以与 phContext 参数中指定的句柄相同。 phNewContext 不应该是 NULL

pOutput[in, out, optional]

指向 SecBufferDesc 结构的指针,该结构包含指向接收输出数据的 SecBuffer 结构的指针。 如果缓冲区在输入中被键入为 SEC_READWRITE,则会在输出中显示。 如果请求(通过 ISC_REQ_ALLOCATE_MEMORY),系统将为安全令牌分配缓冲区,并在安全令牌的缓冲区描述符中填写地址。

使用 Microsoft Digest SSP 时,此参数会收到必须发送到服务器的质询响应。

使用 Schannel SSP 时,如果指定了 ISC_REQ_ALLOCATE_MEMORY 标志,Schannel SSP 将为缓冲区分配内存,并将相应的信息放在 SecBufferDesc 中。 此外,调用方必须传入 SECBUFFER_ALERT 类型的缓冲区。 在输出中,如果生成警报,则此缓冲区包含有关该警报的信息,并且函数失败。

pfContextAttr[out]

指向变量的指针,用于接收一组指示已建立上下文的属性的位标志。 有关各种属性的说明,请参阅上下文要求

用于此参数的标志以 ISC_RET 为前缀,例如 ISC_RET_DELEGATE。 有关有效值的列表,请参阅 fContextReq 参数。

在最终函数调用成功返回之前,不要检查与安全性相关的属性。 与安全性无关的属性标志(如 ASC_RET_ALLOCATED_MEMORY 标志)可以在最终返回之前进行检查。

注意

在与远程对等机协商期间,特定上下文属性可能会更改。

ptsExpiry[out, optional]

指向接收上下文到期时间的 TimeStamp 结构的指针。 建议安全数据包始终在本地时间返回此值。 此参数是可选的,NULL 应为生存期较短的客户端传递。

Microsoft Digest SSP 安全上下文或凭据没有过期时间。

返回值

如果函数成功,该函数将返回以下成功代码之一。

返回代码 说明
SEC_I_COMPLETE_AND_CONTINUE 客户端必须调用 CompleteAuthToken,然后将输出传递给服务器。 然后,客户端等待返回的令牌,并在另一个调用中将其传递给 InitializeSecurityContext(常规)
SEC_I_COMPLETE_NEEDED 客户端必须完成消息生成,然后调用 CompleteAuthToken 函数。
SEC_I_CONTINUE_NEEDED 客户端必须将输出令牌发送到服务器并等待返回令牌。 然后,返回的令牌在另一个调用 InitializeSecurityContext(常规)中传递。 输出令牌可以为空。
SEC_I_INCOMPLETE_CREDENTIALS 与 Schannel 一起使用。 服务器已请求客户端身份验证,提供的凭据要么不包括证书,要么证书不是由服务器信任的证书颁发机构颁发的。 有关详细信息,请参阅“备注”。
SEC_E_INCOMPLETE_MESSAGE 与 Schannel 一起使用。 整个消息的数据不是从网络读取的。
返回此值时,pInput 缓冲区包含一个 SecBuffer 结构,其 BufferType 成员为 SECBUFFER_MISSINGSecBuffercbBuffer 成员包含一个值,该值指示函数在此函数成功之前必须从客户端读取的其他字节数。 虽然此数字并非总是准确,但使用它有助于通过避免多次调用此函数来提高性能。
SEC_E_OK 安全上下文已成功初始化。 不需要另一个 InitializeSecurityContext(常规)调用。 如果函数返回输出令牌,即,如果 pOutput 中的 SECBUFFER_TOKEN 长度为非零,则必须将令牌发送到服务器。

如果函数失败,该函数将返回以下错误代码之一。

返回代码 说明
SEC_E_INSUFFICIENT_MEMORY 没有足够的内存可用于完成请求的操作。
SEC_E_INTERNAL_ERROR 出现未映射到 SSPI 错误代码的错误。
SEC_E_INVALID_HANDLE 传递到函数的句柄无效。
SEC_E_INVALID_TOKEN 错误是由于输入令牌格式不正确,例如在传输过程中损坏的令牌、大小不正确的令牌或传递到错误的安全数据包中的令牌。 如果客户端和服务器未协商正确的安全数据包,则可能会将令牌传递到错误的包。
SEC_E_LOGON_DENIED 登录失败。
SEC_E_NO_AUTHENTICATING_AUTHORITY 无法联系任何机构进行身份验证。 身份验证方的域名可能是错误的,域可能无法访问,或者可能存在信任关系失败。
SEC_E_NO_CREDENTIALS 安全数据包中没有可用的凭证。
SEC_E_TARGET_UNKNOWN 无法识别目标。
SEC_E_UNSUPPORTED_FUNCTION fContextReq 参数中指定了无效的上下文属性标志(ISC_REQ_DELEGATE 或 ISC_REQ_PROMPT_FOR_CREDS)。
SEC_E_WRONG_PRINCIPAL 接收身份验证请求的主体与传递到 pszTargetName 参数的主体不同。 这表示相互身份验证失败。

注解

调用方负责确定最终上下文属性是否足够。 例如,如果请求了保密性,但无法建立,某些应用程序可能会选择立即关闭连接。

如果安全上下文的属性不够,客户端必须通过调用 DeleteSecurityContext 函数释放部分创建的上下文。

InitializeSecurityContext(常规)函数由客户端用来初始化出站上下文。

对于具有 2 个 leg 的安全上下文,调用序列如下所示:

  1. 客户端调用 phContext 设置为 NULL 的函数,并使用输入消息填充缓冲区描述符。
  2. 安全数据包检查参数并构造不透明令牌,并将其放置在缓冲区数组中的 TOKEN 元素中。 如果 fContextReq 参数包含 ISC_REQ_ALLOCATE_MEMORY 标志,则安全数据包将分配内存并返回 TOKEN 元素中的指针。
  3. 客户端将 pOutput 缓冲区中返回的令牌发送到目标服务器。 然后,服务器在对 AcceptSecurityContext(常规)函数的调用中将令牌作为输入参数传递。
  4. AcceptSecurityContext(常规)可能会返回令牌,如果第一次调用返回 SEC_I_CONTINUE_NEEDED,服务器会向客户端发送第二次对 InitializeSecurityContext(常规)的调用。

对于多 leg 安全上下文(例如相互身份验证),调用顺序如下所示:

  1. 客户端如前所述调用函数,但包返回 SEC_I_CONTINUE_NEEDED 成功代码。
  2. 客户端将输出令牌发送到服务器,并等待服务器的回复。
  3. 收到服务器的响应后,客户端将再次调用 InitializeSecurityContext(常规),并将 phContext 设置为从上次调用返回的句柄。 从服务器收到的令牌在 pInput 参数中提供。
  4. 请勿在对 InitializeSecurityContext(常规)的并发调用中使用 phContext值。 安全提供商中实现的线程不安全。

如果服务器已成功响应,安全数据包将返回 SEC_E_OK 并建立安全会话。

如果函数返回错误响应之一,则服务器的响应未得到接受,并且会话未建立。

如果函数返回 SEC_I_CONTINUE_NEEDED、SEC_I_COMPLETE_NEEDED 或 SEC_I_COMPLETE_AND_CONTINUE,则重复步骤 2 和 3。

若要初始化安全上下文,可能需要多次调用此函数,具体取决于基础身份验证机制以及 fContextReq 参数中指定的选项。

fContextReqpfContextAttributes 参数是表示各种上下文属性的位掩码。 有关各种属性的说明,请参阅上下文要求pfContextAttributes 参数在任何成功返回时都有效,但只有在最终成功返回时,才能检查与上下文安全性方面相关的标志。 中间返回可以设置 ISC_RET_ALLOCATED_MEMORY 标志。

如果设置了 ISC_REQ_USE_SUPPLIED_CREDS 标志,安全数据包必须在 pInput 输入缓冲区中查找 SECBUFFER_PKG_PARAMS 缓冲区类型。 这不是常规解决方案,但它允许在适当的时候对安全数据包和应用程序进行强配对。

如果指定了 ISC_REQ_ALLOCATE_MEMORY,调用方必须通过调用 FreeContextBuffer 函数释放内存。

例如,输入令牌可能是 LAN 管理器的质询。 在这种情况下,输出令牌将是对质询的 NTLM 加密响应。

客户端执行的操作取决于此函数的返回代码。 如果返回代码 SEC_E_OK,则不会进行第二次 InitializeSecurityContext(常规)调用,并且不会收到来自服务器的响应。 如果返回代码 SEC_I_CONTINUE_NEEDED,客户端需要来自服务器的响应令牌,并在第二次对 InitializeSecurityContext(常规)的调用中传递令牌。 SEC_I_COMPLETE_NEEDED 返回代码指示客户端必须完成消息生成并调用 CompleteAuthToken 函数。 SEC_I_COMPLETE_AND_CONTINUE 代码包含这两个操作。

如果 InitializeSecurityContext(常规)在第一次(或仅有的一次)调用中返回成功,则调用方最终必须在返回的句柄上调用 DeleteSecurityContext 函数,即使调用在身份验证交换的后续 leg 失败。

客户端在成功完成后可以再次调用 InitializeSecurityContext(常规)。 这向安全数据包指示需要重新身份验证。

内核模式调用方具有以下差异:目标名称是必须使用 VirtualAlloc 在虚拟内存中分配的 Unicode 字符串,不得从池中分配。 在 pInputpOutput 中传递和提供的缓冲区必须位于虚拟内存中,而不是池中。

使用 Schannel SSP 时,如果函数返回 SEC_I_INCOMPLETE_CREDENTIALS,请检查是否在凭据中指定了有效且受信任的证书。 调用 AcquireCredentialsHandle(常规)函数时指定证书。 证书必须是服务器信任的证书颁发机构 (CA) 颁发的客户端身份验证证书。 若要获取服务器信任的 CA 列表,请调用 QueryContextAttributes(常规)函数并指定 SECPKG_ATTR_ISSUER_LIST_EX 属性。

使用 Schannel SSP 时,客户端应用程序从服务器信任的 CA 收到身份验证证书后,应用程序会通过调用 AcquireCredentialsHandle (常规)函数,然后再次调用 InitializeSecurityContext(常规),以便创建新的凭据,同时在 phCredential 参数中指定新凭据。

要求

要求
最低受支持的客户端 Windows XP [仅限桌面应用]
最低受支持的服务器 Windows Server 2003 [仅限桌面应用]
标头 Sspi.h(包括 Security.h)
Secur32.lib
DLL Secur32.dll
Unicode 和 ANSI 名称 InitializeSecurityContextW (Unicode) 和 InitializeSecurityContextA (ANSI)

另请参阅

SSPI 函数

支持服务中的身份验证扩展保护 (EPA)

AcceptSecurityContext(常规)

AcquireCredentialsHandle(常规)

CompleteAuthToken

DeleteSecurityContext

FreeContextBuffer

SecBuffer

SecBufferDesc