Intereting Posts
Будет ли Visual C ++ runtime malloc / бесплатная память возвращать в ОС? Сменил ли C ++ 11 требования к элементам контейнеров STL и как? Странное поведение «unsigned long long int» В C ++, должен ли я беспокоиться о кэшировании переменных или дать компилятору оптимизацию? (Сглаживание) Visual C ++ 2008 «Релиз» содержит информацию об отладке вызов конструктора можно рассматривать как объявление функции? Печать сообщений на консоль из C ++ DLL Получить время выполнения fragmentа кода C ++ выделяет аномально большую память amout для переменных Требуется ли, чтобы конструкторы перемещения не были исключением? Доступ к COM-интерфейсу с C ++ COM-сервера, который не регистрируется через C # Как добавить файл в существующий проект в Codelite? C ++ читается из istream до новой строки (но не в виде пробелов) Использует ли семантика `std :: memory_order_acquire` инструкции процессора на x86 / x86_64? glGetTexImage читает слишком много данных с форматом текстуры GL_ALPHA

Как написать KSP для подключения к KERB_CERTIFICATE_LOGON

Привет всем Я написал пользовательский credentialprovider, который отлично работает при использовании username / password в качестве учетных данных, пароль передается через bluetooth. В конце концов, это было не так сложно, так как документация рассказывает вам, какие интерфейсы для реализации.

Теперь я хочу изменить учетные данные для использования сертификатов. Я вижу, что для этого я должен использовать структуру KERB_CERTIFICATE_LOGON. Дайвинг глубже в теме, я обнаружил, что я должен реализовать специализированный поставщик хранилища ключей, как описано в этой статье Microsoft . И это тот момент, когда я потерялся. Возможно, я глупо искать правильную документацию, но я просто не могу найти, какие интерфейсы я должен реализовать, чтобы иметь KSP, который я могу ссылаться в поле CspData структуры KERB_CERTIFICATE_LOGON. Я просто нахожу кучу методов и быстрый поиск NCRYPT_CERTIFICATE_PROPERTY (упомянутый в вышеупомянутой связанной статье) показал удивительные два результата в google.

Я нашел этот SO-вопрос , который поможет мне подключить credentialprovider и KSP, когда у меня есть, но он не объясняет, как писать KSP. 🙁

