views:

77

answers:

1

On some systems running Windows 7 where we've generated a key in a name key container, if we change the user's password, when we call CryptAcquireCertificatePrivateKey() we get an error CRYPT_E_NO_KEY_PROPERTY (0x8009200B).

This doesn't happen on all boxes. We orginally thought it was something to w/ a domain machine not on the network and there it couldn't refresh it domain stuff, but we got it to reproduce on some standalone machines.

My code for reading the key

if((StoreHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, QWARQ_CERT_STORE_NAME)) != NULL)
     {
        /* Look for certificate with matching user guid.            */
        if((CertContext = CertFindCertificateInStore(StoreHandle,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR,DataBuffer, NULL)) != NULL)
        {
           if(CryptAcquireCertificatePrivateKey(CertContext, 0,NULL, &CryptProvHandle, &KeySpec, &FreeHandle))
           {
           }
           else
           {
                   DWORD dwError=GetLastError();   //CRYPT_E_NO_KEY_PROPERTY
           }
        }
     }

here is code that generates the key/key container

if(CryptAcquireContext(&hCryptProv,KEY_CONTAINER_NAME, NULL,PROV_RSA_FULL, 0) == FALSE) //CRYPT_NEWKEYSET
{
    DWORD result = GetLastError();
    if (NTE_BAD_KEY_STATE  == result)
    {
        DebugLogging::DbgPrintF(TEXT("[CertInitialization] NTE_BAD_KEY_STATE - user has changed his password \n"), result);
        return false;
    }
    else if (NTE_BAD_KEYSET != result)
    {
        DebugLogging::DbgPrintF(TEXT("[CertInitialization] could not acquire CSP[0x%x]\n"), result);
        return false;
    }

    if(CryptAcquireContext(&hCryptProv, KEY_CONTAINER_NAME, NULL,PROV_RSA_FULL, CRYPT_NEWKEYSET) == FALSE) //CRYPT_NEWKEYSET
    {
        DWORD result = GetLastError();
        DebugLogging::DbgPrintF(TEXT("[CertInitialization] could not acquire CSP from new keyset[0x%x]\n"), result);
        return false;
    }
}
if(CryptGenKey(hCryptProv, AT_KEYEXCHANGE, RSA2048BIT_KEY |CRYPT_EXPORTABLE, &hKey)== FALSE)
{
    DebugLogging::DbgPrintF(TEXT("CertGeneration() could not generate key[%d]\n"),GetLastError());
    return false;
} 
A: 

After learning more about DPAPI

Password Change

In this method, there is continuity of access to the user's master keys during a password change. The DPAPI is invoked by the Winlogon component during password change operations in an Active Directory domain:

* DPAPI receives notification from Winlogon during a password change operation.
* DPAPI decrypts all master keys that were encrypted with the user's old passwords.
* DPAPI re-encrypts all master keys with the user's new password.

Password Reset (Set)

In this method, an administrator forcibly resets a user password. A password reset is more complex than a password change. Because the administrator is not logged on as the user and does not have access to the user's old password, that old password cannot be used to decrypt the old master key and re-encrypt it with the new password.

SonicBison