InitializeSecurityContextW 函数 (sspi.h)

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

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

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

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

语法

KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY InitializeSecurityContextW(
  [in, optional]      PCredHandle      phCredential,
  [in, optional]      PCtxtHandle      phContext,
  [in, optional]      PSECURITY_STRING pTargetName,
  [in]                unsigned long    fContextReq,
  [in]                unsigned long    Reserved1,
  [in]                unsigned long    TargetDataRep,
  [in, optional]      PSecBufferDesc   pInput,
  [in]                unsigned long    Reserved2,
  [in, out, optional] PCtxtHandle      phNewContext,
  [in, out, optional] PSecBufferDesc   pOutput,
  [out]               unsigned long    *pfContextAttr,
  [out, optional]     PTimeStamp       ptsExpiry
);

参数

[in, optional] phCredential

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

[in, optional] phContext

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

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

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

[in, optional] pTargetName

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

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

[in] fContextReq

指示上下文请求的位标志。 并非所有包都支持所有要求。 用于此参数的标志以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 参数。

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

[in] Reserved1

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

[in] TargetDataRep

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

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

[in, optional] pInput

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

[in] Reserved2

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

[in, out, optional] phNewContext

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

在第一次调用后使用 Schannel SSP 时,将返回的句柄作为 phContext 参数传递,并为 phNewContext指定 NULL

[in, out, optional] pOutput

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

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

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

[out] pfContextAttr

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

用于此参数的标志以ISC_RET为前缀,例如ISC_RET_DELEGATE。

有关有效值的列表,请参阅 fContextReq 参数。

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

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

[out, optional] ptsExpiry

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

Microsoft摘要 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 缓冲区包含具有 BufferTypeSECBUFFER_MISSING成员的 SecBuffer 结构。 cbBuffer secBuffer 的成员包含一个值,该值指示函数在函数成功之前必须从客户端读取的其他字节数。 虽然此数字并非总是准确,但使用它有助于通过避免多次调用此函数来提高性能。

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(常规) 函数初始化出站上下文。

对于双腿安全上下文,调用序列如下所示:

  1. 客户端调用 phContext 设置为 NULL 的函数,并使用输入消息填充缓冲区描述符。
  2. 安全包检查参数并构造不透明令牌,并将其放置在缓冲区数组中的 TOKEN 元素中。 如果 fContextReq 参数包括ISC_REQ_ALLOCATE_MEMORY标志,则安全包将分配内存并返回 TOKEN 元素中的指针。
  3. 客户端将 pOutput 缓冲区中返回的令牌发送到目标服务器。 然后,服务器在调用 AcceptSecurityContext(常规) 函数时将令牌作为输入参数传递。
  4. AcceptSecurityContext(常规) 可能会返回一个令牌,如果第一次调用返回SEC_I_CONTINUE_NEEDED,服务器会向客户端发送第二次调用 InitializeSecurityContext (常规)
对于多回合安全上下文(例如相互身份验证),调用顺序如下所示:
  1. 客户端如前所述调用函数,但包返回SEC_I_CONTINUE_NEEDED成功代码。
  2. 客户端将输出令牌发送到服务器,并等待服务器的回复。
  3. 收到服务器的响应后,客户端再次调用 InitializeSecurityContext (常规)phContext 设置为上次调用返回的句柄。 从服务器收到的令牌在 pInput 参数中提供。
如果服务器已成功响应,则安全包将返回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 函数,即使调用在身份验证交换的后续部分失败。

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

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

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

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

注意

sspi.h 标头将 InitializeSecurityContext 定义为一个别名,该别名根据 UNICODE 预处理器常量的定义自动选择此函数的 ANSI 或 Unicode 版本。 将中性编码别名与不中性编码的代码混合使用可能会导致编译或运行时错误不匹配。 有关详细信息,请参阅函数原型的 约定。

要求

要求 价值
最低支持的客户端 Windows XP [仅限桌面应用]
支持的最低服务器 Windows Server 2003 [仅限桌面应用]
目标平台 窗户
标头 sspi.h (包括 Security.h)
Secur32.lib
DLL Secur32.dll

另请参阅

AcceptSecurityContext (常规)

AcquireCredentialsHandle (常规)

CompleteAuthToken

DeleteSecurityContext

FreeContextBuffer

SSPI 函数

SecBuffer

SecBufferDesc