Может ли кто-нибудь указать мне, где найти информацию, или показать короткую выборку KSP, используемую в аналогичном сценарии (только объявления метода, и как использовать полученный KSP в вызове KERB_CERTIFICATE_LOGON)?

    Этот комплект разработчика криптографических решений Microsoft имеет хорошую выборку KSP.

    Единственное, что вам нужно сделать в дополнение к этому образцу, – это реализовать свойство SmartCardKeyCertificate . Код будет примерно таким:

    SECURITY_STATUS WINAPI KSPGetKeyProperty( __in NCRYPT_PROV_HANDLE hProvider, __in NCRYPT_KEY_HANDLE hKey, __in LPCWSTR pszProperty, __out_bcount_part_opt(cbOutput, *pcbResult) PBYTE pbOutput, __in DWORD cbOutput, __out DWORD * pcbResult, __in DWORD dwFlags) { ... if (wcscmp(pszProperty, NCRYPT_CERTIFICATE_PROPERTY) == 0) { dwProperty = SAMPLEKSP_CERTIFICATE_PROPERTY; cbResult = GetCertificateSize(); //the size of the certificate that is associated with the key } *pcbResult = cbResult; if(pbOutput == NULL) { Status = ERROR_SUCCESS; goto cleanup; } if(cbOutput < *pcbResult) { Status = NTE_BUFFER_TOO_SMALL; goto cleanup; } if (wcscmp(pszProperty, NCRYPT_CERTIFICATE_PROPERTY) == 0) { CopyMemory(pbOutput, crt, sizeof(crt)); } switch(dwProperty) { case SAMPLEKSP_CERTIFICATE_PROPERTY: CopyMemory(pbOutput, GetCertificate(), cbResult); //Copy to pbOutput the certificate in binary form break; ... } ... } 

    После того, как вы реализуете KSP и зарегистрируете его, ваш CredentialProvider может взаимодействовать с ним:

     HRESULT MyCredential::GetSerialization( CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr, CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs, PWSTR* ppwszOptionalStatusText, CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon ) { ... ULONG ulAuthPackage; HRESULT hr = RetrieveNegotiateAuthPackage(&ulAuthPackage); ConstructAuthInfo(&pcpcs->rgbSerialization, &pcpcs->cbSerialization); if (SUCCEEDED(hr)) { pcpcs->ulAuthenticationPackage = ulAuthPackage; pcpcs->clsidCredentialProvider = CLSID_MyCredentialProvider; // At this point the credential has created the serialized credential used for logon // By setting this to CPGSR_RETURN_CREDENTIAL_FINISHED we are letting logonUI know // that we have all the information we need and it should attempt to submit the // serialized credential. *pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED; } return hr; } HRESULT RetrieveNegotiateAuthPackage(ULONG * pulAuthPackage) { HRESULT hr = S_OK; HANDLE hLsa = NULL; NTSTATUS status = LsaConnectUntrusted(&hLsa); if (SUCCEEDED(HRESULT_FROM_NT(status))) { ULONG ulAuthPackage; LSA_STRING lsaszKerberosName; LsaInitString(&lsaszKerberosName, MICROSOFT_KERBEROS_NAME_A); status = LsaLookupAuthenticationPackage(hLsa, &lsaszKerberosName, &ulAuthPackage); if (SUCCEEDED(HRESULT_FROM_NT(status))) { *pulAuthPackage = ulAuthPackage; hr = S_OK; } else { hr = HRESULT_FROM_NT(status); } LsaDeregisterLogonProcess(hLsa); } else { hr = HRESULT_FROM_NT(status); } return hr; } void ConstructAuthInfo(LPBYTE* ppbAuthInfo, ULONG *pulAuthInfoLen) { WCHAR szCardName[] = L""; // no card name specified but you can put one if you want WCHAR szContainerName[] = L"my_key_name"; WCHAR szReaderName[] = L""; WCHAR szCspName[] = L"My Key Storage Provider"; WCHAR szPin[] = L"11111111"; ULONG ulPinByteLen = wcslen(szPin) * sizeof(WCHAR); WCHAR szUserName[] = L"user"; ULONG ulUserByteLen = wcslen(szUserName) * sizeof(WCHAR); WCHAR szDomainName[] = L"testdomain.com"; ULONG ulDomainByteLen = 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 = 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-pbAuthInfo); pKerbCertLogon->UserName.Length = (USHORT)ulUserByteLen; pKerbCertLogon->UserName.MaximumLength = (USHORT)(ulUserByteLen + sizeof(WCHAR)); pKerbCertLogon->UserName.Buffer = (PWSTR)(pbUserBuffer-pbAuthInfo); pKerbCertLogon->Pin.Length = (USHORT)ulPinByteLen; pKerbCertLogon->Pin.MaximumLength = (USHORT)(ulPinByteLen + sizeof(WCHAR)); pKerbCertLogon->Pin.Buffer = (PWSTR)(pbPinBuffer-pbAuthInfo); pKerbCertLogon->CspDataLength = ulCspDataLen; pKerbCertLogon->CspData = (PUCHAR)(pbCspData-pbAuthInfo); pKerbCspInfo = (KERB_SMARTCARD_CSP_INFO*)pbCspData; pKerbCspInfo->dwCspInfoLen = ulCspDataLen; pKerbCspInfo->MessageType = 1; pKerbCspInfo->KeySpec = CERT_NCRYPT_KEY_SPEC; pKerbCspInfo->nCardNameOffset = 0; pKerbCspInfo->nReaderNameOffset = pKerbCspInfo->nCardNameOffset + wcslen(szCardName) + 1; pKerbCspInfo->nContainerNameOffset = pKerbCspInfo->nReaderNameOffset + wcslen(szReaderName) + 1; pKerbCspInfo->nCSPNameOffset = pKerbCspInfo->nContainerNameOffset + 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)); *ppbAuthInfo = pbAuthInfo; *pulAuthInfoLen = ulAuthInfoLen; } 

    В этом коде есть две основные вещи:

    1. Для взаимодействия с KSP, pKerbCspInfo-> KeySpec должен быть CERT_NCRYPT_KEY_SPEC.
    2. Для правильной сериализации структуры в соответствии с этим ответом:

      pKerbCertLogon-> DomainName.Buffer = (PWSTR) (pbDomainBuffer-pbAuthInfo); pKerbCertLogon-> UserName.Buffer = (PWSTR) (pbUserBuffer-pbAuthInfo); pKerbCertLogon-> Pin.Buffer = (PWSTR) (pbPinBuffer-pbAuthInfo); pKerbCertLogon-> CspData = (PUCHAR) (pbCspData-pbAuthInfo);

    Кроме того, controller домена должен выдавать сертификат с шаблоном аутентификации Kerberos.