//+-------------------------------------------------------------------------- // // Copyright (c) 1999 Microsoft Corporation // // File: keypack.c // // Contents: Keypack encoding/decoding library // // History: // //--------------------------------------------------------------------------- #include "precomp.h" #include #include "md5.h" #include "rc4.h" 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( LICENSE_KEYPACK_ENCRYPT_ALWAYSFRENCH == dwEncryptType || (TRUE == 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; } // // depends on encryption type, check input parameter // if( LICENSE_KEYPACK_ENCRYPT_PRIVATE == pEncodedLicensePack->dwEncodeType ) { if(NULL == pDecodeParm->pbDecryptParm || 0 == pDecodeParm->cbDecryptParm ) { return ERROR_INVALID_PARAMETER; } } 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_NONE: case LICENSE_KEYPACK_ENCRYPT_PRIVATE: pbSignedBlob = EnvelopedData.pbEncryptedData; cbSignedBlob = EnvelopedData.cbEncryptedData; EnvelopedData.pbEncryptedData = NULL; EnvelopedData.pbEncryptedData = 0; if( LICENSE_KEYPACK_ENCRYPT_PRIVATE == pEncodedLicensePack->dwEncodeType ) { dwRetCode = LicensePackEncryptDecryptData( pDecodeParm->pbDecryptParm, pDecodeParm->cbDecryptParm, pbSignedBlob, cbSignedBlob ); } break; case LICENSE_KEYPACK_ENCRYPT_CRYPTO: case LICENSE_KEYPACK_ENCRYPT_ALWAYSCRYPTO: case LICENSE_KEYPACK_ENCRYPT_ALWAYSFRENCH: // // 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; SetLastError(ERROR_SUCCESS); // // make sure that the signed key blob is of the minimum size // if( cbSignedBlob < ( ( 8 * sizeof( DWORD ) ) + ( 3 * sizeof( FILETIME ) ) + sizeof( GUID ) ) ) { 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 ) { 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++ ) { 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 // 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 // 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; } } } memcpy( &pLicenseKeyPack->cbManufacturer, pbCopyPos, sizeof( DWORD ) ); pbCopyPos += sizeof( DWORD ); if( pLicenseKeyPack->cbManufacturer ) { 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 ) { 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; 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. // dwFlags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG; 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 ); }