Hi,
I'll start off by explaining how the Cryptographic Service Providers are stored in the registry. A lot of advapi32 CSP functions can accept a provider name sent in to use that provider, or advapi32 can use the default provider which is located in the registry at:
HKLM\Software\Microsoft\Cryptography\Defaults\
Listed under the Provider\ key are the keys of the different providers available on the computer. Each provider has a non-unique provider type associated with it, and several providers may be of the same provider type. These types are listed under the 'Provider Types' key which is itself under 'Defaults'. The keynames are of the form 'Type XXX' where XXX is the numeric value of the type. These keys under 'Provider Types' assign the default provider that is to be used for each type. The 'Name' value associates each type with the corresponding provider default that is used with this type. It is essential that the 'TypeName' registry of each provider type remain in the registry, because it is only inserted once when the dll is registered. It is acceptable if the 'Name' value is removed, and this should happen when CryptSetProviderEx is called with the CRYPT_DELETEDEFAULT flag.
This is the code that handles the CRYPT_DELETEFLAG in the current implementation of CryptSetProviderExA:
if (dwFlags & CRYPT_DELETE_DEFAULT) { if ( !(keyname = CRYPT_GetTypeKeyName(dwProvType, dwFlags & CRYPT_USER_DEFAULT)) ) CRYPT_ReturnLastError(ERROR_NOT_ENOUGH_MEMORY); RegDeleteKeyA( (dwFlags & CRYPT_USER_DEFAULT) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, keyname); CRYPT_Free(keyname); return TRUE; }
The important line to look as is the RegDeleteKeyA call. This call removes the entire 'Type XXX' key from the registry. The next time a call is made to CryptSetProviderEx to set the default provider and not remove it, the call will fail because of the next line:
if ( !(keyname = CRYPT_GetTypeKeyName(dwProvType, dwFlags & CRYPT_USER_DEFAULT)) )
CRYPT_GetTypeKeyName uses the dwProvType parameter to search the registry for the particular 'Type XXX' key that matches the provider type, but this call fails because when we last called CryptSetProviderExA with the CRYPT_DELETEDEFAULT flag, the entire 'Type XXX' key was removed.
The proper fix for this, and the way windows handles it, is to just remove the 'Name' value from the 'Type XXX' key if the CRYPT_DELETEDEFAULT flag is sent in. This way the required 'TypeName' will never be removed, and the next call can set the default provider.
If you would like to look at the already patched version, I'll attach it along with the patch. Thankyou for taking the time to look this over. If there are problems with the patch, please let me know so we can get this committed.