2016-07-15 1 views
0

Я создаю поставщик учетных данных 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; 
} 

ответ

2

Из документации компании Microsoft о KERB_CERTIFICATE_LOGON структуры:

указателей, хранящихся в элементах типа UNICODE_STRING относительны к началу структуры и не являются абсолютная память указатели.

Но документация не сказать вам, что CspData указатель должен также быть относительно начала структуры ...

При вызове LsaLogonUser с данными с абсолютными указателями памяти он будет работать, и когда указатели относительный. Когда данные сериализуются, они будут работать только со всеми указателями.

Также иногда (в зависимости от CREDENTIAL_PROVIDER_USAGE_SCENARIO) вы должны использовать KERB_CERTIFICATE_UNLOCK_LOGON вместо KERB_CERTIFICATE_LOGON.

+0

Я взял относительные указатели, а также строки Юникода. Я обновил исходное сообщение, чтобы включить функцию InitializeKerbCertificateLogon. –

+0

Вы пробовали это: pKerbCertLogon-> DomainName.Buffer = (PWSTR) (pbDomainBuffer-pbAuthInfo); pKerbCertLogon-> UserName.Buffer = (PWSTR) (pbUserBuffer-pbAuthInfo); pKerbCertLogon-> Pin.Buffer = (PWSTR) (pbPinBuffer-pbAuthInfo); pKerbCertLogon-> CspData = (PUCHAR) (pbCspData-pbAuthInfo); ? –

+0

Это было! Большое спасибо! Я полностью пропустил это из документации и тот факт, что он работал с LsaLogonUser, заставив меня не подвергать сомнению код упаковки auth. –

Смежные вопросы