KSP(密钥存储提供程序)未通过凭据提供程序在登录时加载
KSP (Key Storage Provider) not being loaded at logon via a Credential Provider
我正在创建一个 Windows 凭据提供程序,以使用本文中所述的证书登录到 Windows 域。这意味着创建一个自定义 KSP,LsaLogonUser 将在创建身份验证包时调用该 KSP。
我设法创建自定义 KSP 并在直接调用 LsaLogonUser 的独立应用程序中成功测试了它。基本上创建身份验证包并将其传递给LsaLogonUser,加载KSP,调用一堆函数并对用户进行身份验证,在状态代码和加载的用户配置文件上返回成功结果。
但是,当我在凭据上的 GetSerialization 期间使用相同的身份验证包时,KSP 甚至不会加载,并且我在 ntsStatus 上收到 ReportResult(NTSTATUS ntsStatus, NTSTATUS ntsSubstatus, ....) 报告的0xc000000d(参数不正确)。
这是我在测试中使用的 GetSerialization 代码:
HRESULT AOCredential::GetSerialization(
CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE *pcpgsr,
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *pcpcs,
PWSTR *ppwszOptionalStatusText,
CREDENTIAL_PROVIDER_STATUS_ICON *pcpsiOptionalStatusIcon
)
{
UNREFERENCED_PARAMETER(ppwszOptionalStatusText);
UNREFERENCED_PARAMETER(pcpsiOptionalStatusIcon);
HRESULT hr;
ULONG ulAuthPackage;
hr = RetrieveKerberosAuthPackage(&ulAuthPackage);
if (SUCCEEDED(hr))
{
InitialiseKerbCertificateLogon(&pcpcs->rgbSerialization, &pcpcs->cbSerialization); // this package actually worked when calling LsaLogonUser function directly (the KSP gets loaded and the authentication succeeds)
pcpcs->ulAuthenticationPackage = ulAuthPackage;
pcpcs->clsidCredentialProvider = CLSID_CallsignProvider;
*pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED;
}
return hr;
}
我的问题是,为什么在Windows登录期间直接从LsaLogonUser调用身份验证包而不是从凭据提供程序调用时加载KSP。
InitialiseKerbCertificateLogon 代码为:
void InitialiseKerbCertificateLogon(PWSTR domain, PWSTR username, LPBYTE* authInfo, ULONG *authInfoLength)
{
WCHAR szCardName[] = L"";
WCHAR szContainerName[] = L"Default";
WCHAR szReaderName[] = L"";
WCHAR szCspName[] = CS_KSP_NAME;
WCHAR szPin[] = CS_TEST_PIN;
ULONG ulPinByteLen = (ULONG)(wcslen(szPin) * sizeof(WCHAR));
WCHAR szUserName[] = CS_TEST_USERNAME;
ULONG ulUserByteLen = (ULONG)(wcslen(szUserName) * sizeof(WCHAR));
WCHAR szDomainName[] = CS_TEST_DOMAIN;
ULONG ulDomainByteLen = (ULONG)(wcslen(szDomainName) * sizeof(WCHAR));
LPBYTE pbAuthInfo = NULL;
ULONG ulAuthInfoLen = 0;
KERB_CERTIFICATE_LOGON *pKerbCertLogon;
KERB_SMARTCARD_CSP_INFO *pKerbCspInfo;
LPBYTE pbDomainBuffer, pbUserBuffer, pbPinBuffer;
LPBYTE pbCspData;
LPBYTE pbCspDataContent;
ULONG ulCspDataLen = (ULONG)(sizeof(KERB_SMARTCARD_CSP_INFO) - sizeof(TCHAR) +
(wcslen(szCardName) + 1) * sizeof(WCHAR) +
(wcslen(szCspName) + 1) * sizeof(WCHAR) +
(wcslen(szContainerName) + 1) * sizeof(WCHAR) +
(wcslen(szReaderName) + 1) * sizeof(WCHAR));
ulAuthInfoLen = sizeof(KERB_CERTIFICATE_LOGON) +
ulDomainByteLen + sizeof(WCHAR) +
ulUserByteLen + sizeof(WCHAR) +
ulPinByteLen + sizeof(WCHAR) +
ulCspDataLen;
pbAuthInfo = (LPBYTE)CoTaskMemAlloc(ulAuthInfoLen);
ZeroMemory(pbAuthInfo, ulAuthInfoLen);
pbDomainBuffer = pbAuthInfo + sizeof(KERB_CERTIFICATE_LOGON);
pbUserBuffer = pbDomainBuffer + ulDomainByteLen + sizeof(WCHAR);
pbPinBuffer = pbUserBuffer + ulUserByteLen + sizeof(WCHAR);
pbCspData = pbPinBuffer + ulPinByteLen + sizeof(WCHAR);
memcpy(pbDomainBuffer, szDomainName, ulDomainByteLen);
memcpy(pbUserBuffer, szUserName, ulUserByteLen);
memcpy(pbPinBuffer, szPin, ulPinByteLen);
pKerbCertLogon = (KERB_CERTIFICATE_LOGON*)pbAuthInfo;
pKerbCertLogon->MessageType = KerbCertificateLogon;
pKerbCertLogon->DomainName.Length = (USHORT)ulDomainByteLen;
pKerbCertLogon->DomainName.MaximumLength = (USHORT)(ulDomainByteLen + sizeof(WCHAR));
pKerbCertLogon->DomainName.Buffer = (PWSTR)pbDomainBuffer;
pKerbCertLogon->UserName.Length = (USHORT)ulUserByteLen;
pKerbCertLogon->UserName.MaximumLength = (USHORT)(ulUserByteLen + sizeof(WCHAR));
pKerbCertLogon->UserName.Buffer = (PWSTR)pbUserBuffer;
pKerbCertLogon->Pin.Length = (USHORT)ulPinByteLen;
pKerbCertLogon->Pin.MaximumLength = (USHORT)(ulPinByteLen + sizeof(WCHAR));
pKerbCertLogon->Pin.Buffer = (PWSTR)pbPinBuffer;
pKerbCertLogon->CspDataLength = ulCspDataLen;
pKerbCertLogon->CspData = pbCspData;
pKerbCspInfo = (KERB_SMARTCARD_CSP_INFO*)pbCspData;
pKerbCspInfo->dwCspInfoLen = ulCspDataLen;
pKerbCspInfo->MessageType = 1;
pKerbCspInfo->KeySpec = AT_KEYEXCHANGE;
pKerbCspInfo->nCardNameOffset = 0;
pKerbCspInfo->nReaderNameOffset = pKerbCspInfo->nCardNameOffset + (ULONG)wcslen(szCardName) + 1;
pKerbCspInfo->nContainerNameOffset = pKerbCspInfo->nReaderNameOffset + (ULONG)wcslen(szReaderName) + 1;
pKerbCspInfo->nCSPNameOffset = pKerbCspInfo->nContainerNameOffset + (ULONG)wcslen(szContainerName) + 1;
pbCspDataContent = pbCspData + sizeof(KERB_SMARTCARD_CSP_INFO) - sizeof(TCHAR);
memcpy(pbCspDataContent + (pKerbCspInfo->nCardNameOffset * sizeof(WCHAR)), szCardName, wcslen(szCardName) * sizeof(WCHAR));
memcpy(pbCspDataContent + (pKerbCspInfo->nReaderNameOffset * sizeof(WCHAR)), szReaderName, wcslen(szReaderName) * sizeof(WCHAR));
memcpy(pbCspDataContent + (pKerbCspInfo->nContainerNameOffset * sizeof(WCHAR)), szContainerName, wcslen(szContainerName) * sizeof(WCHAR));
memcpy(pbCspDataContent + (pKerbCspInfo->nCSPNameOffset * sizeof(WCHAR)), szCspName, wcslen(szCspName) * sizeof(WCHAR));
*authInfo = pbAuthInfo;
*authInfoLength = ulAuthInfoLen;
}
来自 Microsoft 关于KERB_CERTIFICATE_LOGON结构的文档:
存储在UNICODE_STRING类型成员中的指针是相对的 到结构的开头,不是绝对内存 指针。
但是文档并没有告诉你CspData
指针也应该相对于结构的开头......
当您使用绝对内存指针调用带有数据LsaLogonUser
时,它将起作用,当指针是相对的时也是如此。序列化数据时,将仅适用于所有相对指针。
此外,有时(取决于CREDENTIAL_PROVIDER_USAGE_SCENARIO)您应该使用KERB_CERTIFICATE_UNLOCK_LOGON而不是KERB_CERTIFICATE_LOGON。
- 我的程序有一个保存配置文件的GUI,如何双击此配置文件以直接加载带有配置数据的GUI?
- CoreCLR 中的检测探查器 - 将帮助程序程序集加载到 dotnet 进程的方法
- 如何在没有"路径"模块的情况下加载 cheerp-wasm 程序?
- 使用动态链接加载程序 <dlfcn.h> 而不是直接函数调用的目的是什么?
- 在另一台 PC 上执行程序时加载 SDL2 共享库时出错
- WinAPI C++如何从 64 位应用程序加载资源
- .NET核心应用程序无法加载C++DLL
- 每次b/c程序无法加载级联时,使用harr级联的人脸识别都会失败
- 将文件从 iOS 应用程序加载到 C++ 对象中/<iostream>iOS 上的问题
- 使用C++应用程序加载 DLL
- Clr Dll是由测试程序加载的,但不是由调用应用程序加载的
- 在Visual Studio 2015中调试本机应用程序加载的托管DLL
- 使用 C 应用程序加载的C++插件中的C++库
- 从 CLI C++应用程序加载库中的 C# WPF 窗体
- 使用C++窗口应用程序加载Linux格式的文本文件
- 我的应用程序加载缓慢或延迟
- 远程运行c++程序;加载共享库时出错
- 如果一个Android NDK应用程序加载了多个共享的c++ STL实现,它的行为是什么?
- 在Windows中,您可以通过编程(c++)检测其他正在运行的程序加载了哪些dll吗?
- C++ Win32 API 将驱动程序加载到内核空间