InitializeSecurityContext (CredSSP) 函数
InitializeSecurityContext (CredSSP) 函数从凭据句柄启动客户端出站安全上下文。 函数在客户端应用程序和远程对等方之间生成安全上下文。 InitializeSecurityContext (CredSSP) 返回客户端必须传递给远程对等方的令牌;对等方又通过 AcceptSecurityContext (CredSSP) 调用将令牌提交到本地安全实现。 所有调用方都应将生成的令牌视为不透明。
通常,在建立足够的安全上下文之前,在循环中调用 InitializeSecurityContext (CredSSP) 函数。
语法
SECURITY_STATUS SEC_ENTRY InitializeSecurityContext(
_In_opt_ PCredHandle phCredential,
_In_opt_ PCtxtHandle phContext,
_In_opt_ SEC_CHAR *pszTargetName,
_In_ unsigned long fContextReq,
_Reserved_ unsigned long Reserved1,
_In_ unsigned long TargetDataRep,
_Inout_opt_ PSecBufferDesc pInput,
_In_ unsigned long Reserved2,
_Inout_opt_ PCtxtHandle phNewContext,
_Out_opt_ PSecBufferDesc pOutput,
_Out_ unsigned long *pfContextAttr,
_Out_opt_ PTimeStamp ptsExpiry
);
参数
phCredential[in, optional]
AcquireCredentialsHandle 返回的凭据的句柄 (CredSSP) 。 此句柄用于生成安全上下文。 InitializeSecurityContext (CredSSP) 函数至少需要出站凭据。
phContext[in, optional]
指向 CtxtHandle 结构的指针。 在首次调用 InitializeSecurityContext (CredSSP) 时,此指针为 NULL
。 在第二次调用中,此参数是指向第一次调用在 phNewContext 参数中返回的部分格式上下文的句柄的指针。
在首次调用 InitializeSecurityContext (CredSSP) 时,指定 NULL
。 在将来的调用中,指定在首次调用此函数后 在 phNewContext 参数中收到的令牌。
警告
不要在 对 InitializeSecurityContext (CredSSP) 的并发调用中使用相同的上下文句柄。 安全服务提供程序中的 API 实现不是线程安全的。
pTargetName[in, optional]
指向唯一标识目标服务器的以 null 结尾的字符串的指针。 Schannel 使用此值来验证服务器证书。 重新建立连接时,Schannel 还使用此值在会话缓存中查找会话。 仅当满足以下所有条件时,才使用缓存的会话:
- 目标名称相同。
- 缓存条目尚未过期。
- 调用 函数的应用程序进程是相同的。
- 登录会话是相同的。
- 凭据句柄相同。
fContextReq[in]
指示上下文请求的位标志。 并非所有包都可以支持所有要求。 用于此参数的标志以 ISC_REQ_ 为前缀,例如,ISC_REQ_DELEGATE。
此参数可以是以下一个或多个属性标志。
值 | 含义 |
---|---|
ISC_REQ_ALLOCATE_MEMORY0x100 |
安全包为调用方分配输出缓冲区。 使用完输出缓冲区后,通过调用 FreeContextBuffer 函数释放它们。 |
ISC_REQ_CONNECTION0x800 |
安全上下文不会处理格式化消息。 |
ISC_REQ_EXTENDED_ERROR0x4000 |
发生错误时,远程方将收到通知。 |
ISC_REQ_MANUAL_CRED_VALIDATION0x80000 |
凭据安全支持提供程序 (CredSSP) 不得自动对服务器进行身份验证。 使用 CredSSP 时,始终设置此标志。 |
ISC_REQ_SEQUENCE_DETECT0x8 |
检测不按顺序接收的消息。 |
ISC_REQ_STREAM0x8000 |
支持面向流的连接。 |
ISC_REQ_USE_SUPPLIED_CREDS0x80 |
CredSSP 不得尝试自动为客户端提供凭据。 |
ISC_REQ_DELEGATE0x1 |
指示将用户的凭据委托给服务器。 如果未指定此标志,则会将一组空凭据委托给服务器。 Windows Server 2008 和 Windows Vista: 此标志是必需的。 |
ISC_REQ_MUTUAL_AUTH0x2 |
指示不需要服务器身份验证。 如果未指定此标志,则仍会强制实施委派策略。 Windows Server 2008 和 Windows Vista: 忽略此标志。 |
客户端可能不支持请求的属性。 有关详细信息,请参阅 pfContextAttr 参数。
有关各种属性的进一步说明,请参阅 上下文要求。
Reserved1[in]
保留。 此参数必须设置为零。
TargetDataRep[in]
目标上的数据表示形式,例如字节排序。 此参数可以是 SECURITY_NATIVE_DREP 或 SECURITY_NETWORK_DREP。
pInput[in, out, optional]
指向 SecBufferDesc 结构的指针,该结构包含指向作为输入提供给包的缓冲区的指针。 除非客户端上下文由服务器启动,否则此参数的值必须在 NULL
首次调用函数时。 在对函数的后续调用或服务器启动客户端上下文时,此参数的值是指向分配的缓冲区的指针,该缓冲区具有足够的内存来保存远程计算机返回的令牌。
在初始调用后调用此函数时,必须有两个缓冲区。 第一个 类型 为 SECBUFFER_TOKEN ,包含从服务器接收的令牌。 第二个缓冲区的类型 为 SECBUFFER_EMPTY;将 pvBuffer 和 cbBuffer 成员都设置为零。
Reserved2[in]
保留。 此参数必须设置为零。
phNewContext[in, out, optional]
指向 CtxtHandle 结构的指针。 在首次调用 InitializeSecurityContext (CredSSP) 时,此指针接收新的上下文句柄。 第二次调用 时,phNewContext 可以与 phContext 参数中指定的句柄相同。
phNewContext 不应为 NULL
。
pOutput[out, optional]
指向 SecBufferDesc 结构的指针。 此结构又包含指向接收输出数据的 SecBuffer 结构的指针。 如果在输入中将缓冲区类型化为 SEC_READWRITE ,则输出中将存在缓冲区。 如果 通过ISC_REQ_ALLOCATE_MEMORY) 请求 (安全令牌,系统会为安全令牌分配缓冲区,并在安全令牌的缓冲区描述符中填写地址。
如果指定 了 ISC_REQ_ALLOCATE_MEMORY 标志,CredSSP 将为缓冲区分配内存,并将相应的信息放入 SecBufferDesc 中。
pfContextAttr[out]
指向一组位标志的 指针,这些 标志指示已建立上下文的属性。 有关各种属性的说明,请参阅 上下文要求。
用于此参数的标志以 ISC_RET 为前缀,例如 ISC_RET_DELEGATE。 有关有效值的列表,请参阅 fContextReq 参数。
在最终函数调用成功返回之前,不要检查与安全相关的属性。 可以在最终返回之前检查与安全性无关的属性标志(例如 ASC_RET_ALLOCATED_MEMORY 标志)。
注意
在与远程对等方协商期间,特定上下文属性可能会更改。
ptsExpiry[out, optional]
指向接收上下文过期时间的 TimeStamp 结构的指针。 建议安全包始终在本地时间返回此值。 此参数是可选的, NULL
应为生存期较短的客户端传递。
返回值
如果函数成功,它将返回以下成功代码之一。
返回代码 | 说明 |
---|---|
SEC_E_INCOMPLETE_MESSAGE | 未从线路中读取整个消息的数据。 返回此值时, pInput 缓冲区包含一个 SecBuffer 结构, 其 BufferType 成员 为 SECBUFFER_MISSING。 SecBuffer 的 cbBuffer 成员指定函数在此函数成功之前必须从客户端读取的其他字节数。 虽然此数字并非始终准确,但使用它可避免多次调用此函数,从而帮助提高性能。 |
SEC_E_OK | 已成功初始化安全上下文。 无需另一个 InitializeSecurityContext (CredSSP) 调用。 如果函数返回输出标记(即 pOutput 中的SECBUFFER_TOKEN长度为非零),则必须将令牌发送到服务器。 |
SEC_I_COMPLETE_AND_CONTINUE | 客户端必须调用 CompleteAuthToken ,然后将输出传递给服务器。 然后,客户端等待返回的令牌,并在另一次调用中将其传递给 InitializeSecurityContext (CredSSP) 。 |
SEC_I_COMPLETE_NEEDED | 客户端必须完成消息的生成,然后调用 CompleteAuthToken 函数。 |
SEC_I_CONTINUE_NEEDED | 客户端必须将输出令牌发送到服务器并等待返回令牌。 客户端在另一次调用 InitializeSecurityContext (CredSSP) 中传递返回的令牌。 输出令牌可以为空。 |
SEC_I_INCOMPLETE_CREDENTIALS | 服务器已请求客户端身份验证,但提供的凭据不包括证书,或者证书不是由服务器信任的证书颁发机构颁发的。 有关详细信息,请参阅“备注”。 |
如果函数失败,该函数将返回以下错误代码之一。
返回代码 | 说明 |
---|---|
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 参数的值无效。 未指定必需的标志,或者指定了 CredSSP 不支持的标志。 |
SEC_E_WRONG_PRINCIPAL | 接收身份验证请求的主体与传递到 pszTargetName 参数的主体不同。 此错误表示相互身份验证失败。 |
SEC_E_DELEGATION_POLICY | 策略不支持将凭据委派给目标服务器。 |
SEC_E_POLICY_NLTM_ONLY | 如果未实现相互身份验证,则不允许将凭据委派给目标服务器。 |
SEC_E_MUTUAL_AUTH_FAILED | 在 fContextReq 参数中指定ISC_REQ_MUTUAL_AUTH标志时,服务器身份验证失败。 |
备注
调用方负责确定最终的上下文属性是否足够。 例如,如果请求了机密性,但无法建立,则某些应用程序可能会选择立即关闭连接。
如果安全上下文的属性不够,客户端必须通过调用 DeleteSecurityContext 函数释放部分创建的上下文。
客户端调用 InitializeSecurityContext (CredSSP) 函数来初始化出站上下文。
对于双腿安全上下文,调用顺序如下:
- 客户端调用将 phContext 设置为
NULL
的 函数,并使用输入消息填充缓冲区描述符。 - 安全包检查参数并构造一个不透明的令牌,并将其放置在缓冲区数组的 TOKEN 元素中。 如果 fContextReq 参数包含 ISC_REQ_ALLOCATE_MEMORY 标志,则安全包将分配内存并返回 TOKEN 元素中的指针。
- 客户端将 pOutput 缓冲区中返回的令牌发送到目标服务器。 然后,服务器在调用 AcceptSecurityContext (CredSSP) 函数时将令牌作为输入参数传递。
- AcceptSecurityContext (CredSSP) 可能会返回令牌。 如果第一个调用返回SEC_I_CONTINUE_NEEDED,服务器将通过第二个 InitializeSecurityContext (CredSSP) 调用 将此令牌发送到客户端。
如果服务器已成功响应,则安全包将返回 SEC_E_OK 并建立安全会话。
如果函数返回错误响应之一,则不接受服务器的响应,并且不会建立会话。
如果函数返回 SEC_I_CONTINUE_NEEDED、 SEC_I_COMPLETE_NEEDED或 SEC_I_COMPLETE_AND_CONTINUE,则重复步骤 2 和 3。
安全上下文初始化可能需要多次调用此函数,具体取决于基础身份验证机制以及在 fContextReq 参数中指定的选项。
fContextReq 和 pfContextAttributes 参数是表示各种上下文属性的位掩码。 有关各种属性的说明,请参阅 上下文要求。 虽然 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 (CredSSP) 调用,并且服务器不会做出响应。 如果返回代码 SEC_I_CONTINUE_NEEDED,则客户端需要一个令牌来响应服务器,并在第二次调用 InitializeSecurityContext (CredSSP) 传递它。 SEC_I_COMPLETE_NEEDED返回代码指示客户端必须完成消息生成并调用 CompleteAuthToken 函数。 SEC_I_COMPLETE_AND_CONTINUE代码包含这两个操作。
如果 InitializeSecurityContext (CredSSP) 在第一个 (或仅) 调用返回成功,则调用方最终必须在返回的句柄上调用 DeleteSecurityContext 函数,即使调用在身份验证交换的后续回合中失败也是如此。
客户端可以在成功完成后再次调用 InitializeSecurityContext (CredSSP) 。 这向安全包指示需要重新身份验证。
内核模式调用方具有以下差异:目标名称是 Unicode 字符串,必须使用 VirtualAlloc 在虚拟内存中分配;不得从池中分配它。 在 pInput 和 pOutput 中传递和提供的缓冲区必须位于虚拟内存中,而不是在池中。
如果函数返回SEC_I_INCOMPLETE_CREDENTIALS,检查传递给 AcquireCredentialsHandle (CredSSP) 函数的 r 凭据指定了一个有效且受信任的证书。证书必须是服务器信任的证书颁发机构颁发的客户端身份验证证书。 若要获取服务器信任的 CA 的列表,请使用 SECPKG_ATTR_ISSUER_LIST_EX 属性调用QueryContextAttributes (CredSSP) 函数。
从服务器信任的证书颁发机构收到身份验证证书后,客户端应用程序将创建新的凭据。 为此,它调用 AcquireCredentialsHandle (CredSSP) 函数,然后再次调用 InitializeSecurityContext (CredSSP) ,并在 phCredential 参数中指定新凭据。
要求
要求 | 值 |
---|---|
最低受支持的客户端 | Windows Vista [仅限桌面应用] |
最低受支持的服务器 | Windows Server 2008 [仅限桌面应用] |
标头 | Sspi.h (包括 Security.h) |
库 | Secur32.lib |
DLL | Secur32.dll |
另请参阅
AcceptSecurityContext (CredSSP)