You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1592 lines
35 KiB
1592 lines
35 KiB
/*++
|
|
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
key.c
|
|
|
|
Abstract:
|
|
|
|
Key manpulators for the IIS cryptographic package.
|
|
|
|
The following routines are exported by this module:
|
|
|
|
IISCryptoGetKeyDeriveKey
|
|
IISCryptoGetKeyExchangeKey
|
|
IISCryptoGetSignatureKey
|
|
IISCryptoGenerateSessionKey
|
|
IISCryptoCloseKey
|
|
IISCryptoExportSessionKeyBlob
|
|
IISCryptoExportSessionKeyBlob2
|
|
IISCryptoImportSessionKeyBlob
|
|
IISCryptoImportSessionKeyBlob2
|
|
IISCryptoExportPublicKeyBlob
|
|
IISCryptoImportPublicKeyBlob
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 02-Dec-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
//
|
|
// Private constants.
|
|
//
|
|
|
|
|
|
//
|
|
// Private types.
|
|
//
|
|
|
|
|
|
//
|
|
// Private globals.
|
|
//
|
|
|
|
|
|
//
|
|
// Private prototypes.
|
|
//
|
|
|
|
HRESULT
|
|
IcpGetKeyHelper(
|
|
OUT HCRYPTKEY * phKey,
|
|
IN HCRYPTPROV hProv,
|
|
IN DWORD dwKeySpec
|
|
);
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoGetKeyDeriveKey2(
|
|
OUT HCRYPTKEY * phKey,
|
|
IN HCRYPTPROV hProv,
|
|
IN HCRYPTHASH hHash
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to derive a key from a password in the given
|
|
provider.
|
|
|
|
Arguments:
|
|
|
|
phKey - Receives the key handle if successful.
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
hHash - A hash object from which the key will be derived
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( phKey != NULL );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
DBG_ASSERT( hHash != CRYPT_NULL );
|
|
|
|
//
|
|
// Short-circuit if cryptography is disabled.
|
|
//
|
|
|
|
if( !IcpGlobals.EnableCryptography ) {
|
|
if( hProv == DUMMY_HPROV )
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a key based on the hash of the password.
|
|
//
|
|
IcpAcquireGlobalLock();
|
|
|
|
if( !CryptDeriveKey(
|
|
hProv,
|
|
CALG_RC4,
|
|
hHash,
|
|
CRYPT_EXPORTABLE,
|
|
phKey ) )
|
|
{
|
|
hr = IcpGetLastError();
|
|
IcpReleaseGlobalLock();
|
|
DBG_ASSERT( FAILED( hr ) );
|
|
return hr;
|
|
}
|
|
|
|
IcpReleaseGlobalLock();
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoGetKeyExchangeKey(
|
|
OUT HCRYPTKEY * phKey,
|
|
IN HCRYPTPROV hProv
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to open the key exchange key in the given
|
|
provider. If the key does not yet exist, this routine will attempt
|
|
to create it.
|
|
|
|
Arguments:
|
|
|
|
phKey - Receives the key handle if successful.
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HRESULT result;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( phKey != NULL );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
|
|
//
|
|
// Let IcpGetKeyHelper() do the dirty work.
|
|
//
|
|
|
|
result = IcpGetKeyHelper(
|
|
phKey,
|
|
hProv,
|
|
AT_KEYEXCHANGE
|
|
);
|
|
|
|
return result;
|
|
|
|
} // IISCryptoGetKeyExchangeKey
|
|
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoGetSignatureKey(
|
|
OUT HCRYPTKEY * phKey,
|
|
IN HCRYPTPROV hProv
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to open the signature key in the given provider.
|
|
If the key does not yet exist, this routine will attempt to create it.
|
|
|
|
Arguments:
|
|
|
|
phKey - Receives the key handle if successful.
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HRESULT result;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( phKey != NULL );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
|
|
//
|
|
// Let IcpGetKeyHelper() do the dirty work.
|
|
//
|
|
|
|
result = IcpGetKeyHelper(
|
|
phKey,
|
|
hProv,
|
|
AT_SIGNATURE
|
|
);
|
|
|
|
return result;
|
|
|
|
} // IISCryptoGetSignatureKey
|
|
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoGenerateSessionKey(
|
|
OUT HCRYPTKEY * phKey,
|
|
IN HCRYPTPROV hProv
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine generates a random session key.
|
|
|
|
Arguments:
|
|
|
|
phKey - Receives the key handle if successful.
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
HRESULT result = NO_ERROR;
|
|
BOOL status;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( phKey != NULL );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
|
|
//
|
|
// Short-circuit if cryptography is disabled.
|
|
//
|
|
|
|
if( !IcpGlobals.EnableCryptography ) {
|
|
if( hProv == DUMMY_HPROV ) {
|
|
*phKey = DUMMY_HSESSIONKEY;
|
|
return NO_ERROR;
|
|
} else {
|
|
return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Generate the key.
|
|
//
|
|
|
|
status = CryptGenKey(
|
|
hProv,
|
|
CALG_RC4,
|
|
CRYPT_EXPORTABLE,
|
|
phKey
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
}
|
|
|
|
if( SUCCEEDED(result) )
|
|
{
|
|
UpdateKeysOpened();
|
|
}
|
|
else
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoGenerateSessionKey.CryptGenKey (advapi32.dll) failed err=0x%x.\n",result));
|
|
*phKey = CRYPT_NULL;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
} // IISCryptoGenerateSessionKey
|
|
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoCloseKey(
|
|
IN HCRYPTKEY hKey
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine closes the specified key.
|
|
|
|
Arguments:
|
|
|
|
hKey - A key handle.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOL status;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( hKey != CRYPT_NULL );
|
|
|
|
//
|
|
// Short-circuit if cryptography is disabled.
|
|
//
|
|
|
|
if( !IcpGlobals.EnableCryptography ) {
|
|
if( hKey == DUMMY_HSESSIONKEY ||
|
|
hKey == DUMMY_HSIGNATUREKEY ||
|
|
hKey == DUMMY_HKEYEXCHANGEKEY ) {
|
|
return NO_ERROR;
|
|
} else {
|
|
return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close the key.
|
|
//
|
|
|
|
status = CryptDestroyKey(
|
|
hKey
|
|
);
|
|
|
|
if( status ) {
|
|
UpdateKeysClosed();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
return IcpGetLastError();
|
|
|
|
} // IISCryptoCloseKey
|
|
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoExportSessionKeyBlob(
|
|
OUT PIIS_CRYPTO_BLOB * ppSessionKeyBlob,
|
|
IN HCRYPTPROV hProv,
|
|
IN HCRYPTKEY hSessionKey,
|
|
IN HCRYPTKEY hKeyExchangeKey
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine exports a session key into a secure session key blob.
|
|
The blob contains the session key (encrypted with the specified
|
|
private key exchange key) and a digital signature (also encrypted).
|
|
|
|
Arguments:
|
|
|
|
ppSessionKeyBlob - Will receive a pointer to the newly created
|
|
session key blob if successful.
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
hSessionKey - The key to export.
|
|
|
|
hKeyExchangeKey - The key to use when encrypting the session key.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HRESULT result = NO_ERROR;
|
|
BOOL status;
|
|
HCRYPTHASH hash;
|
|
DWORD keyLength;
|
|
DWORD hashLength;
|
|
PIC_BLOB blob;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( ppSessionKeyBlob != NULL );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
DBG_ASSERT( hSessionKey != CRYPT_NULL );
|
|
DBG_ASSERT( hKeyExchangeKey != CRYPT_NULL );
|
|
|
|
//
|
|
// Short-circuit if cryptography is disabled.
|
|
//
|
|
|
|
if( !IcpGlobals.EnableCryptography ) {
|
|
if( hProv == DUMMY_HPROV &&
|
|
hSessionKey == DUMMY_HSESSIONKEY &&
|
|
hKeyExchangeKey == DUMMY_HKEYEXCHANGEKEY ) {
|
|
|
|
return IISCryptoCreateCleartextBlob(
|
|
ppSessionKeyBlob,
|
|
(PVOID)"",
|
|
1
|
|
);
|
|
|
|
} else {
|
|
return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Setup our locals so we know how to cleanup on exit.
|
|
//
|
|
|
|
blob = NULL;
|
|
hash = CRYPT_NULL;
|
|
|
|
//
|
|
// Determine the required size of the key data.
|
|
//
|
|
|
|
status = CryptExportKey(
|
|
hSessionKey,
|
|
hKeyExchangeKey,
|
|
SIMPLEBLOB,
|
|
0,
|
|
NULL,
|
|
&keyLength
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.CryptExportKey (advapi32.dll) failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Determine the hash data length.
|
|
//
|
|
|
|
result = IcpGetHashLength(
|
|
&hashLength,
|
|
hProv
|
|
);
|
|
|
|
if( FAILED(result) ) {
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.IcpGetHashLength failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Create a new blob.
|
|
//
|
|
|
|
blob = IcpCreateBlob(
|
|
KEY_BLOB_SIGNATURE,
|
|
keyLength,
|
|
hashLength
|
|
);
|
|
|
|
if( blob == NULL ) {
|
|
result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Export the key.
|
|
//
|
|
|
|
status = CryptExportKey(
|
|
hSessionKey,
|
|
hKeyExchangeKey,
|
|
SIMPLEBLOB,
|
|
0,
|
|
BLOB_TO_DATA(blob),
|
|
&keyLength
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.CryptExportKey failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
DBG_ASSERT( keyLength == blob->DataLength );
|
|
|
|
//
|
|
// Create a hash object.
|
|
//
|
|
|
|
result = IISCryptoCreateHash(
|
|
&hash,
|
|
hProv
|
|
);
|
|
|
|
if( FAILED(result) ) {
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.IISCryptoCreateHash failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Hash the key and generate the signature.
|
|
//
|
|
|
|
status = CryptHashData(
|
|
hash,
|
|
BLOB_TO_DATA(blob),
|
|
keyLength,
|
|
0
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.CryptHashData failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
status = CryptSignHash(
|
|
hash,
|
|
AT_SIGNATURE,
|
|
NULL,
|
|
0,
|
|
BLOB_TO_SIGNATURE(blob),
|
|
&hashLength
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.CryptSignHash failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
DBG_ASSERT( hashLength == blob->SignatureLength );
|
|
|
|
//
|
|
// Success!
|
|
//
|
|
|
|
DBG_ASSERT( IISCryptoIsValidBlob( (PIIS_CRYPTO_BLOB)blob ) );
|
|
DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
|
|
*ppSessionKeyBlob = (PIIS_CRYPTO_BLOB)blob;
|
|
|
|
UpdateBlobsCreated();
|
|
return NO_ERROR;
|
|
|
|
fatal:
|
|
|
|
if( hash != CRYPT_NULL ) {
|
|
DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
|
|
}
|
|
|
|
if( blob != NULL ) {
|
|
IcpFreeMemory( blob );
|
|
}
|
|
|
|
DBG_ASSERT( FAILED(result) );
|
|
return result;
|
|
|
|
} // IISCryptoExportSessionKeyBlob
|
|
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoImportSessionKeyBlob(
|
|
OUT HCRYPTKEY * phSessionKey,
|
|
IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
|
|
IN HCRYPTPROV hProv,
|
|
IN HCRYPTKEY hSignatureKey
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes the specified session key blob and creates the
|
|
corresponding session key, iff the encrypted session key can be
|
|
decrypted and the digital signature can be validated.
|
|
|
|
Arguments:
|
|
|
|
phSessionKey - Receives a pointer to the newly created session key
|
|
if successful.
|
|
|
|
pSessionKeyBlob - Pointer to a key blob created with
|
|
IISCryptoExportSessionKeyBlob().
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
hSignatureKey - Handle to the encryption key to use when validating
|
|
the digital signature.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HRESULT result = NO_ERROR;
|
|
BOOL status;
|
|
HCRYPTHASH hash;
|
|
PIC_BLOB blob;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( phSessionKey != NULL );
|
|
DBG_ASSERT( pSessionKeyBlob != NULL );
|
|
DBG_ASSERT( IISCryptoIsValidBlob( pSessionKeyBlob ) );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
DBG_ASSERT( hSignatureKey != CRYPT_NULL );
|
|
|
|
//
|
|
// Short-circuit if cryptography is disabled.
|
|
//
|
|
|
|
if( !IcpGlobals.EnableCryptography ) {
|
|
if( hProv == DUMMY_HPROV &&
|
|
hSignatureKey == DUMMY_HSIGNATUREKEY &&
|
|
pSessionKeyBlob->BlobSignature == CLEARTEXT_BLOB_SIGNATURE
|
|
) {
|
|
|
|
*phSessionKey = DUMMY_HSESSIONKEY;
|
|
return NO_ERROR;
|
|
|
|
} else {
|
|
return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
DBG_ASSERT( pSessionKeyBlob->BlobSignature == KEY_BLOB_SIGNATURE );
|
|
|
|
//
|
|
// Setup our locals so we know how to cleanup on exit.
|
|
//
|
|
|
|
hash = CRYPT_NULL;
|
|
blob = (PIC_BLOB)pSessionKeyBlob;
|
|
|
|
//
|
|
// Validate the signature.
|
|
//
|
|
|
|
result = IISCryptoCreateHash(
|
|
&hash,
|
|
hProv
|
|
);
|
|
|
|
if( FAILED(result) ) {
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlob.IISCryptoCreateHash failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
status = CryptHashData(
|
|
hash,
|
|
BLOB_TO_DATA(blob),
|
|
blob->DataLength,
|
|
0
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlob.CryptHashData failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
status = CryptVerifySignature(
|
|
hash,
|
|
BLOB_TO_SIGNATURE(blob),
|
|
blob->SignatureLength,
|
|
hSignatureKey,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlob.CryptVerifySignature failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// OK, the signature looks good. Import the key into our CSP.
|
|
//
|
|
|
|
status = CryptImportKey(
|
|
hProv,
|
|
BLOB_TO_DATA(blob),
|
|
blob->DataLength,
|
|
CRYPT_NULL,
|
|
0,
|
|
phSessionKey
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlob.CryptImportKey failed err=0x%x.\n",result));
|
|
}
|
|
|
|
if( FAILED(result) ) {
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Success!
|
|
//
|
|
|
|
DBG_ASSERT( *phSessionKey != CRYPT_NULL );
|
|
DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
|
|
|
|
UpdateKeysOpened();
|
|
return NO_ERROR;
|
|
|
|
fatal:
|
|
|
|
if( hash != CRYPT_NULL ) {
|
|
DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
|
|
}
|
|
|
|
DBG_ASSERT( FAILED(result) );
|
|
return result;
|
|
|
|
} // IISCryptoImportSessionKeyBlob
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoExportSessionKeyBlob2(
|
|
OUT PIIS_CRYPTO_BLOB * ppSessionKeyBlob,
|
|
IN HCRYPTPROV hProv,
|
|
IN HCRYPTKEY hSessionKey,
|
|
IN LPSTR pszPasswd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine exports a session key into a secure session key blob.
|
|
The blob contains the session key (encrypted with the specified
|
|
private key exchange key) and a digital signature (also encrypted).
|
|
|
|
Arguments:
|
|
|
|
ppSessionKeyBlob - Will receive a pointer to the newly created
|
|
session key blob if successful.
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
hSessionKey - The key to export.
|
|
|
|
pszPasswd - The password to use to encrypt the session key.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HRESULT result = NO_ERROR;
|
|
BOOL status;
|
|
BYTE salt[ RANDOM_SALT_LENGTH ];
|
|
HCRYPTHASH hash;
|
|
DWORD keyLength;
|
|
PIC_BLOB2 blob;
|
|
HCRYPTKEY hKeyDerivedKey = CRYPT_NULL;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( ppSessionKeyBlob != NULL );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
DBG_ASSERT( hSessionKey != CRYPT_NULL );
|
|
|
|
//
|
|
// Short-circuit if cryptography is disabled.
|
|
//
|
|
|
|
if( !IcpGlobals.EnableCryptography ) {
|
|
if( hProv == DUMMY_HPROV &&
|
|
hSessionKey == DUMMY_HSESSIONKEY ) {
|
|
|
|
return IISCryptoCreateCleartextBlob(
|
|
ppSessionKeyBlob,
|
|
(PVOID)"",
|
|
1
|
|
);
|
|
|
|
} else {
|
|
return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Setup our locals so we know how to cleanup on exit.
|
|
//
|
|
|
|
blob = NULL;
|
|
hash = CRYPT_NULL;
|
|
|
|
//
|
|
// Generate a random salt of at least 80 bits
|
|
//
|
|
|
|
if( !CryptGenRandom( hProv, RANDOM_SALT_LENGTH, salt ) )
|
|
{
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.CryptGenRandom (advapi32.dll) failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Create a hash object.
|
|
//
|
|
|
|
result = IISCryptoCreateHash( &hash, hProv );
|
|
if( FAILED(result) )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.IISCryptoCreateHash failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Hash the random salt
|
|
|
|
if( !CryptHashData( hash, salt, RANDOM_SALT_LENGTH, 0 ) )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.CryptHashData failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Hash the password string
|
|
//
|
|
|
|
if( !CryptHashData( hash, ( BYTE * )pszPasswd, ( DWORD )strlen( pszPasswd ), 0 ) )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.CryptHashData failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Derive a key from the supplied passwd
|
|
//
|
|
result = IISCryptoGetKeyDeriveKey2( &hKeyDerivedKey,
|
|
hProv,
|
|
hash
|
|
);
|
|
if( FAILED( result ) )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.IISCryptoGetKeyDeriveKey2 failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Determine the required size of the key data.
|
|
//
|
|
|
|
status = CryptExportKey(
|
|
hSessionKey,
|
|
hKeyDerivedKey,
|
|
SYMMETRICWRAPKEYBLOB,
|
|
0,
|
|
NULL,
|
|
&keyLength
|
|
);
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.CryptExportKey (advapi32.dll) failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Create a new blob.
|
|
//
|
|
|
|
blob = IcpCreateBlob2(
|
|
SALT_BLOB_SIGNATURE,
|
|
keyLength,
|
|
RANDOM_SALT_LENGTH
|
|
);
|
|
|
|
if( blob == NULL ) {
|
|
result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Export the key.
|
|
//
|
|
|
|
status = CryptExportKey(
|
|
hSessionKey,
|
|
hKeyDerivedKey,
|
|
SYMMETRICWRAPKEYBLOB,
|
|
0,
|
|
BLOB_TO_DATA2(blob),
|
|
&keyLength
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.CryptExportKey failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
status = CryptDestroyKey( hKeyDerivedKey );
|
|
if( !status )
|
|
{
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.CryptDestroyKey (advapi32.dll) failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
DBG_ASSERT( keyLength == blob->DataLength );
|
|
|
|
memcpy( BLOB_TO_SALT2( blob ), salt, RANDOM_SALT_LENGTH );
|
|
|
|
//
|
|
// Success!
|
|
//
|
|
|
|
DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
|
|
*ppSessionKeyBlob = (PIIS_CRYPTO_BLOB)blob;
|
|
|
|
UpdateBlobsCreated();
|
|
|
|
|
|
return NO_ERROR;
|
|
|
|
fatal:
|
|
|
|
if( hash != CRYPT_NULL ) {
|
|
DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
|
|
}
|
|
|
|
if( blob != NULL ) {
|
|
IcpFreeMemory( blob );
|
|
}
|
|
|
|
DBG_ASSERT( FAILED(result) );
|
|
return result;
|
|
|
|
} // IISCryptoExportSessionKeyBlob2
|
|
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoImportSessionKeyBlob2(
|
|
OUT HCRYPTKEY * phSessionKey,
|
|
IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
|
|
IN HCRYPTPROV hProv,
|
|
IN LPSTR pszPasswd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes the specified session key blob and creates the
|
|
corresponding session key, iff the encrypted session key can be
|
|
decrypted and the digital signature can be validated.
|
|
|
|
Arguments:
|
|
|
|
phSessionKey - Receives a pointer to the newly created session key
|
|
if successful.
|
|
|
|
pSessionKeyBlob - Pointer to a key blob created with
|
|
IISCryptoExportSessionKeyBlob().
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
pszPasswd - The password to use to encrypt the session key.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HRESULT result = NO_ERROR;
|
|
BOOL status;
|
|
BYTE salt[ RANDOM_SALT_LENGTH ];
|
|
HCRYPTKEY hKeyDerivedKey;
|
|
HCRYPTHASH hash;
|
|
PIC_BLOB2 blob;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( phSessionKey != NULL );
|
|
DBG_ASSERT( pSessionKeyBlob != NULL );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
DBG_ASSERT( pszPasswd != NULL );
|
|
|
|
//
|
|
// Short-circuit if cryptography is disabled.
|
|
//
|
|
|
|
if( !IcpGlobals.EnableCryptography ) {
|
|
if( hProv == DUMMY_HPROV &&
|
|
pSessionKeyBlob->BlobSignature == CLEARTEXT_BLOB_SIGNATURE
|
|
) {
|
|
|
|
*phSessionKey = DUMMY_HSESSIONKEY;
|
|
return NO_ERROR;
|
|
|
|
} else {
|
|
return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
DBG_ASSERT( pSessionKeyBlob->BlobSignature == SALT_BLOB_SIGNATURE );
|
|
|
|
//
|
|
// Setup our locals so we know how to cleanup on exit.
|
|
//
|
|
|
|
hash = CRYPT_NULL;
|
|
blob = (PIC_BLOB2)pSessionKeyBlob;
|
|
|
|
//
|
|
// Get the random salt
|
|
//
|
|
|
|
memcpy( salt, BLOB_TO_SALT2( blob ), RANDOM_SALT_LENGTH );
|
|
|
|
//
|
|
// Create a hash object.
|
|
//
|
|
|
|
result = IISCryptoCreateHash( &hash, hProv );
|
|
if( FAILED(result) )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlobWithPasswd.IISCryptoCreateHash failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Hash the random salt
|
|
|
|
if( !CryptHashData( hash, salt, RANDOM_SALT_LENGTH, 0 ) )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlobWithPasswd.CryptHashData failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Hash the password string
|
|
//
|
|
|
|
if( !CryptHashData( hash, ( BYTE * )pszPasswd, ( DWORD )strlen( pszPasswd ), 0 ) )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlobWithPasswd.CryptHashData failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Derive a key from the supplied passwd
|
|
//
|
|
result = IISCryptoGetKeyDeriveKey2( &hKeyDerivedKey,
|
|
hProv,
|
|
hash
|
|
);
|
|
if( FAILED( result ) )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlobWithPasswd.IISCryptoGetKeyDeriveKey2 failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// OK, import the key into our CSP.
|
|
//
|
|
|
|
status = CryptImportKey(
|
|
hProv,
|
|
BLOB_TO_DATA2(blob),
|
|
blob->DataLength,
|
|
hKeyDerivedKey,
|
|
0,
|
|
phSessionKey
|
|
);
|
|
|
|
if( !status ) {
|
|
//result = IcpGetLastError();
|
|
result = HRESULT_FROM_WIN32( ERROR_WRONG_PASSWORD );
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlob.CryptImportKey failed err=0x%x.\n",result));
|
|
}
|
|
|
|
if( FAILED(result) ) {
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Success!
|
|
//
|
|
|
|
DBG_ASSERT( *phSessionKey != CRYPT_NULL );
|
|
DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
|
|
|
|
UpdateKeysOpened();
|
|
return NO_ERROR;
|
|
|
|
fatal:
|
|
|
|
if( hash != CRYPT_NULL ) {
|
|
DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
|
|
}
|
|
|
|
DBG_ASSERT( FAILED(result) );
|
|
return result;
|
|
|
|
} // IISCryptoImportSessionKeyBlob2
|
|
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoExportPublicKeyBlob(
|
|
OUT PIIS_CRYPTO_BLOB * ppPublicKeyBlob,
|
|
IN HCRYPTPROV hProv,
|
|
IN HCRYPTKEY hPublicKey
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine exports a key into a public key blob. Note that since
|
|
public keys are, well, public, then the data in the blob is neither
|
|
encrypted nor signed.
|
|
|
|
Arguments:
|
|
|
|
ppPublicKeyBlob - Will receive a pointer to the newly created public
|
|
key blob if successful.
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
hPublicKey - The public key to export. This should identify either a
|
|
key exchange key or a signature key.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HRESULT result = NO_ERROR;
|
|
BOOL status;
|
|
DWORD keyLength;
|
|
PIC_BLOB blob;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( ppPublicKeyBlob != NULL );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
DBG_ASSERT( hPublicKey != CRYPT_NULL );
|
|
|
|
//
|
|
// Short-circuit if cryptography is disabled.
|
|
//
|
|
|
|
if( !IcpGlobals.EnableCryptography ) {
|
|
if( hProv == DUMMY_HPROV &&
|
|
( hPublicKey == DUMMY_HKEYEXCHANGEKEY ||
|
|
hPublicKey == DUMMY_HSIGNATUREKEY ) ) {
|
|
|
|
return IISCryptoCreateCleartextBlob(
|
|
ppPublicKeyBlob,
|
|
(PVOID)&hPublicKey,
|
|
sizeof(hPublicKey)
|
|
);
|
|
|
|
} else {
|
|
return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Setup our locals so we know how to cleanup on exit.
|
|
//
|
|
|
|
blob = NULL;
|
|
|
|
//
|
|
// Determine the required size of the key data.
|
|
//
|
|
|
|
status = CryptExportKey(
|
|
hPublicKey,
|
|
CRYPT_NULL,
|
|
PUBLICKEYBLOB,
|
|
0,
|
|
NULL,
|
|
&keyLength
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportPublicKeyBlob.CryptExportKey failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Create a new blob.
|
|
//
|
|
|
|
blob = IcpCreateBlob(
|
|
PUBLIC_KEY_BLOB_SIGNATURE,
|
|
keyLength,
|
|
0
|
|
);
|
|
|
|
if( blob == NULL ) {
|
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Export the key.
|
|
//
|
|
|
|
status = CryptExportKey(
|
|
hPublicKey,
|
|
CRYPT_NULL,
|
|
PUBLICKEYBLOB,
|
|
0,
|
|
BLOB_TO_DATA(blob),
|
|
&keyLength
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportPublicKeyBlob.CryptExportKey failed err=0x%x.\n",result));
|
|
goto fatal;
|
|
}
|
|
|
|
DBG_ASSERT( keyLength == blob->DataLength );
|
|
|
|
//
|
|
// Success!
|
|
//
|
|
|
|
DBG_ASSERT( IISCryptoIsValidBlob( (PIIS_CRYPTO_BLOB)blob ) );
|
|
*ppPublicKeyBlob = (PIIS_CRYPTO_BLOB)blob;
|
|
|
|
UpdateBlobsCreated();
|
|
return NO_ERROR;
|
|
|
|
fatal:
|
|
|
|
if( blob != NULL ) {
|
|
IcpFreeMemory( blob );
|
|
}
|
|
|
|
DBG_ASSERT( FAILED(result) );
|
|
return result;
|
|
|
|
} // IISCryptoExportPublicKeyBlob
|
|
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IISCryptoImportPublicKeyBlob(
|
|
OUT HCRYPTKEY * phPublicKey,
|
|
IN PIIS_CRYPTO_BLOB pPublicKeyBlob,
|
|
IN HCRYPTPROV hProv
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes the specified public key blob and creates the
|
|
corresponding key.
|
|
|
|
Arguments:
|
|
|
|
phPublicKey - Receives a pointer to the newly created public key if
|
|
successful.
|
|
|
|
pPublicKeyBlob - Pointer to a public key blob created with
|
|
IISCryptoExportPublicKeyBlob().
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HRESULT result = NO_ERROR;
|
|
BOOL status;
|
|
PIC_BLOB blob;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( phPublicKey != NULL );
|
|
DBG_ASSERT( pPublicKeyBlob != NULL );
|
|
DBG_ASSERT( IISCryptoIsValidBlob( pPublicKeyBlob ) );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
|
|
//
|
|
// Short-circuit if cryptography is disabled.
|
|
//
|
|
|
|
if( !IcpGlobals.EnableCryptography ) {
|
|
if( hProv == DUMMY_HPROV &&
|
|
pPublicKeyBlob->BlobSignature == CLEARTEXT_BLOB_SIGNATURE
|
|
) {
|
|
|
|
*phPublicKey = *(HCRYPTKEY *)( pPublicKeyBlob + 1 );
|
|
return NO_ERROR;
|
|
|
|
} else {
|
|
return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
DBG_ASSERT( pPublicKeyBlob->BlobSignature == PUBLIC_KEY_BLOB_SIGNATURE );
|
|
|
|
//
|
|
// Import the key into our CSP.
|
|
//
|
|
|
|
blob = (PIC_BLOB)pPublicKeyBlob;
|
|
|
|
status = CryptImportKey(
|
|
hProv,
|
|
BLOB_TO_DATA(blob),
|
|
blob->DataLength,
|
|
CRYPT_NULL,
|
|
0,
|
|
phPublicKey
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportPublicKeyBlob.CryptImportKey failed err=0x%x.\n",result));
|
|
}
|
|
|
|
if( SUCCEEDED(result) ) {
|
|
DBG_ASSERT( *phPublicKey != CRYPT_NULL );
|
|
UpdateKeysOpened();
|
|
}
|
|
|
|
return result;
|
|
|
|
} // IISCryptoImportPublicKeyBlob
|
|
|
|
|
|
//
|
|
// Private functions.
|
|
//
|
|
|
|
|
|
HRESULT
|
|
IcpGetKeyHelper(
|
|
OUT HCRYPTKEY * phKey,
|
|
IN HCRYPTPROV hProv,
|
|
IN DWORD dwKeySpec
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a helper routine for IISCryptoGetKeyExchangeKey() and
|
|
IISCryptoGetSignatureKey(). It tries to get/generate the specific
|
|
key type within the given provider.
|
|
|
|
Arguments:
|
|
|
|
phKey - Receives the key handle if successful.
|
|
|
|
hProv - A handle to a crypto service provider.
|
|
|
|
dwKeySpec - The specification of the key to open/create.
|
|
|
|
Return Value:
|
|
|
|
HRESULT - Completion status, 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HRESULT result = NO_ERROR;
|
|
BOOL status;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
DBG_ASSERT( IcpGlobals.Initialized );
|
|
DBG_ASSERT( phKey != NULL );
|
|
DBG_ASSERT( hProv != CRYPT_NULL );
|
|
|
|
//
|
|
// Short-circuit if cryptography is disabled.
|
|
//
|
|
|
|
if( !IcpGlobals.EnableCryptography ) {
|
|
if( hProv == DUMMY_HPROV ) {
|
|
|
|
if( dwKeySpec == AT_KEYEXCHANGE ) {
|
|
*phKey = DUMMY_HKEYEXCHANGEKEY;
|
|
} else {
|
|
ASSERT( dwKeySpec == AT_SIGNATURE );
|
|
*phKey = DUMMY_HSIGNATUREKEY;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} else {
|
|
return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try to retrieve the key.
|
|
//
|
|
|
|
status = CryptGetUserKey(
|
|
hProv,
|
|
dwKeySpec,
|
|
phKey
|
|
);
|
|
|
|
if( status ) {
|
|
DBG_ASSERT( *phKey != CRYPT_NULL );
|
|
UpdateKeysOpened();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Could not get the key. If the failure was anything other than
|
|
// NTE_NO_KEY, then we're toast.
|
|
//
|
|
|
|
result = IcpGetLastError();
|
|
|
|
if( result != NTE_NO_KEY ) {
|
|
DBGPRINTF(( DBG_CONTEXT,"IcpGetKeyHelper.CryptGetUserKey (advapi32.dll) failed err=0x%x.toast.\n",result));
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// OK, CryptGetUserKey() failed with NTE_NO_KEY, meaning
|
|
// that the key does not yet exist, so generate it now.
|
|
//
|
|
// Note that we must be careful to handle the inevitable race
|
|
// conditions that can occur when multiple threads execute this
|
|
// code and each thinks they need to generate the key. We handle
|
|
// this by acquiring the global lock, then reattempting to get
|
|
// the key. If we still cannot get the key, only then do we attempt
|
|
// to generate one.
|
|
//
|
|
|
|
result = NO_ERROR; // until proven otherwise...
|
|
|
|
IcpAcquireGlobalLock();
|
|
|
|
status = CryptGetUserKey(
|
|
hProv,
|
|
dwKeySpec,
|
|
phKey
|
|
);
|
|
|
|
if( !status )
|
|
{
|
|
//
|
|
// We still cannot get the key, so try to generate one.
|
|
//
|
|
DBGPRINTF(( DBG_CONTEXT,"IcpGetKeyHelper.CryptGetUserKey:failed, lets try to generate another key.\n"));
|
|
status = CryptGenKey(
|
|
hProv,
|
|
dwKeySpec,
|
|
0,
|
|
phKey
|
|
);
|
|
|
|
if( !status ) {
|
|
result = IcpGetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT,"IcpGetKeyHelper.CryptGenKey (advapi32.dll) failed err=0x%x.\n",result));
|
|
}
|
|
else
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"IcpGetKeyHelper.CryptGenKey:key generated.\n"));
|
|
}
|
|
|
|
}
|
|
|
|
if( SUCCEEDED(result) )
|
|
{
|
|
UpdateKeysOpened();
|
|
}
|
|
else
|
|
{
|
|
*phKey = CRYPT_NULL;
|
|
}
|
|
|
|
IcpReleaseGlobalLock();
|
|
return result;
|
|
|
|
} // IcpGetKeyHelper
|
|
|