2017-01-26 9 views
0

こんにちは私は、資格情報としてユーザー名/パスワードを使用するときにうまく動作するカスタムcredentialproviderを書いています。パスワードはbluetooth経由で転送されます。 ドキュメンテーションが実装するインタフェースを教えてくれるほど難しいことではありませんでした。KERB_CERTIFICATE_LOGONに接続するためのKSPの書き方

ここで、代わりに証明書を使用するように資格情報を変更したいとします。私はこのためにKERB_CERTIFICATE_LOGON構造体を使うべきであることを知っています。私は、this article by microsoftで説明されているように、カスタムキーストレージプロバイダを実装する必要があることを発見しました。そして、それが私が失われたポイントです。おそらく私は正しい文書を検索するのは馬鹿ですが、KERB_CERTIFICATE_LOGON構造体のCspDataフィールドで参照できるKSPを実装するために実装する必要のあるインタフェースを見つけることができません。私はちょうど多くの方法とNCRYPT_CERTIFICATE_PROPERTY(上のリンクされた記事で言及)の迅速な検索2つのグーグルの結果を明らかにした。

資格取得者とKSPの接続に役立つthis SO-questionが見つかりましたが、KSPの書き方については説明していません。 :-(

誰もが情報を見つけるか、KSPの短いサンプルは同様のシナリオ(ちょうどメソッド宣言、そしてどのようKERB_CERTIFICATE_LOGONへの呼び出しで結果KSPを使用する)で使用されるショーに私を導くことはできますか?

答えて

2

このMicrosoft Cryptographic Provider Development Kitは、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はそれと対話することができます

  1. 、pKerbCspInfo-> KeySpec KSPとの相互作用について:このコードでは二つの主要なものがあります

    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; 
    } 
    

    CERT_NCRYPT_KEY_SPECである必要があります。 this答えに応じて適切な構造をシリアル化

  2. 、:

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

また、ドメインコントローラは、「Kerberos認証」テンプレートで証明書を発行する必要があります。

+0

ありがとうございました!それまでの間、私はCNG-Kitのサンプルを見つけました。しかし、私はそれを働かせることができませんでした。あなたがアドバイスしたように、KeySpecをCERT_NCRYPT_KEY_SPECに変えることはそのトリックを行いました。 – Frank

+0

もう1つ質問:プロバイダーをC++に移植することは可能ですか?私はそれを試して、KSPの登録がうまくいきます。しかし、C++ - バージョンはログオンプロセスで呼び出されないようです。私はそれがGetKeyStorageInterfaceのエクスポートと関係があると思いますが、私はそれを動作させるために何を変更しなければならないのか分かりません。 – Frank

+0

@Frank私はCやC++の使用に違いがあるとは思わない。何がうまくいかない?他のシナリオではC++プロバイダが動作しますか?例:NCryptOpenStorageProvider(...); NCryptOpenKey(...); – plstryagain

関連する問題