2017-02-24 10 views
0

証明書を介してWindowsにログオンするために、資格プロバイダと鍵記憶プロバイダを作成しました。この点の文書は非常に曖昧であるため、Microsoftからさまざまなサンプルを使用して作業を進めました。NCRYPT_KEY_HANDLEによって指し示される証明書の構造

私はほとんどそこにいると思いますが、ログオンは予期せず動作します。時にはケルベロスサーバー(証明書について不平を言う)に行き着くこともあります。時にはプロセスが0x80090029で失敗し、情報がなく、ときどきウィンドウがクラッシュすることがあります。これらのクラッシュはすべてアクセス違反やヌルポインタと関係しており、さまざまな場所で発生します(kerberos.dll、Windows.UI.Logon.dll、...)私はそれが私のキー構造と関係があると思います指定されたNCRYT_KEY_HANDLEをOpenKey実装にポイントします。

CNG-KitのKeyStorageProviderSampleには例がありますが、%AppData%に格納されているRSAキーに依存しています。

SECURITY_STATUS WINAPI KeyHandler::ReadPemCert(__inout KSP_KEY *keyHandle) 
{ 
    LOG_FUNCTION; 

    CERT_CONTEXT certContext = {}; 
    DWORD readLength = 0; 

    LOG("Fetch certificate"); 
    const int maxSizeInBytes = 4096; 
    char pemCertificateAsBytes[maxSizeInBytes]; 
    BluetoothClient bluetoothClient = BluetoothClient(); 
    bluetoothClient.getCertificate((PBYTE)pemCertificateAsBytes, readLength); 

    DWORD certAsDerLen = readLength; 
    BYTE* certAsDer = new BYTE[certAsDerLen]; 
    LOG("convert PEM to DER"); 
    if (!CryptStringToBinaryA(pemCertificateAsBytes, 0, CRYPT_STRING_BASE64, certAsDer, &certAsDerLen, NULL, NULL)) 
    { 
     LOG_LAST_ERROR("CryptStringToBinary failed. Err:"); 
    } 
    LOG_BYTES_AS_HEX("DER-Zertifikat", certAsDer, certAsDerLen); 

    PCCERT_CONTEXT pcCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, certAsDer, certAsDerLen); 
    certContext->pCertInfo = pcCertContext->pCertInfo; 
    certContext->cbCertEncoded = pcCertContext->cbCertEncoded; 
    certContext->pbCertEncoded = pcCertContext->pbCertEncoded; 
    certContext->dwCertEncodingType = pcCertContext->dwCertEncodingType; 

    CERT_INFO *certInfo; 
    certInfo = certContext.pCertInfo; 

    CERT_PUBLIC_KEY_INFO pubKeyInfo = certInfo->SubjectPublicKeyInfo; 

    LOG("Aquire cryptocontext"); 
    HCRYPTPROV hProv = 0; 
    if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) 
    { 
     { 
      LOG_LAST_ERROR("CryptAcquireContext failed. Err:"); 
      return -1; 
     } 
    } 

    LOG("Importing public key"); 
    NCRYPT_KEY_HANDLE publicKeyHandle = NULL; 
    if (!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING, &pubKeyInfo, &publicKeyHandle)) 
    { 
     LOG_LAST_ERROR("CryptImportPublicKeyInfo failed. Err:"); 
     return -1; 
    } 

    keyHandle->fFinished = TRUE; 
    keyHandle->hPublicKey = (BCRYPT_KEY_HANDLE)publicKeyHandle; 
    keyHandle->pszKeyBlobType = BCRYPT_RSAPUBLIC_BLOB; 

    LocalFree(certInfo); 

    return ERROR_SUCCESS; 
} 

:それは安全なハードウェアに保存されているように私は、私は次のコードを介して他の装置とインポートから読み取ること、私はちょうど公開部分(すなわちパブリック証明書)を持って、可能な秘密鍵を持っていませんキー構造は次のように初期化されます。

