windows-nt/Source/XPSP1/NT/termsrv/common/license/hclient/liclient/cliprot.c
2020-09-26 16:20:57 +08:00

2187 lines
72 KiB
C

/*++
Copyright (c) 1998-99 Microsoft Corporation
Module Name:
cliprot.c
Abstract:
Author:
Frederick Chong (fredch) 6/1/1998
Environment:
Win32, WinCE, Win16
Notes:
--*/
#include "windows.h"
#ifndef OS_WINCE
#include "stdio.h"
#endif // OS_WINCE
#include "stdlib.h"
#ifdef OS_WINCE
#include "wincelic.h"
#endif //OS_WINCE
#include "tchar.h"
#include "lmcons.h"
#include "seccom.h"
#include "cryptkey.h"
#include "hccontxt.h"
#include "cliprot.h"
#include "hcpack.h"
#include "store.h"
#include "licdbg.h"
#include "platform.h"
#include "licecert.h"
#ifdef _WIN64
#define OFFSET_OF(type, field) ((LONG)(LONG_PTR)&(((type *)0)->field))
#else
#define OFFSET_OF(type, field) ((LONG)(LONG *)&(((type *)0)->field))
#endif
#define MAX_ALLOWABLE_LICENSE_SIZE (256 * 1024)
#define EXTENDED_ERROR_CAPABILITY 0x80
VOID
FreeProprietaryCertificate(
PHydra_Server_Cert * ppCertificate );
static BOOL GeneratePseudoLicense(DWORD FAR * pcbData , PBYTE *ppbData);
static LICENSE_STATUS MapStoreError(LS_STATUS lsStatus)
{
if(lsStatus == LSSTAT_SUCCESS)
return LICENSE_STATUS_OK;
if( (lsStatus == LSSTAT_ERROR) || (lsStatus == LSSTAT_INVALID_HANDLE) )
return LICENSE_STATUS_INVALID_INPUT;
if(lsStatus == LSSTAT_INSUFFICIENT_BUFFER)
return LICENSE_STATUS_INSUFFICIENT_BUFFER;
if(lsStatus == LSSTAT_LICENSE_NOT_FOUND)
return LICENSE_STATUS_NO_LICENSE_ERROR;
if(lsStatus == LSSTAT_OUT_OF_MEMORY)
return LICENSE_STATUS_OUT_OF_MEMORY;
if(lsStatus == LSSTAT_LICENSE_EXISTS)
return LICENSE_STATUS_DUPLICATE_LICENSE_ERROR;
return LICENSE_STATUS_INVALID_INPUT;
}
LICENSE_STATUS
CALL_TYPE
LicenseClientHandleServerMessage(
PLicense_Client_Context pContext,
UINT32 *puiExtendedErrorInfo,
BYTE FAR * pbInput,
DWORD cbInput,
BYTE FAR * pbOutput,
DWORD FAR * pcbOutput
)
{
LICENSE_STATUS lsReturn = LICENSE_STATUS_OK;
BYTE FAR *pbTemp = NULL;
DWORD dwTemp = 0;
Preamble Header;
BOOL fNew = FALSE;
BOOL fSupportExtendedError = FALSE;
if(NULL == pContext || NULL == pbInput || pcbOutput == NULL)
{
lsReturn = LICENSE_STATUS_INVALID_INPUT;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
pbTemp = pbInput;
dwTemp = cbInput;
Header = *( UNALIGNED Preamble*)pbTemp;
//
// check if we can support this preamble version
//
if( Header.bVersion > LICENSE_CURRENT_PREAMBLE_VERSION )
{
lsReturn = LICENSE_STATUS_NOT_SUPPORTED;
goto CommonReturn;
}
//
// Sets the preamble version to the version that the server is using
//
pContext->dwProtocolVersion |= Header.bVersion;
if(pContext->dwProtocolVersion >= 2)
{
fSupportExtendedError = TRUE;
}
if( Header.wMsgSize != dwTemp)
{
License_Error_Message Error;
memset(&Error, 0x00, sizeof(License_Error_Message));
Error.dwErrorCode = GM_HS_ERR_INVALID_MESSAGE_LEN;
Error.dwStateTransition = ST_RESEND_LAST_MESSAGE;
Error.bbErrorInfo.wBlobType = BB_ERROR_BLOB;
Error.bbErrorInfo.wBlobLen = 0;
Error.bbErrorInfo.pBlob = NULL;
DebugLog((DEB_TRACE, "Packing License Error Message from Client : %4d\n", *pcbOutput));
PackLicenseErrorMessage(&Error, fSupportExtendedError, pbOutput, pcbOutput);
lsReturn = LICENSE_STATUS_INVALID_INPUT;
goto CommonReturn;
}
pbTemp += sizeof(Preamble);
dwTemp -= sizeof(Preamble);
switch(Header.bMsgType)
{
case GM_ERROR_ALERT:
{
License_Error_Message Error;
memset(&Error, 0x00, sizeof(License_Error_Message));
DebugLog((DEB_TRACE, "Unpacking Hydra Server Error Message of size: %4d\n", dwTemp));
if( LICENSE_STATUS_OK != (lsReturn = UnPackLicenseErrorMessage(pbTemp,
dwTemp,
&Error)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
DebugLog((DEB_TRACE, "LicenseClientHandleServerError : %4d\n", *pcbOutput));
lsReturn = LicenseClientHandleServerError(pContext,
&Error,
puiExtendedErrorInfo,
pbOutput,
pcbOutput);
if(Error.bbErrorInfo.pBlob)
{
free(Error.bbErrorInfo.pBlob);
Error.bbErrorInfo.pBlob = NULL;
}
#if DBG
if(pbOutput)
OutputDebugString(_T("Client response data : \n"));
LS_DUMPSTRING(*pcbOutput, pbOutput);
#endif
if( lsReturn == LICENSE_STATUS_OK ||
lsReturn == LICENSE_STATUS_CONTINUE ||
lsReturn == LICENSE_STATUS_CLIENT_ABORT ||
lsReturn == LICENSE_STATUS_SERVER_ABORT )
goto CommonReturn;
else
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
break;
}
case HS_LICENSE_REQUEST:
{
Hydra_Server_License_Request LicRequest;
DWORD dw;
memset(&LicRequest, 0x00, sizeof(Hydra_Server_License_Request));
DebugLog((DEB_TRACE, "Unpacking Hydra Server's License Request : %4d\n", dwTemp));
if( LICENSE_STATUS_OK != (lsReturn = UnpackHydraServerLicenseRequest(pbTemp,
dwTemp,
&LicRequest)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
DebugLog((DEB_TRACE, "Client handles Server's license Request : %4d\n", *pcbOutput));
lsReturn = LicenseClientHandleServerRequest(pContext,
&LicRequest,
TRUE,
pbOutput,
pcbOutput,
fSupportExtendedError);
#if DBG
if(pbOutput)
OutputDebugString(_T("Client response data : \n"));
LS_DUMPSTRING(*pcbOutput, pbOutput);
#endif
if(LicRequest.ProductInfo.pbCompanyName)
{
free(LicRequest.ProductInfo.pbCompanyName);
LicRequest.ProductInfo.pbCompanyName = NULL;
}
if(LicRequest.ProductInfo.pbProductID)
{
free(LicRequest.ProductInfo.pbProductID);
LicRequest.ProductInfo.pbProductID = NULL;
}
for(dw = 0; dw <LicRequest.ScopeList.dwScopeCount; dw++)
{
if(LicRequest.ScopeList.Scopes[dw].pBlob)
{
free(LicRequest.ScopeList.Scopes[dw].pBlob);
LicRequest.ScopeList.Scopes[dw].pBlob = NULL;
}
}
if(LicRequest.ScopeList.Scopes)
{
free(LicRequest.ScopeList.Scopes);
LicRequest.ScopeList.Scopes = NULL;
}
if( LicRequest.KeyExchngList.pBlob )
{
free( LicRequest.KeyExchngList.pBlob );
}
if( LicRequest.ServerCert.pBlob )
{
free( LicRequest.ServerCert.pBlob );
}
if( lsReturn != LICENSE_STATUS_OK &&
lsReturn != LICENSE_STATUS_CONTINUE &&
lsReturn != LICENSE_STATUS_CLIENT_ABORT )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
break;
}
case HS_PLATFORM_CHALLENGE:
{
Hydra_Server_Platform_Challenge PlatformCh;
memset(&PlatformCh, 0x00, sizeof(Hydra_Server_Platform_Challenge));
DebugLog((DEB_TRACE, "Unpacking Hydra Server's platform Challenge Request : %4d\n", dwTemp));
if( LICENSE_STATUS_OK != (lsReturn = UnPackHydraServerPlatformChallenge(pbTemp,
dwTemp,
&PlatformCh)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
DebugLog((DEB_TRACE, "Client Handles Server's platform Challenge Response : %0d\n", *pcbOutput));
lsReturn = LicenseClientHandleServerPlatformChallenge(pContext,
&PlatformCh,
pbOutput,
pcbOutput,
fSupportExtendedError);
#if DBG
if(pbOutput)
OutputDebugString(_T("Client response data : \n"));
LS_DUMPSTRING(*pcbOutput, pbOutput);
#endif
if(PlatformCh.EncryptedPlatformChallenge.pBlob)
{
free(PlatformCh.EncryptedPlatformChallenge.pBlob);
PlatformCh.EncryptedPlatformChallenge.pBlob = NULL;
}
if( lsReturn!=LICENSE_STATUS_CONTINUE )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
break;
}
case HS_NEW_LICENSE:
fNew = TRUE;
DebugLog((DEB_TRACE, "New License received from Server.\n"));
case HS_UPGRADE_LICENSE:
{
Hydra_Server_New_License NewLicense;
if (dwTemp > MAX_ALLOWABLE_LICENSE_SIZE)
{
//
// SECURITY: Too much data to store in the registry
// Reject the message
//
LS_LOG_RESULT(lsReturn = LICENSE_STATUS_INVALID_INPUT);
goto ErrorReturn;
}
memset(&NewLicense, 0x00, sizeof(Hydra_Server_New_License));
DebugLog((DEB_TRACE, "Unpacking Hydra Server's New License Message : %4d\n", dwTemp));
if(LICENSE_STATUS_OK !=
(lsReturn = UnPackHydraServerNewLicense(pbTemp,
dwTemp,
&NewLicense)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
DebugLog((DEB_TRACE, "License Client handles New License : %4d\n", *pcbOutput));
lsReturn = LicenseClientHandleNewLicense(pContext,
&NewLicense,
fNew,
pbOutput,
pcbOutput);
if(NewLicense.EncryptedNewLicenseInfo.pBlob)
{
free(NewLicense.EncryptedNewLicenseInfo.pBlob);
NewLicense.EncryptedNewLicenseInfo.pBlob = NULL;
}
#if DBG
if(pbOutput)
OutputDebugString(_T("Client response data : \n"));
LS_DUMPSTRING(*pcbOutput, pbOutput);
#endif
if( lsReturn != LICENSE_STATUS_OK )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
break;
}
default:
//
// Invalid message type
//
lsReturn = LICENSE_STATUS_INVALID_INPUT;
goto ErrorReturn;
break;
}
LS_LOG_RESULT(lsReturn);
CommonReturn:
return lsReturn;
LS_RETURN(lsReturn);
ErrorReturn:
*pcbOutput = 0;
goto CommonReturn;
}
LICENSE_STATUS
CALL_TYPE
LicenseClientHandleServerError(
PLicense_Client_Context pContext,
PLicense_Error_Message pCanonical,
UINT32 *puiExtendedErrorInfo,
BYTE FAR * pbMessage,
DWORD FAR * pcbMessage
)
{
LICENSE_STATUS lsReturn = LICENSE_STATUS_OK;
LS_BEGIN(TEXT("LicenseClientHandleServerError"));
if(NULL == pContext || NULL == pCanonical || NULL == pcbMessage || NULL == puiExtendedErrorInfo)
{
lsReturn = LICENSE_STATUS_INVALID_INPUT;
LS_LOG_RESULT(lsReturn);
return lsReturn;
}
// Switch on the StateTransition as this dictates the next state
// client has to take!
switch(pCanonical->dwStateTransition)
{
case ST_TOTAL_ABORT: //Server has asked for a total abort
*pcbMessage = 0;
if( pCanonical->dwErrorCode == GM_HS_ERR_INVALID_CLIENT ||
pCanonical->dwErrorCode == GM_HS_ERR_INVALID_SCOPE ||
pCanonical->dwErrorCode == GM_HS_ERR_INVALID_PRODUCTID ||
pCanonical->dwErrorCode == GM_HS_ERR_INVALID_CLIENT )
{
lsReturn = LICENSE_STATUS_SERVER_ABORT;
}
else
lsReturn = LICENSE_STATUS_CLIENT_ABORT;
pContext->dwState = LICENSE_CLIENT_STATE_ABORT;
pContext->cbLastMessage = 0;
break;
case ST_NO_TRANSITION:
lsReturn = LICENSE_STATUS_OK;
*pcbMessage = 0;
break;
case ST_RESEND_LAST_MESSAGE:
// Server has asked to send the last send message again!
// treat as error (fall through)
case ST_RESET_PHASE_TO_START:
// Server has asked to restart the negotiation
// treat as error (fall through)
default:
// Server sent unknown dwStateTransition
lsReturn = LICENSE_STATUS_CLIENT_ABORT;
pContext->dwState = LICENSE_CLIENT_STATE_ABORT;
pContext->cbLastMessage = 0;
break;
}
if ((lsReturn != LICENSE_STATUS_OK) && (pCanonical->bbErrorInfo.wBlobLen > 0) && (pCanonical->bbErrorInfo.pBlob != NULL))
{
// ignore any errors
UnPackExtendedErrorInfo(puiExtendedErrorInfo,&(pCanonical->bbErrorInfo));
}
LS_LOG_RESULT(lsReturn);
return lsReturn;
}
LICENSE_STATUS
CALL_TYPE
LicenseClientHandleServerRequest(
PLicense_Client_Context pContext,
PHydra_Server_License_Request pCanonical,
BOOL fNewLicense,
BYTE FAR * pbMessage,
DWORD FAR * pcbMessage,
BOOL fExtendedError
)
{
LICENSE_STATUS lsReturn = LICENSE_STATUS_OK;
UCHAR Random[LICENSE_RANDOM];
UCHAR PreMasterSecret[LICENSE_PRE_MASTER_SECRET];
HANDLE hStore = NULL;
LSINDEX lsIndex;
DWORD dwCount = 0;
BYTE FAR * pbData = NULL;
DWORD cbData = 0;
LS_BEGIN(TEXT("LicenseClientHandleServerRequest"));
memset(&lsIndex, 0x00, sizeof(LSINDEX));
if( (pContext == NULL) || (pCanonical == NULL) )
{
lsReturn = LICENSE_STATUS_INVALID_INPUT;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
if(pContext->dwState != LICENSE_CLIENT_STATE_WAIT_SERVER_HELLO)
{
lsReturn = LICENSE_STATUS_INVALID_CLIENT_STATE;
goto ErrorReturn;
}
if( pContext->dwContextFlags & LICENSE_CONTEXT_NO_SERVER_AUTHENTICATION )
{
//
// No server authentication required, make sure that we have the
// public key or the certificate of the server so that we can use it to
// encrypt the pre-master secret during the next phase of the licensing protocol.
//
if( ( NULL == pContext->pbServerPubKey ) && ( NULL == pContext->pServerCert ) )
{
lsReturn = LICENSE_STATUS_CONTEXT_INITIALIZATION_ERROR;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
}
else
{
//
// Do Hydra server authentication by validating the server certificate
//
DWORD
dwCertVersion;
if( ( 0 >= pCanonical->ServerCert.wBlobLen ) ||
( NULL == pCanonical->ServerCert.pBlob ) )
{
//
// make sure that we have received a certificate from the server
//
lsReturn = LICENSE_STATUS_NO_CERTIFICATE;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//
// Determine the version of the certificate so that we can decode and
// validate it correctly.
//
memcpy( ( char * )&dwCertVersion, pCanonical->ServerCert.pBlob, sizeof( DWORD ) );
if( CERT_CHAIN_VERSION_2 > dwCertVersion )
{
Hydra_Server_Cert ServerCert;
//
// Validate a proprietory certificate
//
memset( &ServerCert, 0, sizeof( ServerCert ) );
if( !UnpackServerCert(pCanonical->ServerCert.pBlob,
(DWORD)pCanonical->ServerCert.wBlobLen,
&ServerCert) )
{
lsReturn = LICENSE_STATUS_UNSPECIFIED_ERROR;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Now verify the signature on the server certificate
if(!ValidateServerCert(&ServerCert) )
{
lsReturn = LICENSE_STATUS_UNSPECIFIED_ERROR;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
else
{
//
// free any old certificate and remember the new one.
//
if( pContext->pServerCert )
{
FreeProprietaryCertificate( &pContext->pServerCert );
}
lsReturn = LicenseSetCertificate(
( HANDLE )pContext,
&ServerCert );
if( LICENSE_STATUS_OK != lsReturn )
{
LS_LOG_RESULT( lsReturn );
goto ErrorReturn;
}
}
}
else
{
DWORD
fDates = CERT_DATE_DONT_VALIDATE;
//
// X509 certificate
//
//
// this first call finds out the memory required for the public key
//
lsReturn = VerifyCertChain( pCanonical->ServerCert.pBlob,
( DWORD )pCanonical->ServerCert.wBlobLen,
NULL,
&pContext->cbServerPubKey,
&fDates );
if( LICENSE_STATUS_INSUFFICIENT_BUFFER == lsReturn )
{
if( pContext->pbServerPubKey )
{
free( pContext->pbServerPubKey );
}
pContext->pbServerPubKey = malloc( pContext->cbServerPubKey );
if( NULL == pContext->pbServerPubKey )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
lsReturn = VerifyCertChain( pCanonical->ServerCert.pBlob,
( DWORD )pCanonical->ServerCert.wBlobLen,
pContext->pbServerPubKey,
&pContext->cbServerPubKey,
&fDates );
}
if( LICENSE_STATUS_OK != lsReturn )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
}
}
if(pContext->pCryptParam == NULL)
{
lsReturn = LICENSE_STATUS_INITIALIZATION_FAILED;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Copy Server Random to pCryptSystem->rgbServerRandom
memcpy(pContext->pCryptParam->rgbServerRandom, pCanonical->ServerRandom, LICENSE_RANDOM);
LicenseDebugOutput("Server Random : \n");
LS_DUMPSTRING(LICENSE_RANDOM, pContext->pCryptParam->rgbServerRandom);
//Generate 32 byte Client Random
if (!TSRNG_GenerateRandomBits(Random, LICENSE_RANDOM))
{
lsReturn = LICENSE_STATUS_CONTEXT_INITIALIZATION_ERROR;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Copy ClientRandom to pContext->pCryptParam
memcpy(pContext->pCryptParam->rgbClientRandom, Random, LICENSE_RANDOM);
LicenseDebugOutput("Client Random : \n");
LS_DUMPSTRING(LICENSE_RANDOM, pContext->pCryptParam->rgbClientRandom);
//Generate 48 byte long PreMasterSecret
if (!TSRNG_GenerateRandomBits(PreMasterSecret, LICENSE_PRE_MASTER_SECRET))
{
lsReturn = LICENSE_STATUS_CONTEXT_INITIALIZATION_ERROR;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
LicenseDebugOutput("Pre Master Secret : \n");
LS_DUMPSTRING(LICENSE_PRE_MASTER_SECRET, PreMasterSecret);
//Copy Premastersecret to pCryptParam
lsReturn = LicenseSetPreMasterSecret(pContext->pCryptParam, PreMasterSecret);
//Search in the store to find an appropriate License
//To do that, first open the system store.
if( LICENSE_STATUS_OK != (lsReturn = MapStoreError(LSOpenLicenseStore(&hStore, NULL, TRUE))) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Initialize lsIndex structure with the values sent by the Server
lsIndex.dwVersion = pCanonical->ProductInfo.dwVersion;
lsIndex.cbCompany = pCanonical->ProductInfo.cbCompanyName;
if( NULL == (lsIndex.pbCompany = (LPSTR)malloc(lsIndex.cbCompany)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(lsIndex.pbCompany, 0x00, lsIndex.cbCompany);
memcpy(lsIndex.pbCompany, pCanonical->ProductInfo.pbCompanyName, lsIndex.cbCompany);
lsIndex.cbProductID = pCanonical->ProductInfo.cbProductID;
if( NULL == (lsIndex.pbProductID = (LPSTR)malloc(lsIndex.cbProductID)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(lsIndex.pbProductID, 0x00, lsIndex.cbProductID);
memcpy(lsIndex.pbProductID, pCanonical->ProductInfo.pbProductID, lsIndex.cbProductID );
for(dwCount=0; dwCount<pCanonical->ScopeList.dwScopeCount; dwCount ++)
{
DWORD dwProtVer = PREAMBLE_VERSION_1_0;
lsIndex.cbScope = pCanonical->ScopeList.Scopes[dwCount].wBlobLen;
if( NULL == (lsIndex.pbScope = (LPSTR)malloc(lsIndex.cbScope)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
continue;
}
//Initialize pszScope member of the lsIndex with the ith element in the scopelist
memset(lsIndex.pbScope, 0x00, lsIndex.cbScope);
memcpy(lsIndex.pbScope, pCanonical->ScopeList.Scopes[dwCount].pBlob, lsIndex.cbScope);
if( LICENSE_STATUS_OK != (lsReturn = MapStoreError(LSFindLicenseInStore(hStore,
&lsIndex,
&cbData,
NULL))) )
{
if(lsIndex.pbScope)
{
free(lsIndex.pbScope);
lsIndex.pbScope = NULL;
}
continue;
}
//
// NOTE: this line was previously
// if(pContext->dwProtocolVersion != PREAMBLE_VERSION_2_0) for
// Hydra 4.0 clients, which means that a pseudo license will be
// generated for licensing protocol later than 2.0 as well!
// To overcome this problem, Hydra 5.0 server will use the
// PREAMBLE_VERSION_2_0 for Hydra 4.0 clients.
//
if( GET_PREAMBLE_VERSION( pContext->dwProtocolVersion ) < PREAMBLE_VERSION_2_0)
{
if( !GeneratePseudoLicense(&cbData, &pbData) )
{
lsReturn = LICENSE_STATUS_UNSPECIFIED_ERROR;
if(lsIndex.pbScope)
{
free(lsIndex.pbScope);
lsIndex.pbScope = NULL;
}
goto ErrorReturn;
}
lsReturn = LICENSE_STATUS_OK;
if(lsIndex.pbScope)
{
free(lsIndex.pbScope);
lsIndex.pbScope = NULL;
}
break;
}
if(cbData == 0)
{
if(lsIndex.pbScope)
{
free(lsIndex.pbScope);
lsIndex.pbScope = NULL;
}
continue;
}
if( NULL == (pbData=(BYTE FAR *)malloc(cbData)) )
{
if(lsIndex.pbScope)
{
free(lsIndex.pbScope);
lsIndex.pbScope = NULL;
}
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
continue;
}
if( LICENSE_STATUS_OK != (lsReturn = MapStoreError(LSFindLicenseInStore(hStore,
&lsIndex,
&cbData,
pbData))) )
{
if(lsIndex.pbScope)
{
free(lsIndex.pbScope);
lsIndex.pbScope = NULL;
}
continue;
}
LicenseDebugOutput("License Info Data : \n");
LS_DUMPSTRING(cbData, pbData);
lsReturn = LICENSE_STATUS_OK;
if(lsIndex.pbScope)
{
free(lsIndex.pbScope);
lsIndex.pbScope = NULL;
}
break;
}
//If a license is found in the store, then Continue with Hydra_Client_License_Info message
if( LICENSE_STATUS_OK == lsReturn )
{
if( LICENSE_STATUS_CONTINUE != (lsReturn = ClientConstructLicenseInfo(pContext,
pbData,
cbData,
pbMessage,
pcbMessage,
fExtendedError)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
goto CommonReturn;
}
//Else if no license if found, then depending on fNewLicense, either Request for a new license
//or, abort connection
else if(lsReturn == LICENSE_STATUS_NO_LICENSE_ERROR)
{
if(fNewLicense)
{
if( LICENSE_STATUS_CONTINUE != (lsReturn = ClientConstructNewLicenseRequest(pContext,
pbMessage,
pcbMessage,
fExtendedError)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
goto CommonReturn;
}
else //Generate an error message and close connection
{
if( LICENSE_STATUS_CLIENT_ABORT != (lsReturn = ClientConstructErrorAlert(pContext,
GM_HC_ERR_NO_LICENSE,
ST_TOTAL_ABORT,
NULL,
0,
pbMessage,
pcbMessage,
fExtendedError
)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
}
}
LS_LOG_RESULT(lsReturn);
CommonReturn:
//
// close license store
//
if( hStore )
{
LSCloseLicenseStore(hStore);
hStore = NULL;
}
if(pbData)
{
free(pbData);
pbData = NULL;
}
if(lsIndex.pbCompany)
{
free(lsIndex.pbCompany);
lsIndex.pbCompany = NULL;
}
if(lsIndex.pbProductID)
{
free(lsIndex.pbProductID);
lsIndex.pbProductID = NULL;
}
if(lsIndex.pbScope)
{
free(lsIndex.pbScope);
lsIndex.pbScope = NULL;
}
return lsReturn;
//LS_RETURN(lsReturn);
ErrorReturn:
*pcbMessage = 0;
if( pContext != NULL)
{
if(pContext->pServerCert)
{
free(pContext->pServerCert);
pContext->pServerCert = NULL;
}
if( pContext->pbServerPubKey )
{
free( pContext->pbServerPubKey );
pContext->pbServerPubKey = NULL;
}
}
goto CommonReturn;
}
LICENSE_STATUS
CALL_TYPE
LicenseClientHandleServerPlatformChallenge(
PLicense_Client_Context pContext,
PHydra_Server_Platform_Challenge pCanonical,
BYTE FAR * pbMessage,
DWORD FAR * pcbMessage,
BOOL fExtendedError
)
{
LICENSE_STATUS lsReturn = LICENSE_STATUS_OK;
Hydra_Client_Platform_Challenge_Response Response;
BYTE MACData[LICENSE_MAC_DATA];
HWID hwid;
BYTE FAR * pbData = NULL;
UCHAR * LocalBuf = NULL;
DWORD cbData = 0;
LS_BEGIN(TEXT("LicenseClientHandleServerPlatformChallenge"));
if( (pContext == NULL) || (pCanonical == NULL) || (pcbMessage == NULL) )
{
lsReturn = LICENSE_STATUS_INVALID_INPUT;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(&Response, 0x00, sizeof(Hydra_Client_Platform_Challenge_Response));
if( (pContext->dwState != LICENSE_CLIENT_STATE_LICENSE_RESPONSE) &&
(pContext->dwState != LICENSE_CLIENT_STATE_NEW_LICENSE_REQUEST) )
{
lsReturn = LICENSE_STATUS_INVALID_CLIENT_STATE;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//First decrypt the encrypted platform challenge
if( LICENSE_STATUS_OK != (lsReturn = LicenseDecryptSessionData(pContext->pCryptParam,
pCanonical->EncryptedPlatformChallenge.pBlob,
(DWORD)pCanonical->EncryptedPlatformChallenge.wBlobLen)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Generate the MAC with the decrypted platform Challenge
if( LICENSE_STATUS_OK != (lsReturn = LicenseGenerateMAC(pContext->pCryptParam,
pCanonical->EncryptedPlatformChallenge.pBlob,
(DWORD)pCanonical->EncryptedPlatformChallenge.wBlobLen,
MACData
)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
LicenseDebugOutput(" Client generated MAC data to verify Server's message Authenticity : \n");
LS_DUMPSTRING(LICENSE_MAC_DATA, MACData);
//Compare the generated MAC with the one sent by the server
if( memcmp(MACData, pCanonical->MACData, LICENSE_MAC_DATA) )
{
lsReturn = LICENSE_STATUS_INVALID_MAC_DATA;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Generate Platform Challenge Response
if( LICENSE_STATUS_OK != (lsReturn = ClientGenerateChallengeResponse(pContext,
&pCanonical->EncryptedPlatformChallenge,
&Response.EncryptedChallengeResponse)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Generate HWID, Encrypt it using the Session key and put it in the Response
memset(&hwid, 0x00, sizeof(HWID));
if( LICENSE_STATUS_OK != (lsReturn = GenerateClientHWID(&hwid)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//GenerateClientHWID(&hwid);
LicenseDebugOutput("HWID in byte : \n");
LS_DUMPSTRING(sizeof(HWID), (BYTE FAR *)&hwid);
Response.EncryptedHWID.wBlobType = BB_DATA_BLOB;
Response.EncryptedHWID.wBlobLen = sizeof(HWID);
if( NULL == (Response.EncryptedHWID.pBlob = (BYTE FAR *)malloc(Response.EncryptedHWID.wBlobLen)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(Response.EncryptedHWID.pBlob, 0x00, Response.EncryptedHWID.wBlobLen);
memcpy(Response.EncryptedHWID.pBlob, &hwid, Response.EncryptedHWID.wBlobLen);
if( NULL == (LocalBuf = (UCHAR *)malloc(Response.EncryptedChallengeResponse.wBlobLen +
Response.EncryptedHWID.wBlobLen)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
cbData += Response.EncryptedChallengeResponse.wBlobLen;
memcpy(LocalBuf, Response.EncryptedChallengeResponse.pBlob, Response.EncryptedChallengeResponse.wBlobLen);
memcpy(LocalBuf + cbData, Response.EncryptedHWID.pBlob, Response.EncryptedHWID.wBlobLen);
cbData += Response.EncryptedHWID.wBlobLen;
//Generate MACData and put it in the Response
if( LICENSE_STATUS_OK != (lsReturn = LicenseGenerateMAC(pContext->pCryptParam,
LocalBuf,
cbData,
Response.MACData)) )
{
free(LocalBuf);
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
free(LocalBuf);
//Now encrypt the platform challenge response using the negotiated session key
if( LICENSE_STATUS_OK != (lsReturn = LicenseEncryptSessionData(pContext->pCryptParam,
Response.EncryptedChallengeResponse.pBlob,
Response.EncryptedChallengeResponse.wBlobLen
)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Encrypt the HWID with generated session key
if( LICENSE_STATUS_OK != (lsReturn = LicenseEncryptSessionData(pContext->pCryptParam,
Response.EncryptedHWID.pBlob,
(DWORD)Response.EncryptedHWID.wBlobLen)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Now we have our Platform challenge Response Ready. Pack the data in a byte stream
if( LICENSE_STATUS_OK != (lsReturn = PackHydraClientPlatformChallengeResponse(&Response,
fExtendedError,
pbMessage,
pcbMessage)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
// Set appropriate state and data in proper places
//Set the MACData in the CryptSystem MAC buffer.
memcpy(pContext->rgbMACData, Response.MACData, LICENSE_MAC_DATA);
//Set the state of the context to LICENSE_CLIENT_STATE_PLATFORM_CHALLENGE_RESPONSE
//provided data was written in the output. i.e pbMessage is not NULL
if(pbMessage)
pContext->dwState = LICENSE_CLIENT_STATE_PLATFORM_CHALLENGE_RESPONSE;
//Copy the whole message to the context
pContext->cbLastMessage = *pcbMessage;
if(pbMessage)
{
if( pContext->pbLastMessage )
{
free( pContext->pbLastMessage );
}
if( NULL == (pContext->pbLastMessage = (BYTE FAR *)malloc(pContext->cbLastMessage)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(pContext->pbLastMessage, 0x00, pContext->cbLastMessage);
memcpy(pContext->pbLastMessage, pbMessage, pContext->cbLastMessage);
}
lsReturn = LICENSE_STATUS_CONTINUE;
LS_LOG_RESULT(lsReturn);
CommonReturn:
//LICENSE_LOG_RESULT(lsReturn);
if(Response.EncryptedChallengeResponse.pBlob)
{
free(Response.EncryptedChallengeResponse.pBlob);
Response.EncryptedChallengeResponse.pBlob = NULL;
}
if(Response.EncryptedHWID.pBlob)
{
free(Response.EncryptedHWID.pBlob);
Response.EncryptedHWID.pBlob = NULL;
}
return lsReturn;
//LS_RETURN(lsReturn);
ErrorReturn:
*pcbMessage = 0;
goto CommonReturn;
}
LICENSE_STATUS
CALL_TYPE
LicenseClientHandleNewLicense(
PLicense_Client_Context pContext,
PHydra_Server_New_License pCanonical,
BOOL fNew,
BYTE FAR * pbMessage,
DWORD FAR * pcbMessage
)
{
LICENSE_STATUS lsReturn = LICENSE_STATUS_OK;
New_License_Info NewLicense;
BYTE MACData[LICENSE_MAC_DATA];
Binary_Blob bbData;
LSINDEX lsIndex;
HANDLE hStore = NULL;
LS_BEGIN(TEXT("LicenseClientHandleNewLicense"));
if(NULL == pContext || NULL == pCanonical )
{
lsReturn = LICENSE_STATUS_INVALID_INPUT;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(&bbData, 0x00, sizeof(Binary_Blob));
memset(&NewLicense, 0x00, sizeof(New_License_Info));
memset(&lsIndex, 0x00, sizeof(LSINDEX));
//First decrypt the encrypted license info
if( LICENSE_STATUS_OK != (lsReturn = LicenseDecryptSessionData(pContext->pCryptParam,
pCanonical->EncryptedNewLicenseInfo.pBlob,
( DWORD )( pCanonical->EncryptedNewLicenseInfo.wBlobLen ))) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Generate the MAC data with the decrypted data
if( LICENSE_STATUS_OK != (lsReturn = LicenseGenerateMAC(pContext->pCryptParam,
pCanonical->EncryptedNewLicenseInfo.pBlob,
(DWORD)pCanonical->EncryptedNewLicenseInfo.wBlobLen,
MACData)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Compare this MAC with the one sent by the Server.
if(memcmp(MACData, pCanonical->MACData, LICENSE_MAC_DATA))
{
lsReturn = LICENSE_STATUS_INVALID_MAC_DATA;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
if( LICENSE_STATUS_OK != (lsReturn = UnpackNewLicenseInfo(pCanonical->EncryptedNewLicenseInfo.pBlob,
(DWORD)pCanonical->EncryptedNewLicenseInfo.wBlobLen,
&NewLicense)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Try to open the system license store
if( LICENSE_STATUS_OK != (lsReturn = MapStoreError(LSOpenLicenseStore(&hStore, NULL, FALSE))) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Initialize the LSINDEX structure. This structure will be used to add/replace a license in the store
//To do that, first initialize version info
lsIndex.dwVersion = NewLicense.dwVersion;
//Initialize Scope info
lsIndex.cbScope = NewLicense.cbScope;
if( NULL == (lsIndex.pbScope = (LPSTR)malloc(lsIndex.cbScope)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(lsIndex.pbScope, 0x00, lsIndex.cbScope);
memcpy(lsIndex.pbScope, NewLicense.pbScope, lsIndex.cbScope);
//Initialize CompanyName info
lsIndex.cbCompany = NewLicense.cbCompanyName;
if( NULL == (lsIndex.pbCompany = (LPSTR)malloc(lsIndex.cbCompany)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(lsIndex.pbCompany, 0x00, lsIndex.cbCompany);
memcpy(lsIndex.pbCompany, NewLicense.pbCompanyName, lsIndex.cbCompany);
//Initialize ProductID info
lsIndex.cbProductID = NewLicense.cbProductID;
if( NULL == (lsIndex.pbProductID = (LPSTR)malloc(lsIndex.cbProductID)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(lsIndex.pbProductID, 0x00, lsIndex.cbProductID);
memcpy(lsIndex.pbProductID, NewLicense.pbProductID, lsIndex.cbProductID);
LS_LOG_RESULT(lsReturn);
if( LICENSE_STATUS_OK != (lsReturn = LSAddLicenseToStore(hStore,
LS_REPLACE_LICENSE_OK,
&lsIndex,
NewLicense.pbLicenseInfo,
NewLicense.cbLicenseInfo
)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Update state info and inform that the License Verification is over and the client can carry on
//with further connection!
pContext->dwState = LICENSE_CLIENT_STATE_DONE;
memset(pContext->rgbMACData, 0x00, LICENSE_MAC_DATA);
//Reset the last send message to 0;
if(pContext->pbLastMessage)
{
memset(pContext->pbLastMessage, 0x00, pContext->cbLastMessage);
free(pContext->pbLastMessage);
pContext->pbLastMessage = NULL;
}
pContext->cbLastMessage = 0;
lsReturn = LICENSE_STATUS_OK;
CommonReturn:
if( hStore )
{
LSCloseLicenseStore( hStore );
}
if(NewLicense.pbScope)
{
free(NewLicense.pbScope);
NewLicense.pbScope = NULL;
}
if(NewLicense.pbCompanyName)
{
free(NewLicense.pbCompanyName);
NewLicense.pbCompanyName = NULL;
}
if(NewLicense.pbProductID)
{
free(NewLicense.pbProductID);
NewLicense.pbProductID = NULL;
}
if(NewLicense.pbLicenseInfo)
{
free(NewLicense.pbLicenseInfo);
NewLicense.pbLicenseInfo = NULL;
}
if(lsIndex.pbScope)
{
free(lsIndex.pbScope);
lsIndex.pbScope = NULL;
}
if(lsIndex.pbCompany)
{
free(lsIndex.pbCompany);
lsIndex.pbCompany = NULL;
}
if(lsIndex.pbProductID)
{
free(lsIndex.pbProductID);
lsIndex.pbProductID = NULL;
}
if(bbData.pBlob)
{
free(bbData.pBlob);
bbData.pBlob = NULL;
}
return lsReturn;
ErrorReturn:
goto CommonReturn;
}
LICENSE_STATUS
CALL_TYPE
ClientConstructLicenseInfo(
PLicense_Client_Context pContext,
BYTE FAR * pbInput,
DWORD cbInput,
BYTE FAR * pbOutput,
DWORD FAR * pcbOutput,
BOOL fExtendedError
)
{
LICENSE_STATUS lsReturn = LICENSE_STATUS_OK;
Hydra_Client_License_Info Canonical;
HWID hwid;
Binary_Blob bbPreMasterSecret;
DWORD dwSize = 0;
DWORD dwState = 0;
PBYTE pbServerPubKey;
DWORD cbServerPubKey;
LS_BEGIN(TEXT("ClientContstructLicenseInfo"));
if(NULL == pContext || NULL == pcbOutput)
{
lsReturn = LICENSE_STATUS_INVALID_INPUT;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Construct the messages
bbPreMasterSecret.wBlobType = BB_RANDOM_BLOB;
bbPreMasterSecret.wBlobLen = LICENSE_PRE_MASTER_SECRET;
if( NULL == (bbPreMasterSecret.pBlob = (BYTE FAR *)malloc(LICENSE_PRE_MASTER_SECRET)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memcpy(bbPreMasterSecret.pBlob, pContext->pCryptParam->rgbPreMasterSecret, LICENSE_PRE_MASTER_SECRET);
memset(&Canonical, 0x00, sizeof(Hydra_Client_License_Info));
//RSA is hardcoded for the time being
Canonical.dwPrefKeyExchangeAlg = pContext->pCryptParam->dwKeyExchAlg;
#ifdef OS_WINCE
Canonical.dwPlatformID = CLIENT_OS_ID_OTHER | CLIENT_IMAGE_ID_MICROSOFT;
#else // WinNT or Win9x
{
DWORD dwVersion = GetVersion();
if (dwVersion & 0x80000000) {
// Win95
Canonical.dwPlatformID = CLIENT_OS_ID_OTHER | CLIENT_IMAGE_ID_MICROSOFT;
} else {
OSVERSIONINFOEX ovix;
BOOL b;
ovix.dwOSVersionInfoSize = sizeof(ovix);
b = GetVersionEx((LPOSVERSIONINFO) &ovix);
if(b && ((ovix.wSuiteMask & VER_SUITE_EMBEDDEDNT) || (ovix.wSuiteMask & VER_SUITE_PERSONAL)))
{
Canonical.dwPlatformID = CLIENT_OS_ID_WINNT_40 | CLIENT_IMAGE_ID_MICROSOFT;
}
else
{
// WinNT
Canonical.dwPlatformID = CLIENT_IMAGE_ID_MICROSOFT |
((((DWORD)(LOBYTE(LOWORD(dwVersion)))) - 2) << 24);
Canonical.dwPlatformID |= (DWORD)(HIBYTE(LOWORD(dwVersion)));
}
}
}
#endif
//ClientRandom
memcpy(Canonical.ClientRandom, pContext->pCryptParam->rgbClientRandom, LICENSE_RANDOM);
if( pContext->pServerCert )
{
//
// This public key is used for pre-Hydra 5.0 servers that are using proprietory
// server certificates.
//
pbServerPubKey = pContext->pServerCert->PublicKeyData.pBlob;
cbServerPubKey = pContext->pServerCert->PublicKeyData.wBlobLen;
}
else
{
pbServerPubKey = pContext->pbServerPubKey;
cbServerPubKey = pContext->cbServerPubKey;
}
//We have to switch here depending on the key exchange algorithm to be used -Shubho
if( LICENSE_STATUS_OK != (lsReturn = LicenseEnvelopeData(pbServerPubKey,
cbServerPubKey,
bbPreMasterSecret.pBlob,
bbPreMasterSecret.wBlobLen,
NULL,
&dwSize)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
if( NULL == (Canonical.EncryptedPreMasterSecret.pBlob = (BYTE FAR *)malloc(dwSize)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(Canonical.EncryptedPreMasterSecret.pBlob, 0x00, dwSize);
if( LICENSE_STATUS_OK != (lsReturn = LicenseEnvelopeData(pbServerPubKey,
cbServerPubKey,
bbPreMasterSecret.pBlob,
bbPreMasterSecret.wBlobLen,
Canonical.EncryptedPreMasterSecret.pBlob,
&dwSize)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
Canonical.EncryptedPreMasterSecret.wBlobLen = (WORD)dwSize;
//Fill up LicenseInfo buffer
Canonical.LicenseInfo.wBlobType = BB_DATA_BLOB;
Canonical.LicenseInfo.wBlobLen = (WORD)cbInput;
if( NULL == (Canonical.LicenseInfo.pBlob = (BYTE FAR *)malloc(Canonical.LicenseInfo.wBlobLen)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(Canonical.LicenseInfo.pBlob, 0x00, Canonical.LicenseInfo.wBlobLen);
memcpy(Canonical.LicenseInfo.pBlob, pbInput, Canonical.LicenseInfo.wBlobLen);
//Generate HWID and put the data in a binary_blob to encrypt
memset(&hwid, 0x00, sizeof(HWID));
if( LICENSE_STATUS_OK != (lsReturn = GenerateClientHWID(&hwid)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
Canonical.EncryptedHWID.wBlobType = BB_DATA_BLOB;
Canonical.EncryptedHWID.wBlobLen = sizeof(HWID);
if( NULL == (Canonical.EncryptedHWID.pBlob = (BYTE FAR *)malloc(Canonical.EncryptedHWID.wBlobLen)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(Canonical.EncryptedHWID.pBlob, 0x00, Canonical.EncryptedHWID.wBlobLen);
memcpy(Canonical.EncryptedHWID.pBlob, &hwid, Canonical.EncryptedHWID.wBlobLen);
dwState = pContext->pCryptParam->dwCryptState;
//Generate the session key and MACsalt
if( LICENSE_STATUS_OK != (lsReturn = LicenseBuildMasterSecret(pContext->pCryptParam)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
if( LICENSE_STATUS_OK != (lsReturn = LicenseMakeSessionKeys(pContext->pCryptParam, 0)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Encrypt the HWID with generated session key
if( LICENSE_STATUS_OK != (lsReturn = LicenseEncryptSessionData(pContext->pCryptParam,
Canonical.EncryptedHWID.pBlob,
(DWORD)Canonical.EncryptedHWID.wBlobLen)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Generate the MAC with original HWID
LicenseGenerateMAC(pContext->pCryptParam, ( BYTE FAR * )&hwid, sizeof(hwid), Canonical.MACData);
//Now everything is ready, so pack the data
if( LICENSE_STATUS_OK != (lsReturn = PackHydraClientLicenseInfo(&Canonical, fExtendedError, pbOutput, pcbOutput)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Set the MACData in the CryptSystem MAC buffer.
memcpy(pContext->rgbMACData, Canonical.MACData, LICENSE_MAC_DATA);
//Set the state of the context to LICENSE_CLIENT_STATE_LICENSE_RESPONSE
//if any output data is written. i.e. pbOutput is not null. Also revert back
//the crypparam state as this will also be called twice and we change the state
//only when we have written something in the output!!!!! - bad!!!!!
if(pbOutput)
{
pContext->dwState = LICENSE_CLIENT_STATE_LICENSE_RESPONSE;
}
else //Restore earlier CryptSystem States
{
pContext->pCryptParam->dwCryptState = dwState;
memcpy(pContext->pCryptParam->rgbPreMasterSecret, bbPreMasterSecret.pBlob, LICENSE_PRE_MASTER_SECRET);
memset(pContext->pCryptParam->rgbSessionKey, 0x00, LICENSE_SESSION_KEY);
memset(pContext->pCryptParam->rgbMACSaltKey, 0x00, LICENSE_MAC_WRITE_KEY);
}
//Copy the whole message to the context
pContext->cbLastMessage = *pcbOutput;
if(pbOutput)
{
if( pContext->pbLastMessage )
{
free( pContext->pbLastMessage );
}
if( NULL == (pContext->pbLastMessage = (BYTE FAR *)malloc(pContext->cbLastMessage)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
goto ErrorReturn;
}
memset(pContext->pbLastMessage, 0x00, pContext->cbLastMessage);
memcpy(pContext->pbLastMessage, pbOutput, pContext->cbLastMessage);
}
lsReturn = LICENSE_STATUS_CONTINUE;
LS_LOG_RESULT(lsReturn);
CommonReturn:
if(Canonical.EncryptedPreMasterSecret.pBlob)
{
free(Canonical.EncryptedPreMasterSecret.pBlob);
Canonical.EncryptedPreMasterSecret.pBlob = NULL;
}
if(Canonical.LicenseInfo.pBlob)
{
free(Canonical.LicenseInfo.pBlob);
Canonical.LicenseInfo.pBlob = NULL;
}
if(Canonical.EncryptedHWID.pBlob)
{
free(Canonical.EncryptedHWID.pBlob);
Canonical.EncryptedHWID.pBlob = NULL;
}
if(bbPreMasterSecret.pBlob)
{
free(bbPreMasterSecret.pBlob);
bbPreMasterSecret.pBlob = NULL;
}
return lsReturn;
// LS_RETURN(lsReturn);
ErrorReturn:
*pcbOutput = 0;
goto CommonReturn;
}
LICENSE_STATUS
CALL_TYPE
ClientConstructNewLicenseRequest(
PLicense_Client_Context pContext,
BYTE FAR * pbOutput,
DWORD FAR * pcbOutput,
BOOL fExtendedError
)
{
LICENSE_STATUS lsReturn = LICENSE_STATUS_OK;
Hydra_Client_New_License_Request Request;
Binary_Blob bbPreMasterSecret;
DWORD dwSize = 0;
DWORD dwState = 0;
#ifdef OS_WINCE
#define LS_MAX(a,b) ((a) > (b) ? (a) : (b))
BYTE szUserName[LS_MAX((UNLEN + 1),HWID_STR_LEN)];
DWORD cbUserName = sizeof(szUserName);
BYTE szMachineName[LS_MAX(MAX_COMPUTERNAME_LENGTH + 1,HWID_STR_LEN)];
DWORD cbMachineName = sizeof(szMachineName);
#else
BYTE szUserName[(UNLEN + 1) * sizeof(TCHAR)];
DWORD cbUserName = UNLEN + 1;
BYTE szMachineName[(MAX_COMPUTERNAME_LENGTH + 1) * sizeof(TCHAR)];
DWORD cbMachineName = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(TCHAR);
#endif
PBYTE pbServerPubKey;
DWORD cbServerPubKey;
LS_BEGIN(TEXT("ClientConstructNewLicenseRequest"));
if(NULL == pContext)
{
lsReturn = LICENSE_STATUS_INVALID_INPUT;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(szUserName,0,sizeof(szUserName));
memset(szMachineName,0,sizeof(szMachineName));
dwState = pContext->pCryptParam->dwCryptState;
bbPreMasterSecret.wBlobType = BB_RANDOM_BLOB;
bbPreMasterSecret.wBlobLen = LICENSE_PRE_MASTER_SECRET;
if( NULL == (bbPreMasterSecret.pBlob = (BYTE FAR *)malloc(LICENSE_PRE_MASTER_SECRET)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memcpy(bbPreMasterSecret.pBlob, pContext->pCryptParam->rgbPreMasterSecret, LICENSE_PRE_MASTER_SECRET);
//Initialize the message
memset(&Request, 0x00, sizeof(Hydra_Client_New_License_Request));
//RSA is hardcoded for the time being
Request.dwPrefKeyExchangeAlg = pContext->pCryptParam->dwKeyExchAlg;
//PlatformID
#ifdef OS_WINCE
Request.dwPlatformID = CLIENT_OS_ID_OTHER | CLIENT_IMAGE_ID_MICROSOFT;
#else // WinNT or Win9x
{
DWORD dwVersion = GetVersion();
if (dwVersion & 0x80000000) {
// Win95
Request.dwPlatformID = CLIENT_OS_ID_OTHER | CLIENT_IMAGE_ID_MICROSOFT;
} else {
OSVERSIONINFOEX ovix;
BOOL b;
ovix.dwOSVersionInfoSize = sizeof(ovix);
b = GetVersionEx((LPOSVERSIONINFO) &ovix);
if(b && ((ovix.wSuiteMask & VER_SUITE_EMBEDDEDNT) || (ovix.wSuiteMask & VER_SUITE_PERSONAL)))
{
Request.dwPlatformID = CLIENT_OS_ID_WINNT_40 | CLIENT_IMAGE_ID_MICROSOFT;
}
else
{
// WinNT
Request.dwPlatformID = CLIENT_IMAGE_ID_MICROSOFT |
((((DWORD)(LOBYTE(LOWORD(dwVersion)))) - 2) << 24);
}
}
}
#endif
//Copy ClientRandom
memcpy(Request.ClientRandom, pContext->pCryptParam->rgbClientRandom, LICENSE_RANDOM);
//Encrypt the Premastersecret using Server's Public key
//We have to switch here depending on the key exchange algorithm to be used -Shubho
if( pContext->pServerCert )
{
//
// This public key is used for pre-Hydra 5.0 servers that are using proprietory
// server certificates.
//
pbServerPubKey = pContext->pServerCert->PublicKeyData.pBlob;
cbServerPubKey = pContext->pServerCert->PublicKeyData.wBlobLen;
}
else
{
pbServerPubKey = pContext->pbServerPubKey;
cbServerPubKey = pContext->cbServerPubKey;
}
if( LICENSE_STATUS_OK != (lsReturn = LicenseEnvelopeData(pbServerPubKey,
cbServerPubKey,
bbPreMasterSecret.pBlob,
bbPreMasterSecret.wBlobLen,
NULL,
&dwSize)) )
{
#if DBG
OutputDebugString(_T("LicenseEnvelopeData failed"));
LS_LOG_RESULT(lsReturn);
#endif
goto ErrorReturn;
}
if( NULL == (Request.EncryptedPreMasterSecret.pBlob = (BYTE FAR *)malloc(dwSize)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(Request.EncryptedPreMasterSecret.pBlob, 0x00, dwSize);
if( LICENSE_STATUS_OK != (lsReturn = LicenseEnvelopeData(pbServerPubKey,
cbServerPubKey,
bbPreMasterSecret.pBlob,
bbPreMasterSecret.wBlobLen,
Request.EncryptedPreMasterSecret.pBlob,
&dwSize)) )
{
#if DBG
OutputDebugString(_T("LicenseEnvelopeData failed"));
LS_LOG_RESULT(lsReturn);
#endif
goto ErrorReturn;
}
Request.EncryptedPreMasterSecret.wBlobLen = (WORD)dwSize;
//
// initialize the user name binary blob
//
#if !defined(OS_WINCE)
GetUserName( (LPTSTR)szUserName, &cbUserName );
#elif defined(OS_WINCE)
GetUserName( (LPSTR)szUserName, &cbUserName );
#endif //OS_WINCE
Request.ClientUserName.wBlobType = BB_CLIENT_USER_NAME_BLOB;
Request.ClientUserName.wBlobLen = ( WORD )cbUserName;
Request.ClientUserName.pBlob = szUserName;
//
// initialize the machine name binary blob
//
#if defined(OS_WINCE)
GetComputerName( (LPSTR)szMachineName, &cbMachineName );
#else
GetComputerName( (LPTSTR)szMachineName, &cbMachineName );
#endif
Request.ClientMachineName.wBlobType = BB_CLIENT_MACHINE_NAME_BLOB;
Request.ClientMachineName.wBlobLen = ( WORD )cbMachineName + 1;
Request.ClientMachineName.pBlob = szMachineName;
//New License Request is ready. Now pack the data,
if( LICENSE_STATUS_OK != (lsReturn = PackHydraClientNewLicenseRequest(&Request,
fExtendedError,
pbOutput,
pcbOutput)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Anyway Generate the session key and MACsalt for future use
if( LICENSE_STATUS_OK != (lsReturn = LicenseBuildMasterSecret(pContext->pCryptParam)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
if( LICENSE_STATUS_OK != (lsReturn = LicenseMakeSessionKeys(pContext->pCryptParam, 0)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Set the MACData in the CryptSystem MAC buffer.
memset(pContext->rgbMACData, 0x00, LICENSE_MAC_DATA);
//Set the state of the context to LICENSE_CLIENT_STATE_NEW_LICENSE_REQUEST
//if something is written on the output. i.e. pbOutput is not NULL
if(pbOutput)
{
pContext->dwState = LICENSE_CLIENT_STATE_LICENSE_RESPONSE;
}
else //Restore earlier CryptSystem States
{
pContext->pCryptParam->dwCryptState = dwState;
memcpy(pContext->pCryptParam->rgbPreMasterSecret, bbPreMasterSecret.pBlob, LICENSE_PRE_MASTER_SECRET);
memset(pContext->pCryptParam->rgbSessionKey, 0x00, LICENSE_SESSION_KEY);
memset(pContext->pCryptParam->rgbMACSaltKey, 0x00, LICENSE_MAC_WRITE_KEY);
}
//Copy the whole message to the context
pContext->cbLastMessage = *pcbOutput;
if(pbOutput)
{
if( pContext->pbLastMessage )
{
free( pContext->pbLastMessage );
}
if( NULL == (pContext->pbLastMessage = (BYTE FAR *)malloc(pContext->cbLastMessage)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(pContext->pbLastMessage, 0x00, pContext->cbLastMessage);
memcpy(pContext->pbLastMessage, pbOutput, pContext->cbLastMessage);
}
lsReturn = LICENSE_STATUS_CONTINUE;
LS_LOG_RESULT(lsReturn);
CommonReturn:
if(bbPreMasterSecret.pBlob)
{
free(bbPreMasterSecret.pBlob);
bbPreMasterSecret.pBlob = NULL;
}
if( Request.EncryptedPreMasterSecret.pBlob )
{
free( Request.EncryptedPreMasterSecret.pBlob );
}
return lsReturn;
//LS_RETURN(lsReturn);
ErrorReturn:
*pcbOutput = 0;
goto CommonReturn;
}
LICENSE_STATUS
CALL_TYPE
ClientConstructErrorAlert(
PLicense_Client_Context pContext,
DWORD dwErrorCode,
DWORD dwStateTransition,
BYTE FAR * pbErrorInfo,
DWORD cbErrorInfo,
BYTE FAR * pbOutput,
DWORD FAR * pcbOutput,
BOOL fExtendedError
)
{
LICENSE_STATUS lsReturn = LICENSE_STATUS_OK;
License_Error_Message Error;
LS_BEGIN(TEXT("ClientConstructErrorAlert\n"));
if(NULL == pContext)
{
lsReturn = LICENSE_STATUS_INVALID_INPUT;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(&Error, 0x00, sizeof(License_Error_Message));
Error.dwErrorCode = dwErrorCode;
Error.dwStateTransition = dwStateTransition;
Error.bbErrorInfo.wBlobType = BB_ERROR_BLOB;
Error.bbErrorInfo.wBlobLen = (WORD)cbErrorInfo;
if(Error.bbErrorInfo.wBlobLen>0)
{
if( NULL == (Error.bbErrorInfo.pBlob = (BYTE FAR *)malloc(Error.bbErrorInfo.wBlobLen)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(Error.bbErrorInfo.pBlob, 0x00, Error.bbErrorInfo.wBlobLen);
memcpy(Error.bbErrorInfo.pBlob, pbErrorInfo, Error.bbErrorInfo.wBlobLen);
}
else
Error.bbErrorInfo.pBlob = NULL;
if( LICENSE_STATUS_OK != (lsReturn = PackLicenseErrorMessage(&Error,
fExtendedError,
pbOutput,
pcbOutput)) )
{
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//Set the MACData in the CryptSystem MAC buffer.
memset(pContext->rgbMACData, 0x00, LICENSE_MAC_DATA);
//Set the state of the context to LICENSE_CLIENT_STATE_ABORT;
switch(dwStateTransition)
{
case ST_TOTAL_ABORT:
pContext->dwState = LICENSE_CLIENT_STATE_ABORT;
lsReturn = LICENSE_STATUS_CLIENT_ABORT;
pContext->cbLastMessage = 0;
break;
case ST_NO_TRANSITION:
lsReturn = LICENSE_STATUS_CONTINUE;
pContext->cbLastMessage = *pcbOutput;
if(pbOutput)
{
if( pContext->pbLastMessage )
{
free( pContext->pbLastMessage );
}
if( NULL == (pContext->pbLastMessage = (BYTE FAR *)malloc(pContext->cbLastMessage)) )
{
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
memset(pContext->pbLastMessage, 0x00, pContext->cbLastMessage);
memcpy(pContext->pbLastMessage, pbOutput, pContext->cbLastMessage);
}
break;
case ST_RESET_PHASE_TO_START:
lsReturn = LICENSE_STATUS_CONTINUE;
if( (pContext->dwState == LICENSE_CLIENT_STATE_LICENSE_RESPONSE) ||
(pContext->dwState == LICENSE_CLIENT_STATE_NEW_LICENSE_REQUEST) )
{
pContext->dwState = LICENSE_CLIENT_STATE_WAIT_SERVER_HELLO;
}
else if(pContext->dwState == LICENSE_CLIENT_STATE_PLATFORM_CHALLENGE_RESPONSE)
{
pContext->dwState = LICENSE_CLIENT_STATE_NEW_LICENSE_REQUEST;
}
break;
case ST_RESEND_LAST_MESSAGE:
lsReturn = LICENSE_STATUS_CONTINUE;
break;
}
LS_LOG_RESULT(lsReturn);
CommonReturn:
if(Error.bbErrorInfo.pBlob)
{
free(Error.bbErrorInfo.pBlob);
Error.bbErrorInfo.pBlob = NULL;
}
return lsReturn;
//LS_RETURN(lsReturn);
ErrorReturn:
*pcbOutput = 0;
goto CommonReturn;
}
LICENSE_STATUS
CALL_TYPE
ClientGenerateChallengeResponse(
PLicense_Client_Context pContext,
PBinary_Blob pChallengeData,
PBinary_Blob pResponseData
)
{
LICENSE_STATUS lsReturn = LICENSE_STATUS_OK;
PPlatformChallengeResponseData pbChallengeResponse = NULL;
WORD cbChallengeResponse;
LS_BEGIN(TEXT("ClientGenerateChallengeResponse"));
//For the time being we will send back the same data. But we have to finalize on the challenge
//response generation algorithm as soon as possible - Shubho
if( (pContext == NULL) || (pChallengeData == NULL) || (pResponseData == NULL) )
{
lsReturn = LICENSE_STATUS_INVALID_INPUT;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
pResponseData->wBlobType = BB_DATA_BLOB;
//
// Determine how much memory we need to allocate, PlatformChallenge* is a variable length
// structure.
//
cbChallengeResponse = (WORD)OFFSET_OF(PlatformChallengeResponseData, pbChallenge) + pChallengeData->wBlobLen;
ASSERT(cbChallengeResponse <= PLATFORM_CHALLENGE_LENGTH);
if(cbChallengeResponse > PLATFORM_CHALLENGE_LENGTH)
{
lsReturn = LICENSE_STATUS_INVALID_INPUT;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
pbChallengeResponse = (PPlatformChallengeResponseData)malloc(cbChallengeResponse);
if( NULL == pbChallengeResponse )
{
// can't allocate memory
lsReturn = LICENSE_STATUS_OUT_OF_MEMORY;
LS_LOG_RESULT(lsReturn);
goto ErrorReturn;
}
//
// Setup challenge response data,
//
pbChallengeResponse->wVersion = CURRENT_PLATFORMCHALLENGE_VERSION;
#ifdef OS_WINCE
pbChallengeResponse->wClientType = WINCE_PLATFORMCHALLENGE_TYPE;
pbChallengeResponse->wLicenseDetailLevel = LICENSE_DETAIL_DETAIL;
#else
//
// We only need one Win32 type since we already have dwPlatformID to differentiate Win98/NT
// Note, we set license detail level in #define just in case platform can't handle amount
// of data set back by license server
//
pbChallengeResponse->wClientType = WIN32_PLATFORMCHALLENGE_TYPE;
pbChallengeResponse->wLicenseDetailLevel = LICENSE_DETAIL_DETAIL;
#endif
if( (pChallengeData->pBlob != NULL) && (pChallengeData->wBlobLen >0) )
{
pbChallengeResponse->cbChallenge = pChallengeData->wBlobLen;
memcpy(
(PBYTE)pbChallengeResponse + OFFSET_OF(PlatformChallengeResponseData, pbChallenge),
pChallengeData->pBlob,
pChallengeData->wBlobLen
);
}
else
{
// server didn't send us any challenge data.
pbChallengeResponse->cbChallenge = 0;
}
pResponseData->wBlobLen = cbChallengeResponse;
pResponseData->pBlob = (BYTE FAR *)pbChallengeResponse;
lsReturn = LICENSE_STATUS_OK;
LS_LOG_RESULT(lsReturn);
CommonReturn:
//LS_RETURN(lsReturn);
return lsReturn;
ErrorReturn:
goto CommonReturn;
}
static BOOL GeneratePseudoLicense(
DWORD FAR * pcbNewLicense,
LPBYTE FAR *ppNewLicense)
{
TCHAR g_LicenseString[] = TEXT("Licensed To Kill");
#define REPEAT_LICENSE_STRING 15
#define LICENSE_STRING_LEN sizeof(TCHAR) * lstrlen(g_LicenseString)
#define LICENSE_SIZE ( LICENSE_STRING_LEN * REPEAT_LICENSE_STRING ) + 1 * sizeof(TCHAR)
UINT i;
BYTE FAR *pbLicenseData = NULL;
DWORD cbLicenseData = LICENSE_SIZE;
if( NULL == ( *ppNewLicense = malloc(cbLicenseData) ) )
{
return FALSE;
}
memset(*ppNewLicense, 0x00, cbLicenseData);
//
// fill the memory with this license string
//
pbLicenseData = *ppNewLicense;
for( i = 0; i < REPEAT_LICENSE_STRING; i++ )
{
memcpy( pbLicenseData, g_LicenseString, LICENSE_STRING_LEN );
pbLicenseData += LICENSE_STRING_LEN;
}
*pcbNewLicense = cbLicenseData;
return TRUE;
}
VOID
FreeProprietaryCertificate(
PHydra_Server_Cert * ppCertificate )
{
if( NULL == *ppCertificate )
{
return;
}
if( ( *ppCertificate )->PublicKeyData.pBlob )
{
free( ( *ppCertificate )->PublicKeyData.pBlob );
}
if( ( *ppCertificate )->SignatureBlob.pBlob )
{
free( ( *ppCertificate )->SignatureBlob.pBlob );
}
free( *ppCertificate );
*ppCertificate = NULL;
}