Я создаю поставщик учетных данных Windows для входа в домен Windows, используя сертификаты, как описано в этом article. Это означает создание пользовательского KSP, который будет вызываться LsaLogonUser при создании пакета проверки подлинности.KSP (Key Storage Provider) не загружается при входе в систему через Поставщик учетных данных
Мне удалось создать пользовательский KSP и протестировать его успешно в автономном приложении, которое напрямую вызывает LsaLogonUser. В основном создавая пакет проверки подлинности и передавая его в LsaLogonUser, загружал KSP, называл кучу функций и аутентифицировал пользователя, возвращающего результат успеха, на код состояния и загруженный профиль пользователя.
Однако, когда я использую тот же пакет проверки подлинности во время GetSerialization для учетных данных, KSP даже не загружается, и я получаю 0xc000000d (параметр неверен), сообщенный ReportResult (NTSTATUS ntsStatus, NTSTATUS ntsSubstatus, .. ..) на ntsStatus.
Это код 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;
}
Мой вопрос, почему KSP становится загружен, когда пакет аутентификации вызывается из LsaLogonUser непосредственно, но не от Credential поставщика во время вход в Windows.
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;
}
Я взял относительные указатели, а также строки Юникода. Я обновил исходное сообщение, чтобы включить функцию InitializeKerbCertificateLogon. –
Вы пробовали это: pKerbCertLogon-> DomainName.Buffer = (PWSTR) (pbDomainBuffer-pbAuthInfo); pKerbCertLogon-> UserName.Buffer = (PWSTR) (pbUserBuffer-pbAuthInfo); pKerbCertLogon-> Pin.Buffer = (PWSTR) (pbPinBuffer-pbAuthInfo); pKerbCertLogon-> CspData = (PUCHAR) (pbCspData-pbAuthInfo); ? –
Это было! Большое спасибо! Я полностью пропустил это из документации и тот факт, что он работал с LsaLogonUser, заставив меня не подвергать сомнению код упаковки auth. –