|
|
/*++
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
|