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.
--
James Hawkins