|
|
//+--------------------------------------------------------------------------
//
// Copyright (c) 1999 Microsoft Corporation
//
// File: keypack.c
//
// Contents: Keypack encoding/decoding library
//
// History:
//
//---------------------------------------------------------------------------
#include "precomp.h"
#include <stddef.h>
#include "md5.h"
#include "rc4.h"
#ifdef IGNORE_EXPIRATION
#define LICENSE_EXPIRATION_IGNORE L"SOFTWARE\\Microsoft\\TermServLicensing\\IgnoreLicenseExpiration"
#endif
typedef struct _Enveloped_Data { DWORD cbEncryptedKey; PBYTE pbEncryptedKey; DWORD cbEncryptedData; PBYTE pbEncryptedData; } Enveloped_Data, * PEnveloped_Data;
///////////////////////////////////////////////////////////////////////////////
//
// Internal functions
//
DWORD WINAPI VerifyAndGetLicenseKeyPack( HCRYPTPROV hCryptProv, PLicense_KeyPack pLicenseKeyPack, DWORD cbSignerCert, PBYTE pbSignerCert, DWORD cbRootCertificate, PBYTE pbRootCertificate, DWORD cbSignedBlob, PBYTE pbSignedBlob );
DWORD WINAPI GetCertificate( DWORD cbCertificateBlob, PBYTE pbCertificateBlob, HCRYPTPROV hCryptProv, PCCERT_CONTEXT * ppCertContext, HCERTSTORE * phCertStore );
DWORD WINAPI VerifyCertificateChain( HCERTSTORE hCertStore, PCCERT_CONTEXT pCertContext, DWORD cbRootCertificate, PBYTE pbRootCertificate );
DWORD WINAPI GetCertVerificationResult( DWORD dwFlags );
DWORD WINAPI UnpackEnvelopedData( IN OUT PEnveloped_Data pEnvelopedData, IN DWORD cbPackedData, IN PBYTE pbPackedData );
DWORD WINAPI GetEnvelopedData( IN DWORD dwEncyptType, IN HCRYPTPROV hCryptProv, IN PEnveloped_Data pEnvelopedData, OUT PDWORD pcbData, OUT PBYTE *ppbData );
/////////////////////////////////////////////////////////
DWORD WINAPI LicensePackEncryptDecryptData( IN PBYTE pbParm, IN DWORD cbParm, IN OUT PBYTE pbData, IN DWORD cbData ) /*++
Abstract:
Internal routine to encrypt/decrypt a blob of data
Parameter:
pbParm : binary blob to generate encrypt/decrypt key. cbParm : size of binary blob. pbData : data to be encrypt/decrypt. cbData : size of data to be encrypt/decrypt.
Returns:
ERROR_SUCCESS or error code.
Remark:
--*/ { DWORD dwRetCode = ERROR_SUCCESS; MD5_CTX md5Ctx; RC4_KEYSTRUCT rc4KS; BYTE key[16]; int i;
if(NULL == pbParm || 0 == cbParm) { SetLastError(dwRetCode = ERROR_INVALID_PARAMETER); return dwRetCode; }
MD5Init(&md5Ctx); MD5Update( &md5Ctx, pbParm, cbParm );
MD5Final(&md5Ctx);
memset(key, 0, sizeof(key));
for(i=0; i < 5; i++) { key[i] = md5Ctx.digest[i]; }
//
// Call RC4 to encrypt/decrypt data
//
rc4_key( &rc4KS, sizeof(key), key );
rc4( &rc4KS, cbData, pbData );
return dwRetCode; }
static BYTE rgbPubKeyWithExponentOfOne[] = { 0x06, 0x02, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xab, 0xef, 0xfa, 0xc6, 0x7d, 0xe8, 0xde, 0xfb, 0x68, 0x38, 0x09, 0x92, 0xd9, 0x42, 0x7e, 0x6b, 0x89, 0x9e, 0x21, 0xd7, 0x52, 0x1c, 0x99, 0x3c, 0x17, 0x48, 0x4e, 0x3a, 0x44, 0x02, 0xf2, 0xfa, 0x74, 0x57, 0xda, 0xe4, 0xd3, 0xc0, 0x35, 0x67, 0xfa, 0x6e, 0xdf, 0x78, 0x4c, 0x75, 0x35, 0x1c, 0xa0, 0x74, 0x49, 0xe3, 0x20, 0x13, 0x71, 0x35, 0x65, 0xdf, 0x12, 0x20, 0xf5, 0xf5, 0xf5, 0xc1 };
//---------------------------------------------------------------
BOOL WINAPI GetPlaintextKey( IN HCRYPTPROV hProv, IN HCRYPTKEY hSymKey, OUT BYTE *pbPlainKey // this must be a 16 byte buffer
) /*++
part of Jeff Spelman's code
--*/ { HCRYPTKEY hPubKey = 0; BYTE rgbSimpleBlob[128]; DWORD cbSimpleBlob; BYTE *pb; DWORD i; BOOL fRet = FALSE;
memset(rgbSimpleBlob, 0, sizeof(rgbSimpleBlob));
if (!CryptImportKey(hProv, rgbPubKeyWithExponentOfOne, sizeof(rgbPubKeyWithExponentOfOne), 0, 0, &hPubKey)) { goto Ret; }
cbSimpleBlob = sizeof(rgbSimpleBlob); if (!CryptExportKey(hSymKey, hPubKey, SIMPLEBLOB, 0, rgbSimpleBlob, &cbSimpleBlob)) { goto Ret; }
memset(pbPlainKey, 0, 16); pb = rgbSimpleBlob + sizeof(BLOBHEADER) + sizeof(ALG_ID); // byte reverse the key
for (i = 0; i < 5; i++) { pbPlainKey[i] = pb[5 - (i + 1)]; }
fRet = TRUE;
Ret: if (hPubKey) { CryptDestroyKey(hPubKey); }
return fRet; }
//--------------------------------------------------------------------
DWORD WINAPI KeyPackDecryptData( IN DWORD dwEncryptType, IN HCRYPTPROV hCryptProv, IN BYTE* pbEncryptKey, IN DWORD cbEncryptKey, IN BYTE* pbEncryptData, IN DWORD cbEncryptData, OUT PBYTE* ppbDecryptData, OUT PDWORD pcbDecryptData ) /*++
Abstract:
Decrypt a blob of data
Parameters:
bForceCrypto : TRUE if always use Crypto. API, FALSE otherwise. hCryptProv : pbEncryptKey : cbEncryptKey : pbEncryptData : cbEncryptData : ppbDecryptData : pcbDecryptData :
Returns:
ERROR_SUCCESS or error code.
Remark:
--*/ { HCRYPTKEY hSymKey = 0; DWORD dwErrCode = ERROR_SUCCESS; BYTE rgbPlainKey[16]; RC4_KEYSTRUCT KeyStruct; BOOL bFrenchLocale;
bFrenchLocale = (MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH) == GetSystemDefaultLangID());
if( (HCRYPTPROV)NULL == hCryptProv || NULL == pbEncryptKey || 0 == cbEncryptKey || NULL == pbEncryptData || 0 == cbEncryptData ) { SetLastError(dwErrCode = ERROR_INVALID_PARAMETER); return dwErrCode; }
if( NULL == ppbDecryptData || NULL == pcbDecryptData ) { SetLastError(dwErrCode = ERROR_INVALID_PARAMETER); return dwErrCode; }
*pcbDecryptData = 0; *ppbDecryptData = NULL;
if(!CryptImportKey( hCryptProv, pbEncryptKey, cbEncryptKey, 0, CRYPT_EXPORTABLE, &hSymKey )) { dwErrCode = GetLastError(); goto cleanup; }
*pcbDecryptData = cbEncryptData; *ppbDecryptData = (PBYTE) LocalAlloc(LPTR, cbEncryptData); if(NULL == *ppbDecryptData) { dwErrCode = GetLastError(); goto cleanup; }
memcpy( *ppbDecryptData, pbEncryptData, *pcbDecryptData );
if(bFrenchLocale && LICENSE_KEYPACK_ENCRYPT_CRYPTO == dwEncryptType) { if(!GetPlaintextKey( hCryptProv, hSymKey, rgbPlainKey)) { dwErrCode = GetLastError(); goto cleanup; }
//
// RC4 - input buffer size = output buffer size
//
rc4_key(&KeyStruct, sizeof(rgbPlainKey), rgbPlainKey); rc4(&KeyStruct, *pcbDecryptData, *ppbDecryptData);
dwErrCode = ERROR_SUCCESS; } else { if(!CryptDecrypt(hSymKey, 0, TRUE, 0, *ppbDecryptData, pcbDecryptData)) { dwErrCode = GetLastError(); if(NTE_BAD_LEN == dwErrCode) { PBYTE pbNew; //
// output buffer is too small, re-allocate
//
pbNew = (PBYTE) LocalReAlloc( *ppbDecryptData, *pcbDecryptData, LMEM_ZEROINIT ); if(NULL == pbNew) { dwErrCode = GetLastError(); goto cleanup; }
*ppbDecryptData = pbNew; }
memcpy( *ppbDecryptData, pbEncryptData, cbEncryptData );
if(!CryptDecrypt(hSymKey, 0, TRUE, 0, *ppbDecryptData, pcbDecryptData)) { dwErrCode = GetLastError(); } } } cleanup:
if (hSymKey) { CryptDestroyKey(hSymKey); } if(dwErrCode != ERROR_SUCCESS) { if(*ppbDecryptData != NULL) { LocalFree(*ppbDecryptData); }
*ppbDecryptData = NULL; *pcbDecryptData = 0; }
return dwErrCode; }
///////////////////////////////////////////////////////////////////////////////
//
// decode the encrypted license key pack blob with the license server's private
// key.
//
// hCryptProv is opened with the key container that contains the key exchange
// private key.
//
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI DecodeLicenseKeyPackEx( OUT PLicense_KeyPack pLicenseKeyPack, IN PLicensePackDecodeParm pDecodeParm, IN DWORD cbKeyPackBlob, IN PBYTE pbKeyPackBlob ) /*++
Abstract:
Decode the encrypted license key pack blob.
Parameters:
pLicenseKeyPack : Decoded license key pack. hCryptProv :
--*/ { DWORD dwRetCode = ERROR_SUCCESS; DWORD cbSignedBlob, cbSignature; PBYTE pbSignedBlob = NULL, pcbSignature = NULL; Enveloped_Data EnvelopedData; PEncodedLicenseKeyPack pEncodedLicensePack;
if( NULL == pLicenseKeyPack || NULL == pDecodeParm || NULL == pbKeyPackBlob || 0 == cbKeyPackBlob ) { return ERROR_INVALID_PARAMETER; }
if( (HCRYPTPROV)NULL == pDecodeParm->hCryptProv ) { return ERROR_INVALID_PARAMETER; }
pEncodedLicensePack = (PEncodedLicenseKeyPack)pbKeyPackBlob; if(pEncodedLicensePack->dwSignature != LICENSEPACKENCODE_SIGNATURE) { //
// EncodedLicenseKeyPack() puts size of encryption key as first DWORD
//
dwRetCode = DecodeLicenseKeyPack( pLicenseKeyPack, pDecodeParm->hCryptProv, pDecodeParm->cbClearingHouseCert, pDecodeParm->pbClearingHouseCert, pDecodeParm->cbRootCertificate, pDecodeParm->pbRootCertificate, cbKeyPackBlob, pbKeyPackBlob );
return dwRetCode; }
if(pEncodedLicensePack->dwStructVersion > LICENSEPACKENCODE_CURRENTVERSION) { return ERROR_INVALID_DATA; }
if( pEncodedLicensePack->dwEncodeType > LICENSE_KEYPACK_ENCRYPT_MAX ) { return ERROR_INVALID_DATA; }
if( cbKeyPackBlob != offsetof(EncodedLicenseKeyPack, pbData) + pEncodedLicensePack->cbData ) { return ERROR_INVALID_DATA; } //
// check input parameters
//
if( 0 == pDecodeParm->cbClearingHouseCert || NULL == pDecodeParm->pbClearingHouseCert || 0 == pDecodeParm->cbRootCertificate || NULL == pDecodeParm->pbRootCertificate ) { return ERROR_INVALID_PARAMETER; }
//
// Get the enveloped data
//
memset( &EnvelopedData, 0, sizeof( Enveloped_Data ) );
dwRetCode = UnpackEnvelopedData( &EnvelopedData, pEncodedLicensePack->cbData, &(pEncodedLicensePack->pbData[0]) );
if( ERROR_SUCCESS != dwRetCode ) { goto done; }
switch( pEncodedLicensePack->dwEncodeType ) { case LICENSE_KEYPACK_ENCRYPT_CRYPTO: case LICENSE_KEYPACK_ENCRYPT_ALWAYSCRYPTO:
//
// unpack the enveloped data to get the signed keypack blob
//
dwRetCode = GetEnvelopedData( pEncodedLicensePack->dwEncodeType, pDecodeParm->hCryptProv, &EnvelopedData, &cbSignedBlob, &pbSignedBlob );
break;
default:
// impossible to come here
dwRetCode = ERROR_INVALID_DATA; }
if( ERROR_SUCCESS != dwRetCode ) { goto done; } //
// Get the license keypack from the signed blob. We also provide the
// clearing house certificate to verify the authenticity of the keypack.
//
dwRetCode = VerifyAndGetLicenseKeyPack( pDecodeParm->hCryptProv, pLicenseKeyPack, pDecodeParm->cbClearingHouseCert, pDecodeParm->pbClearingHouseCert, pDecodeParm->cbRootCertificate, pDecodeParm->pbRootCertificate, cbSignedBlob, pbSignedBlob );
done:
if( EnvelopedData.pbEncryptedKey ) { LocalFree( EnvelopedData.pbEncryptedKey ); }
if( EnvelopedData.pbEncryptedData ) { LocalFree( EnvelopedData.pbEncryptedData ); }
if( pbSignedBlob ) { LocalFree( pbSignedBlob ); }
return( dwRetCode ); }
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI GetEnvelopedData( IN DWORD dwEncryptType, IN HCRYPTPROV hCryptProv, IN PEnveloped_Data pEnvelopedData, OUT PDWORD pcbData, OUT PBYTE *ppbData ) /*++
--*/ { HCRYPTKEY hPrivateKey = 0; DWORD dwRetCode = ERROR_SUCCESS;
if( (HCRYPTPROV)NULL == hCryptProv || pEnvelopedData == NULL || ppbData == NULL || pcbData == NULL ) { SetLastError(dwRetCode = ERROR_INVALID_PARAMETER); return dwRetCode; }
//
// Make sure we have a exchange key to decrypt session key.
//
if( !CryptGetUserKey( hCryptProv, AT_KEYEXCHANGE, &hPrivateKey ) ) { dwRetCode = GetLastError(); goto done; }
//
// decrypt the data, KeyPackDecryptData() handle
// memory freeing in case of error.
//
dwRetCode = KeyPackDecryptData( dwEncryptType, hCryptProv, pEnvelopedData->pbEncryptedKey, pEnvelopedData->cbEncryptedKey, pEnvelopedData->pbEncryptedData, pEnvelopedData->cbEncryptedData, ppbData, pcbData ); done:
if( hPrivateKey ) { CryptDestroyKey( hPrivateKey ); }
return( dwRetCode ); }
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI UnpackEnvelopedData( IN OUT PEnveloped_Data pEnvelopedData, IN DWORD cbPackedData, IN PBYTE pbPackedData ) /*++
Abstract:
Unpack an encrypted license pack blob.
Parameters:
pEnvelopedData : cbPackedData : pbPackedData :
Returns:
--*/ { PBYTE pbCopyPos = pbPackedData; DWORD cbDataToUnpack = cbPackedData;
//
// ensure that the data is of minimum length
//
if( ( ( sizeof( DWORD ) * 2 ) > cbPackedData ) || ( NULL == pbPackedData ) || ( NULL == pEnvelopedData ) ) { return( ERROR_INVALID_PARAMETER ); }
//
// read a DWORD to get the encrypted key length
//
memcpy( &pEnvelopedData->cbEncryptedKey, pbCopyPos, sizeof( DWORD ) );
pbCopyPos += sizeof( DWORD ); cbDataToUnpack -= sizeof( DWORD ); if( cbDataToUnpack < pEnvelopedData->cbEncryptedKey ) { return( ERROR_INVALID_DATA ); }
//
// Allocate memory to unpack the encrypted key
//
if(pEnvelopedData->cbEncryptedKey > 0) { pEnvelopedData->pbEncryptedKey = LocalAlloc( GPTR, pEnvelopedData->cbEncryptedKey );
if( NULL == pEnvelopedData->pbEncryptedKey ) { return( GetLastError() ); }
memcpy( pEnvelopedData->pbEncryptedKey, pbCopyPos, pEnvelopedData->cbEncryptedKey ); } pbCopyPos += pEnvelopedData->cbEncryptedKey; cbDataToUnpack -= pEnvelopedData->cbEncryptedKey;
//
// expecting to read a DWORD for the encrypted data length
//
if( sizeof( DWORD ) > cbDataToUnpack ) { return( ERROR_INVALID_DATA ); }
memcpy( &pEnvelopedData->cbEncryptedData, pbCopyPos, sizeof( DWORD ) );
pbCopyPos += sizeof( DWORD ); cbDataToUnpack -= sizeof( DWORD );
if( cbDataToUnpack < pEnvelopedData->cbEncryptedData ) { return( ERROR_INVALID_DATA ); }
//
// allocate memory for the encrypted data
//
pEnvelopedData->pbEncryptedData = LocalAlloc( GPTR, pEnvelopedData->cbEncryptedData );
if( NULL == pEnvelopedData->pbEncryptedData ) { return( GetLastError() ); }
memcpy( pEnvelopedData->pbEncryptedData, pbCopyPos, pEnvelopedData->cbEncryptedData );
return( ERROR_SUCCESS ); }
///////////////////////////////////////////////////////////////////////////////
//
// decode the encrypted license key pack blob with the license server's private
// key.
//
// hCryptProv is opened with the key container that contains the key exchange
// private key.
//
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI DecodeLicenseKeyPack( PLicense_KeyPack pLicenseKeyPack, HCRYPTPROV hCryptProv, DWORD cbClearingHouseCert, PBYTE pbClearingHouseCert, DWORD cbRootCertificate, PBYTE pbRootCertificate, DWORD cbKeyPackBlob, PBYTE pbKeyPackBlob ) { DWORD dwRetCode = ERROR_SUCCESS; DWORD cbSignedBlob, cbSignature; PBYTE pbSignedBlob = NULL, pcbSignature = NULL; Enveloped_Data EnvelopedData;
if( 0 == hCryptProv ) { return( ERROR_INVALID_PARAMETER ); } //
// Get the enveloped data
//
memset( &EnvelopedData, 0, sizeof( Enveloped_Data ) );
dwRetCode = UnpackEnvelopedData( &EnvelopedData, cbKeyPackBlob, pbKeyPackBlob );
if( ERROR_SUCCESS != dwRetCode ) { goto done; }
//
// unpack the enveloped data to get the signed keypack blob
//
dwRetCode = GetEnvelopedData( LICENSE_KEYPACK_ENCRYPT_CRYPTO, hCryptProv, &EnvelopedData, &cbSignedBlob, &pbSignedBlob );
if( ERROR_SUCCESS != dwRetCode ) { goto done; } //
// Get the license keypack from the signed blob. We also provide the
// clearing house certificate to verify the authenticity of the keypack.
//
dwRetCode = VerifyAndGetLicenseKeyPack( hCryptProv, pLicenseKeyPack, cbClearingHouseCert, pbClearingHouseCert, cbRootCertificate, pbRootCertificate, cbSignedBlob, pbSignedBlob );
done:
if( EnvelopedData.pbEncryptedKey ) { LocalFree( EnvelopedData.pbEncryptedKey ); }
if( EnvelopedData.pbEncryptedData ) { LocalFree( EnvelopedData.pbEncryptedData ); }
if( pbSignedBlob ) { LocalFree( pbSignedBlob ); }
return( dwRetCode ); }
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI VerifyAndGetLicenseKeyPack( HCRYPTPROV hCryptProv, PLicense_KeyPack pLicenseKeyPack, DWORD cbSignerCert, PBYTE pbSignerCert, DWORD cbRootCertificate, PBYTE pbRootCertificate, DWORD cbSignedBlob, PBYTE pbSignedBlob ) { DWORD dwRetCode = ERROR_SUCCESS; PCCERT_CONTEXT pCertContext = 0; HCERTSTORE hCertStore = 0; HCRYPTHASH hCryptHash = 0; HCRYPTKEY hPubKey = 0; PBYTE pbCopyPos = pbSignedBlob, pbSignedHash; PKeyPack_Description pKpDesc; DWORD i, cbSignedHash, cbRequired = 0; SetLastError(ERROR_SUCCESS);
//
// make sure that the signed key blob is of the minimum size
//
cbRequired = ( 10 * sizeof( DWORD ) ) + ( 3 * sizeof( FILETIME ) ) + sizeof( GUID ) ;
if( cbSignedBlob < cbRequired ) { return( ERROR_INVALID_PARAMETER ); }
//
// get a certificate context for the signer's certificate
//
dwRetCode = GetCertificate( cbSignerCert, pbSignerCert, hCryptProv, &pCertContext, &hCertStore );
if( ERROR_SUCCESS != dwRetCode ) { SetLastError(dwRetCode); goto ErrorReturn; } //
// Verify the signer's certificate and the certificate chain that issued the
// certificate.
//
dwRetCode = VerifyCertificateChain( hCertStore, pCertContext, cbRootCertificate, pbRootCertificate );
if( ERROR_SUCCESS != dwRetCode ) { SetLastError(dwRetCode); goto ErrorReturn; }
//
// unpack the signed blob
//
memcpy( &pLicenseKeyPack->dwVersion, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD ); memcpy( &pLicenseKeyPack->dwKeypackType, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD ); memcpy( &pLicenseKeyPack->dwDistChannel, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD ); memcpy( &pLicenseKeyPack->KeypackSerialNum, pbCopyPos, sizeof( GUID ) ); pbCopyPos += sizeof( GUID ); memcpy( &pLicenseKeyPack->IssueDate, pbCopyPos, sizeof( FILETIME ) ); pbCopyPos += sizeof( FILETIME );
memcpy( &pLicenseKeyPack->ActiveDate, pbCopyPos, sizeof( FILETIME ) ); pbCopyPos += sizeof( FILETIME );
memcpy( &pLicenseKeyPack->ExpireDate, pbCopyPos, sizeof( FILETIME ) ); pbCopyPos += sizeof( FILETIME );
memcpy( &pLicenseKeyPack->dwBeginSerialNum, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
memcpy( &pLicenseKeyPack->dwQuantity, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
memcpy( &pLicenseKeyPack->cbProductId, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
if( pLicenseKeyPack->cbProductId ) { cbRequired += pLicenseKeyPack->cbProductId;
if( cbSignedBlob < cbRequired ) { SetLastError(dwRetCode = ERROR_INVALID_PARAMETER); goto ErrorReturn; }
pLicenseKeyPack->pbProductId = LocalAlloc( GPTR, pLicenseKeyPack->cbProductId );
if( NULL == pLicenseKeyPack->pbProductId ) { goto ErrorReturn; }
memcpy( pLicenseKeyPack->pbProductId, pbCopyPos, pLicenseKeyPack->cbProductId ); pbCopyPos += pLicenseKeyPack->cbProductId; }
memcpy( &pLicenseKeyPack->dwProductVersion, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
memcpy( &pLicenseKeyPack->dwPlatformId, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
memcpy( &pLicenseKeyPack->dwLicenseType, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
memcpy( &pLicenseKeyPack->dwDescriptionCount, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
if( pLicenseKeyPack->dwDescriptionCount ) { //
// allocate memory for the keypack descriptions structure
//
pLicenseKeyPack->pDescription = LocalAlloc( GPTR, ( sizeof( KeyPack_Description ) * pLicenseKeyPack->dwDescriptionCount ) );
if( NULL == pLicenseKeyPack->pDescription ) { goto ErrorReturn; } for( i = 0, pKpDesc = pLicenseKeyPack->pDescription; i < pLicenseKeyPack->dwDescriptionCount; i++, pKpDesc++ ) { cbRequired += ( sizeof( LCID ) + 2* (sizeof( DWORD ) ));
if( cbSignedBlob < cbRequired) { SetLastError(dwRetCode = ERROR_INVALID_PARAMETER); goto ErrorReturn;
}
memcpy( &pKpDesc->Locale, pbCopyPos, sizeof( LCID ) ); pbCopyPos += sizeof( LCID );
memcpy( &pKpDesc->cbProductName, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
if( pKpDesc->cbProductName ) { //
// allocate memory for product name
//
cbRequired += (pKpDesc->cbProductName);
if( cbSignedBlob < cbRequired) { SetLastError(dwRetCode = ERROR_INVALID_PARAMETER); goto ErrorReturn;
}
pKpDesc->pbProductName = LocalAlloc( GPTR, pKpDesc->cbProductName );
if( NULL == pKpDesc->pbProductName ) { goto ErrorReturn; }
//
// copy the product name
//
memcpy( pKpDesc->pbProductName, pbCopyPos, pKpDesc->cbProductName ); pbCopyPos += pKpDesc->cbProductName; }
memcpy( &pKpDesc->cbDescription, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
if( pKpDesc->cbDescription ) { //
// allocate memory for the keypack description
//
cbRequired += (pKpDesc->cbDescription);
if( cbSignedBlob < cbRequired) { SetLastError(dwRetCode = ERROR_INVALID_PARAMETER); goto ErrorReturn; }
pKpDesc->pDescription = LocalAlloc( GPTR, pKpDesc->cbDescription );
if( NULL == pKpDesc->pDescription ) { goto ErrorReturn; }
//
// copy the key pack description
//
memcpy( pKpDesc->pDescription, pbCopyPos, pKpDesc->cbDescription ); pbCopyPos += pKpDesc->cbDescription; } } }
cbRequired += ( 3 * sizeof( DWORD ));
if( cbSignedBlob < cbRequired) { SetLastError(dwRetCode = ERROR_INVALID_PARAMETER); goto ErrorReturn; }
memcpy( &pLicenseKeyPack->cbManufacturer, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
if( pLicenseKeyPack->cbManufacturer ) { cbRequired += (pLicenseKeyPack->cbManufacturer);
if( cbSignedBlob < cbRequired) { SetLastError(dwRetCode = ERROR_INVALID_PARAMETER); goto ErrorReturn;
} pLicenseKeyPack->pbManufacturer = LocalAlloc( GPTR, pLicenseKeyPack->cbManufacturer );
if( NULL == pLicenseKeyPack->pbManufacturer ) { goto ErrorReturn; }
memcpy( pLicenseKeyPack->pbManufacturer, pbCopyPos, pLicenseKeyPack->cbManufacturer ); pbCopyPos += pLicenseKeyPack->cbManufacturer; }
memcpy( &pLicenseKeyPack->cbManufacturerData, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD );
if( pLicenseKeyPack->cbManufacturerData ) { cbRequired += (pLicenseKeyPack->cbManufacturerData);
if( cbSignedBlob < cbRequired) { SetLastError(dwRetCode = ERROR_INVALID_PARAMETER); goto ErrorReturn;
}
pLicenseKeyPack->pbManufacturerData = LocalAlloc( GPTR, pLicenseKeyPack->cbManufacturerData );
if( NULL == pLicenseKeyPack->pbManufacturerData ) { goto ErrorReturn; }
memcpy( pLicenseKeyPack->pbManufacturerData, pbCopyPos, pLicenseKeyPack->cbManufacturerData ); pbCopyPos += pLicenseKeyPack->cbManufacturerData; }
//
// get the size and the pointer of the signed hash.
//
memcpy( &cbSignedHash, pbCopyPos, sizeof( DWORD ) ); pbSignedHash = pbCopyPos + sizeof( DWORD );
//
// compute the hash
//
if( !CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hCryptHash ) ) { goto ErrorReturn; }
if( !CryptHashData( hCryptHash, pbSignedBlob, (DWORD)(pbCopyPos - pbSignedBlob), 0 ) ) { goto ErrorReturn; }
//
// import the public key
//
if( !CryptImportPublicKeyInfoEx( hCryptProv, X509_ASN_ENCODING, &pCertContext->pCertInfo->SubjectPublicKeyInfo, CALG_RSA_SIGN, 0, NULL, &hPubKey ) ) { goto ErrorReturn; } //
// use the public key to verify the signed hash
//
if( !CryptVerifySignature( hCryptHash, pbSignedHash, cbSignedHash, hPubKey, NULL, 0) ) { goto ErrorReturn; } ErrorReturn:
dwRetCode = GetLastError();
if( hCryptHash ) { CryptDestroyHash( hCryptHash ); }
if( hPubKey ) { CryptDestroyKey( hPubKey ); }
if( pCertContext ) { CertFreeCertificateContext( pCertContext ); }
if( hCertStore ) { CertCloseStore( hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ); }
return( dwRetCode ); }
///////////////////////////////////////////////////////////////////////////////
//
// GetCertificate
//
// Get the first certificate from the certificate blob. The certificate blob
// is in fact a certificate store that may contain a chain of certificates.
// This function also return handles to the crypto provider and the certificate
// store.
//
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI GetCertificate( DWORD cbCertificateBlob, PBYTE pbCertificateBlob, HCRYPTPROV hCryptProv, PCCERT_CONTEXT * ppCertContext, HCERTSTORE * phCertStore ) { CRYPT_DATA_BLOB CertBlob; DWORD dwRetCode = ERROR_SUCCESS; //
// Open the PKCS7 certificate store
//
CertBlob.cbData = cbCertificateBlob; CertBlob.pbData = pbCertificateBlob;
*phCertStore = CertOpenStore( sz_CERT_STORE_PROV_PKCS7, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, hCryptProv, CERT_STORE_NO_CRYPT_RELEASE_FLAG, &CertBlob );
if( NULL == ( *phCertStore ) ) { return( GetLastError() ); }
//
// get the first certificate from the store
//
*ppCertContext = CertEnumCertificatesInStore( *phCertStore, NULL ); if( NULL == ( *ppCertContext ) ) { return( GetLastError() ); } return( dwRetCode ); }
///////////////////////////////////////////////////////////////////////////////
//
// VerifyCertificateChain
//
// Verify the certificate represented by the cert context against the
// issuers in the certificate store. The caller may provide a root
// certificate so that all issuers are eventually verified against this
// root certificate. If no root certificate is provided, then the last
// issuer in the chain must be a self-signing issuer.
//
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI VerifyCertificateChain( HCERTSTORE hCertStore, PCCERT_CONTEXT pCertContext, DWORD cbRootCertificate, PBYTE pbRootCertificate ) { DWORD dwRetCode = ERROR_SUCCESS, dwFlags; PCCERT_CONTEXT pRootCertCtx = NULL; PCCERT_CONTEXT pIssuerCertCtx = NULL; PCCERT_CONTEXT pCurrentContext = NULL; #ifdef IGNORE_EXPIRATION
LONG lRet; HKEY hKey = NULL; #endif
if( ( 0 != cbRootCertificate ) && ( NULL != pbRootCertificate ) ) { //
// Get a certificate context for the root certificate
//
pRootCertCtx = CertCreateCertificateContext( X509_ASN_ENCODING, pbRootCertificate, cbRootCertificate );
if( NULL == pRootCertCtx ) { dwRetCode = GetLastError(); goto done; } }
//
// Verify the certificate chain. The time, signature and validity of
// the subject certificate is verified. Only the signatures are verified
// for the certificates in the issuer chain.
//
#ifdef IGNORE_EXPIRATION
//Verify if registry key exists and ignore time check
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, LICENSE_EXPIRATION_IGNORE , 0, KEY_READ , &hKey );
if( ERROR_SUCCESS == lRet ) {
dwFlags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG; } else { #endif
dwFlags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG; #ifdef IGNORE_EXPIRATION
}
if(hKey) { RegCloseKey(hKey); } #endif
pCurrentContext = CertDuplicateCertificateContext( pCertContext );
if (NULL == pCurrentContext) { dwRetCode = ERROR_INVALID_PARAMETER; goto done; }
do { pIssuerCertCtx = NULL; pIssuerCertCtx = CertGetIssuerCertificateFromStore( hCertStore, pCurrentContext, pIssuerCertCtx, &dwFlags ); if( pIssuerCertCtx ) { //
// Found the issuer, verify that the checks went OK
//
dwRetCode = GetCertVerificationResult( dwFlags );
if( ERROR_SUCCESS != dwRetCode ) { break; } //
// only verify the signature for subsequent issuer certificates
//
dwFlags = CERT_STORE_SIGNATURE_FLAG;
//
// free the current certificate context and make the current issuer certificate
// the subject certificate for the next iteration.
//
CertFreeCertificateContext( pCurrentContext ); pCurrentContext = pIssuerCertCtx; } } while( pIssuerCertCtx );
if( ERROR_SUCCESS != dwRetCode ) { //
// encountered some error while verifying the certificate
//
goto done; }
//
// we got here because we have walked through the chain of issuers in the
// store. The last issuer in the chain may or may not be a self signing root.
//
if( pRootCertCtx ) { //
// The caller has specified a root certificate that must be used. Verify the
// last issuer against this root certificate regardless of whether it is a
// self signing root.
//
dwFlags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
if( ( NULL == pCurrentContext ) || ( !CertVerifySubjectCertificateContext( pCurrentContext, pRootCertCtx, &dwFlags ) ) ) { dwRetCode = GetLastError(); goto done; }
//
// get the certificate verification result
//
dwRetCode = GetCertVerificationResult( dwFlags ); } else { //
// if the caller did not specify a CA root certificate, make sure that the root
// issuer of the certificate is a self-signed root. Otherwise, return an error
//
if( CRYPT_E_SELF_SIGNED != GetLastError() ) { dwRetCode = GetLastError(); } }
done: if( pRootCertCtx ) { CertFreeCertificateContext( pRootCertCtx ); }
if( pCurrentContext ) { CertFreeCertificateContext( pCurrentContext ); }
if( pIssuerCertCtx ) { CertFreeCertificateContext( pIssuerCertCtx ); }
return( dwRetCode ); }
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI GetCertVerificationResult( DWORD dwFlags ) { if( dwFlags & CERT_STORE_SIGNATURE_FLAG ) { //
// The certificate signature did not verify
//
return( (DWORD )NTE_BAD_SIGNATURE );
} if( dwFlags & CERT_STORE_TIME_VALIDITY_FLAG ) { //
// The certificate has expired
//
return( ( DWORD )CERT_E_EXPIRED ); }
//
// check if the cert has been revoked
//
if( dwFlags & CERT_STORE_REVOCATION_FLAG ) { if( !( dwFlags & CERT_STORE_NO_CRL_FLAG ) ) { //
// The certificate has been revoked
//
return( ( DWORD )CERT_E_REVOKED ); } }
return( ERROR_SUCCESS ); }
|