Leaked source code of windows server 2003
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

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