SECURITY_STATUS 
WINAPI 
KeyHandler::CreateNewKeyObject(
    __in_opt LPCWSTR pszKeyName, 
    __deref_out KSP_KEY **ppKey) 
{ 
    LOG_FUNCTION; 

    KSP_KEY *pKey = NULL; 
    DWORD cbKeyName = 0; 
    SECURITY_STATUS Status = NTE_INTERNAL_ERROR; 
    NTSTATUS   ntStatus = STATUS_INTERNAL_ERROR; 

    pKey = (KSP_KEY *)HeapAlloc(GetProcessHeap(), 0, sizeof(KSP_KEY)); 
    if (pKey == NULL) 
    { 
     return NTE_NO_MEMORY; 
    } 
    pKey->cbLength = sizeof(KSP_KEY); 
    pKey->dwMagic = KSP_KEY_MAGIC; 
    pKey->dwAlgID = KSP_RSA_ALGID; 
    pKey->pszKeyFilePath = NULL; 
    pKey->pszKeyBlobType = NULL; 
    pKey->dwKeyBitLength = 0; 
    pKey->fFinished = FALSE; 

    //Copy the keyname into the key struct. 
    if (pszKeyName != NULL) 
    { 
     cbKeyName = (DWORD)(wcslen(pszKeyName) + 1) * sizeof(WCHAR); 
     pKey->pszKeyName = (LPWSTR)HeapAlloc(
      GetProcessHeap(), 
      0, 
      cbKeyName + sizeof(WCHAR)); 
     if (pKey->pszKeyName == NULL) 
     { 
      return NTE_NO_MEMORY; 
     } 
     CopyMemory(pKey->pszKeyName, pszKeyName, cbKeyName); 
     pKey->pszKeyName[cbKeyName/sizeof(WCHAR)] = L'\0'; 
    } 
    else 
    { 
     pKey->pszKeyName = NULL; 
    } 

    if (globalRSAProviderHandle == NULL) 
    { 
     ntStatus = BCryptOpenAlgorithmProvider(
      &globalRSAProviderHandle, 
      BCRYPT_RSA_ALGORITHM, 
      NULL, 
      0); 
     if (!NT_SUCCESS(ntStatus)) 
     { 
      return NormalizeNteStatus(ntStatus); 
     } 

    } 
    pKey->hProvider = globalRSAProviderHandle; 

    pKey->pbKeyFile = NULL; 
    pKey->cbKeyFile = 0; 

    pKey->pbPrivateKey = NULL; 
    pKey->cbPrivateKey = 0; 

    pKey->hPublicKey = NULL; 
    pKey->hPrivateKey = NULL; 

    pKey->dwExportPolicy = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG; 

    pKey->dwKeyUsagePolicy = NCRYPT_ALLOW_DECRYPT_FLAG | NCRYPT_ALLOW_SIGNING_FLAG; 

    pKey->pbSecurityDescr = NULL; 
    pKey->cbSecurityDescr = 0; 

    InitializeListHead(&pKey->PropertyList); 
    *ppKey = pKey; 
    pKey = NULL; 
    return ERROR_SUCCESS; 
} 

さまざまなメモリエラーにつながる間違いがあります。しかし、私はWindowsプログラミングとC/C++の新機能として、ポイントを見つけることができず、WindowsがNCRYTP_KEY_HANDLEに期待するデータ構造に関するドキュメントを見つけることができません。 誰でもこの構造についてもっと知っていますか?

+0

私はこの質問の深さのために、Stack Exchangeネットワークの別のサイトに属していると思います。https://crypto.stackexchange.com –

答えて

1

NCRYPT_KEY_HANDLEは、定義した構造体へのポインタに過ぎません。 Windows自体はこの構造を気にせず、プロバイダがその構造をどのように扱うかを知っていることを期待しています。

KeyHandler::ReadPemCertには、従来のCryptoAPIとCNG APIが混在していました。 KSPを実装しているので、CNG API(CryptImportPublicKeyInfoEx2)のみを使用してください。

DWORD error = NTE_FAIL; 
BCRYPT_KEY_HANDLE hKey = NULL; 

... 

PCCERT_CONTEXT pcCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, certAsDer, certAsDerLen); 
if(!pcCertContext) 
{ 
    goto Exit; 
} 


if (!CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, &pcCertContext->pCertInfo->SubjectPublicKeyInfo, 0, nullptr, &hKey)) 
{ 
    goto Exit; 
} 

/* Also you can export key and print out the result to make sure everything works 

    DWORD temp = 0; 
    status = BCryptExportKey(hKey, 0, BCRYPT_RSAPUBLIC_BLOB, nullptr, 0, &temp, 0); 
    if (status != ERROR_SUCCESS) 
    { 
     goto Exit; 
    } 

    std::vector<BYTE> key(temp); 
    status = BCryptExportKey(hKey, 0, BCRYPT_RSAPUBLIC_BLOB, key.data(), key.size(), &temp, 0); 
    if (status != ERROR_SUCCESS) 
    { 
     goto Exit; 
    } 

    for (auto const& i : key) 
    { 
     std::cout << std::hex << (int)i; 
    } 
} 
*/ 

keyHandle->fFinished = TRUE; 
keyHandle->hPublicKey = hKey; 
keyHandle->pszKeyBlobType = BCRYPT_RSAPUBLIC_BLOB; 

erro = ERROR_SUCCESS; 

Exit: 

if(pcCertContext) 
{ 
    CertFreeCertificateContext(pcCertContext); 
} 

return error; 
関連する問題