/*++ 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 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; dwCountScopeList.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; }