Blame libfreerdp/core/license.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * RDP Licensing
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011-2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
Packit 1fb8d4
 * Copyright 2018 David Fort <contact@hardening-consulting.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/crypto.h>
Packit 1fb8d4
#include <winpr/shell.h>
Packit 1fb8d4
#include <winpr/path.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
Packit 1fb8d4
#include "redirection.h"
Packit 1fb8d4
#include "certificate.h"
Packit 1fb8d4
Packit 1fb8d4
#include "license.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("core.license")
Packit 1fb8d4
Packit 1fb8d4
#if 0
Packit 1fb8d4
#define LICENSE_NULL_CLIENT_RANDOM		1
Packit 1fb8d4
#define LICENSE_NULL_PREMASTER_SECRET		1
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
static wStream* license_send_stream_init(rdpLicense* license);
Packit 1fb8d4
Packit 1fb8d4
static void license_generate_randoms(rdpLicense* license);
Packit 1fb8d4
static BOOL license_generate_keys(rdpLicense* license);
Packit 1fb8d4
static BOOL license_generate_hwid(rdpLicense* license);
Packit 1fb8d4
static BOOL license_encrypt_premaster_secret(rdpLicense* license);
Packit 1fb8d4
Packit 1fb8d4
static LICENSE_PRODUCT_INFO* license_new_product_info(void);
Packit 1fb8d4
static void license_free_product_info(LICENSE_PRODUCT_INFO* productInfo);
Packit 1fb8d4
static BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo);
Packit 1fb8d4
Packit 1fb8d4
static LICENSE_BLOB* license_new_binary_blob(UINT16 type);
Packit 1fb8d4
static void license_free_binary_blob(LICENSE_BLOB* blob);
Packit 1fb8d4
static BOOL license_read_binary_blob(wStream* s, LICENSE_BLOB* blob);
Packit 1fb8d4
static BOOL license_write_binary_blob(wStream* s, const LICENSE_BLOB* blob);
Packit 1fb8d4
Packit 1fb8d4
static SCOPE_LIST* license_new_scope_list(void);
Packit 1fb8d4
static void license_free_scope_list(SCOPE_LIST* scopeList);
Packit 1fb8d4
static BOOL license_read_scope_list(wStream* s, SCOPE_LIST* scopeList);
Packit 1fb8d4
Packit 1fb8d4
static BOOL license_read_license_request_packet(rdpLicense* license, wStream* s);
Packit 1fb8d4
static BOOL license_read_platform_challenge_packet(rdpLicense* license, wStream* s);
Packit 1fb8d4
static BOOL license_read_new_or_upgrade_license_packet(rdpLicense* license, wStream* s);
Packit 1fb8d4
static BOOL license_read_error_alert_packet(rdpLicense* license, wStream* s);
Packit 1fb8d4
Packit 1fb8d4
static BOOL license_write_new_license_request_packet(rdpLicense* license, wStream* s);
Packit 1fb8d4
static BOOL license_answer_license_request(rdpLicense* license);
Packit 1fb8d4
Packit 1fb8d4
static BOOL license_write_platform_challenge_response_packet(rdpLicense* license, wStream* s,
Packit 1fb8d4
		const BYTE* mac_data);
Packit 1fb8d4
static BOOL license_send_platform_challenge_response_packet(rdpLicense* license);
Packit 1fb8d4
static BOOL license_send_client_info(rdpLicense* license, const LICENSE_BLOB *calBlob, BYTE* signature);
Packit 1fb8d4
Packit 1fb8d4
#define PLATFORMID (CLIENT_OS_ID_WINNT_POST_52 | CLIENT_IMAGE_ID_MICROSOFT)
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
Packit 1fb8d4
static const char* const LICENSE_MESSAGE_STRINGS[] =
Packit 1fb8d4
{
Packit 1fb8d4
	"",
Packit 1fb8d4
	"License Request",
Packit 1fb8d4
	"Platform Challenge",
Packit 1fb8d4
	"New License",
Packit 1fb8d4
	"Upgrade License",
Packit 1fb8d4
	"", "", "", "", "", "",
Packit 1fb8d4
	"", "", "", "", "", "",
Packit 1fb8d4
	"",
Packit 1fb8d4
	"License Info",
Packit 1fb8d4
	"New License Request",
Packit 1fb8d4
	"",
Packit 1fb8d4
	"Platform Challenge Response",
Packit 1fb8d4
	"", "", "", "", "", "", "", "", "",
Packit 1fb8d4
	"Error Alert"
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static const char* const error_codes[] =
Packit 1fb8d4
{
Packit 1fb8d4
	"ERR_UNKNOWN",
Packit 1fb8d4
	"ERR_INVALID_SERVER_CERTIFICATE",
Packit 1fb8d4
	"ERR_NO_LICENSE",
Packit 1fb8d4
	"ERR_INVALID_MAC",
Packit 1fb8d4
	"ERR_INVALID_SCOPE",
Packit 1fb8d4
	"ERR_UNKNOWN",
Packit 1fb8d4
	"ERR_NO_LICENSE_SERVER",
Packit 1fb8d4
	"STATUS_VALID_CLIENT",
Packit 1fb8d4
	"ERR_INVALID_CLIENT",
Packit 1fb8d4
	"ERR_UNKNOWN",
Packit 1fb8d4
	"ERR_UNKNOWN",
Packit 1fb8d4
	"ERR_INVALID_PRODUCT_ID",
Packit 1fb8d4
	"ERR_INVALID_MESSAGE_LENGTH"
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static const char* const  state_transitions[] =
Packit 1fb8d4
{
Packit 1fb8d4
	"ST_UNKNOWN",
Packit 1fb8d4
	"ST_TOTAL_ABORT",
Packit 1fb8d4
	"ST_NO_TRANSITION",
Packit 1fb8d4
	"ST_RESET_PHASE_TO_START",
Packit 1fb8d4
	"ST_RESEND_LAST_MESSAGE"
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static void license_print_product_info(const LICENSE_PRODUCT_INFO* productInfo)
Packit 1fb8d4
{
Packit 1fb8d4
	char* CompanyName = NULL;
Packit 1fb8d4
	char* ProductId = NULL;
Packit 1fb8d4
	ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) productInfo->pbCompanyName,
Packit 1fb8d4
			productInfo->cbCompanyName / 2, &CompanyName, 0, NULL, NULL);
Packit 1fb8d4
	ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) productInfo->pbProductId,
Packit 1fb8d4
			productInfo->cbProductId / 2, &ProductId, 0, NULL, NULL);
Packit 1fb8d4
	WLog_INFO(TAG, "ProductInfo:");
Packit 1fb8d4
	WLog_INFO(TAG, "\tdwVersion: 0x%08"PRIX32"", productInfo->dwVersion);
Packit 1fb8d4
	WLog_INFO(TAG, "\tCompanyName: %s", CompanyName);
Packit 1fb8d4
	WLog_INFO(TAG, "\tProductId: %s", ProductId);
Packit 1fb8d4
	free(CompanyName);
Packit 1fb8d4
	free(ProductId);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void license_print_scope_list(const SCOPE_LIST* scopeList)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	const LICENSE_BLOB* scope;
Packit 1fb8d4
	WLog_INFO(TAG, "ScopeList (%"PRIu32"):", scopeList->count);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < scopeList->count; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		scope = &scopeList->array[index];
Packit 1fb8d4
		WLog_INFO(TAG, "\t%s", (const char*) scope->data);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
static const char licenseStore[] = "licenses";
Packit 1fb8d4
Packit 1fb8d4
static BOOL computeCalHash(const char *hostname, char *hashStr)
Packit 1fb8d4
{
Packit 1fb8d4
	WINPR_DIGEST_CTX* sha1 = NULL;
Packit 1fb8d4
	BOOL ret = FALSE;
Packit 1fb8d4
	BYTE hash[20];
Packit 1fb8d4
	int i;
Packit 1fb8d4
Packit 1fb8d4
	if (!(sha1 = winpr_Digest_New()))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	if (!winpr_Digest_Update(sha1, (const BYTE *)hostname, strlen(hostname)))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	if (!winpr_Digest_Final(sha1, hash, sizeof(hash)))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < sizeof(hash); i++, hashStr += 2)
Packit 1fb8d4
		sprintf_s(hashStr, 3, "%.2x", hash[i]);
Packit 1fb8d4
Packit 1fb8d4
    ret = TRUE;
Packit 1fb8d4
out:
Packit 1fb8d4
	winpr_Digest_Free(sha1);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL saveCal(rdpSettings *settings, const BYTE *data, int length, char *hostname)
Packit 1fb8d4
{
Packit 1fb8d4
	char hash[41];
Packit 1fb8d4
	FILE *fp;
Packit 1fb8d4
	char *licenseStorePath = NULL;
Packit 1fb8d4
	char filename[MAX_PATH], filenameNew[MAX_PATH];
Packit 1fb8d4
	char *filepath = NULL, *filepathNew = NULL;
Packit 1fb8d4
	size_t written;
Packit 1fb8d4
	BOOL ret = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!PathFileExistsA(settings->ConfigPath))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!PathMakePathA(settings->ConfigPath, 0))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "error creating directory '%s'", settings->ConfigPath);
Packit 1fb8d4
			goto out;
Packit 1fb8d4
		}
Packit 1fb8d4
		WLog_INFO(TAG, "creating directory %s", settings->ConfigPath);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!(licenseStorePath = GetCombinedPath(settings->ConfigPath, licenseStore)))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	if (!PathFileExistsA(licenseStorePath))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!PathMakePathA(licenseStorePath, 0))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "error creating directory '%s'", licenseStorePath);
Packit 1fb8d4
			goto out;
Packit 1fb8d4
		}
Packit 1fb8d4
		WLog_INFO(TAG, "creating directory %s", licenseStorePath);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!computeCalHash(hostname, hash))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	sprintf_s(filename, sizeof(filename)-1, "%s.cal", hash);
Packit 1fb8d4
	sprintf_s(filenameNew, sizeof(filenameNew)-1, "%s.cal.new", hash);
Packit 1fb8d4
Packit 1fb8d4
	if (!(filepath = GetCombinedPath(licenseStorePath, filename)))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	if (!(filepathNew = GetCombinedPath(licenseStorePath, filenameNew)))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	fp = fopen(filepathNew, "wb");
Packit 1fb8d4
	if (!fp)
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	written = fwrite(data, length, 1, fp);
Packit 1fb8d4
	fclose(fp);
Packit 1fb8d4
Packit 1fb8d4
	if (written != 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		DeleteFile(filepathNew);
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ret = MoveFileEx(filepathNew, filepath, MOVEFILE_REPLACE_EXISTING);
Packit 1fb8d4
Packit 1fb8d4
out:
Packit 1fb8d4
	free(filepathNew);
Packit 1fb8d4
	free(filepath);
Packit 1fb8d4
	free(licenseStorePath);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BYTE *loadCalFile(rdpSettings *settings, const char* hostname, int *dataLen)
Packit 1fb8d4
{
Packit 1fb8d4
	char *licenseStorePath = NULL, *calPath = NULL;
Packit 1fb8d4
	char calFilename[MAX_PATH];
Packit 1fb8d4
	char hash[41];
Packit 1fb8d4
	int length, status;
Packit 1fb8d4
	FILE *fp;
Packit 1fb8d4
	BYTE *ret = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!computeCalHash(hostname, hash))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "loadCalFile: unable to compute hostname hash");
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	sprintf_s(calFilename, sizeof(calFilename)-1, "%s.cal", hash);
Packit 1fb8d4
Packit 1fb8d4
	if (!(licenseStorePath = GetCombinedPath(settings->ConfigPath, licenseStore)))
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!(calPath = GetCombinedPath(licenseStorePath, calFilename)))
Packit 1fb8d4
		goto error_path;
Packit 1fb8d4
Packit 1fb8d4
	fp = fopen(calPath, "rb");
Packit 1fb8d4
	if (!fp)
Packit 1fb8d4
		goto error_open;
Packit 1fb8d4
Packit 1fb8d4
	_fseeki64(fp, 0, SEEK_END);
Packit 1fb8d4
	length = _ftelli64(fp);
Packit 1fb8d4
	_fseeki64(fp, 0, SEEK_SET);
Packit 1fb8d4
Packit 1fb8d4
	ret = (BYTE *)malloc(length);
Packit 1fb8d4
	if (!ret)
Packit 1fb8d4
		goto error_malloc;
Packit 1fb8d4
Packit 1fb8d4
	status = fread(ret, length, 1, fp);
Packit 1fb8d4
	if (status <= 0)
Packit 1fb8d4
		goto error_read;
Packit 1fb8d4
Packit 1fb8d4
	*dataLen = length;
Packit 1fb8d4
Packit 1fb8d4
	fclose(fp);
Packit 1fb8d4
	free(calPath);
Packit 1fb8d4
	free(licenseStorePath);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
Packit 1fb8d4
error_read:
Packit 1fb8d4
	free(ret);
Packit 1fb8d4
error_malloc:
Packit 1fb8d4
	fclose(fp);
Packit 1fb8d4
error_open:
Packit 1fb8d4
	free(calPath);
Packit 1fb8d4
error_path:
Packit 1fb8d4
	free(licenseStorePath);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read a licensing preamble.\n
Packit 1fb8d4
 * @msdn{cc240480}
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param bMsgType license message type
Packit 1fb8d4
 * @param flags message flags
Packit 1fb8d4
 * @param wMsgSize message size
Packit 1fb8d4
 * @return if the operation completed successfully
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_read_preamble(wStream* s, BYTE* bMsgType, BYTE* flags, UINT16* wMsgSize)
Packit 1fb8d4
{
Packit 1fb8d4
	/* preamble (4 bytes) */
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(s, *bMsgType); /* bMsgType (1 byte) */
Packit 1fb8d4
	Stream_Read_UINT8(s, *flags); /* flags (1 byte) */
Packit 1fb8d4
	Stream_Read_UINT16(s, *wMsgSize); /* wMsgSize (2 bytes) */
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write a licensing preamble.\n
Packit 1fb8d4
 * @msdn{cc240480}
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param bMsgType license message type
Packit 1fb8d4
 * @param flags message flags
Packit 1fb8d4
 * @param wMsgSize message size
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static BOOL license_write_preamble(wStream* s, BYTE bMsgType, BYTE flags, UINT16 wMsgSize)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(s, 4))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* preamble (4 bytes) */
Packit 1fb8d4
	Stream_Write_UINT8(s, bMsgType); /* bMsgType (1 byte) */
Packit 1fb8d4
	Stream_Write_UINT8(s, flags); /* flags (1 byte) */
Packit 1fb8d4
	Stream_Write_UINT16(s, wMsgSize); /* wMsgSize (2 bytes) */
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Initialize a license packet stream.\n
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 * @return stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
wStream* license_send_stream_init(rdpLicense* license)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	BOOL do_crypt = license->rdp->do_crypt;
Packit 1fb8d4
Packit 1fb8d4
	license->rdp->sec_flags = SEC_LICENSE_PKT;
Packit 1fb8d4
Packit 1fb8d4
	/**
Packit 1fb8d4
	 * Encryption of licensing packets is optional even if the rdp security
Packit 1fb8d4
	 * layer is used. If the peer has not indicated that it is capable of
Packit 1fb8d4
	 * processing encrypted licensing packets (rdp->do_crypt_license) we turn
Packit 1fb8d4
	 * off encryption (via rdp->do_crypt) before initializing the rdp stream
Packit 1fb8d4
	 * and reenable it afterwards.
Packit 1fb8d4
	 */
Packit 1fb8d4
Packit 1fb8d4
	if (do_crypt)
Packit 1fb8d4
	{
Packit 1fb8d4
		license->rdp->sec_flags |= SEC_LICENSE_ENCRYPT_CS;
Packit 1fb8d4
		license->rdp->do_crypt = license->rdp->do_crypt_license;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	s = rdp_send_stream_init(license->rdp);
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
	license->rdp->do_crypt = do_crypt;
Packit 1fb8d4
	license->PacketHeaderLength = Stream_GetPosition(s);
Packit 1fb8d4
	if (!Stream_SafeSeek(s, LICENSE_PREAMBLE_LENGTH))
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	return s;
Packit 1fb8d4
Packit 1fb8d4
fail:
Packit 1fb8d4
	Stream_Release(s);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send an RDP licensing packet.\n
Packit 1fb8d4
 * @msdn{cc240479}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static BOOL license_send(rdpLicense* license, wStream* s, BYTE type)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	BYTE flags;
Packit 1fb8d4
	UINT16 wMsgSize;
Packit 1fb8d4
	rdpRdp* rdp = license->rdp;
Packit 1fb8d4
	BOOL ret;
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_LICENSE("Sending %s Packet", LICENSE_MESSAGE_STRINGS[type & 0x1F]);
Packit 1fb8d4
	length = Stream_GetPosition(s);
Packit 1fb8d4
	wMsgSize = length - license->PacketHeaderLength;
Packit 1fb8d4
	Stream_SetPosition(s, license->PacketHeaderLength);
Packit 1fb8d4
	flags = PREAMBLE_VERSION_3_0;
Packit 1fb8d4
Packit 1fb8d4
	/**
Packit 1fb8d4
	 * Using EXTENDED_ERROR_MSG_SUPPORTED here would cause mstsc to crash when
Packit 1fb8d4
	 * running in server mode! This flag seems to be incorrectly documented.
Packit 1fb8d4
	 */
Packit 1fb8d4
Packit 1fb8d4
	if (!rdp->settings->ServerMode)
Packit 1fb8d4
		flags |= EXTENDED_ERROR_MSG_SUPPORTED;
Packit 1fb8d4
Packit 1fb8d4
	if(!license_write_preamble(s, type, flags, wMsgSize))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "Sending %s Packet, length %"PRIu16"", LICENSE_MESSAGE_STRINGS[type & 0x1F], wMsgSize);
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(s) - LICENSE_PREAMBLE_LENGTH, wMsgSize);
Packit 1fb8d4
#endif
Packit 1fb8d4
	Stream_SetPosition(s, length);
Packit 1fb8d4
	ret = rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID);
Packit 1fb8d4
	rdp->sec_flags = 0;
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Receive an RDP licensing packet.\n
Packit 1fb8d4
 * @msdn{cc240479}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @return if the operation completed successfully
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
int license_recv(rdpLicense* license, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE flags;
Packit 1fb8d4
	BYTE bMsgType;
Packit 1fb8d4
	UINT16 wMsgSize;
Packit 1fb8d4
	UINT16 length;
Packit 1fb8d4
	UINT16 channelId;
Packit 1fb8d4
	UINT16 securityFlags = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!rdp_read_header(license->rdp, s, &length, &channelId))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Incorrect RDP header.");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!rdp_read_security_header(s, &securityFlags, &length))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (securityFlags & SEC_ENCRYPT)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!rdp_decrypt(license->rdp, s, length, securityFlags))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "rdp_decrypt failed");
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!(securityFlags & SEC_LICENSE_PKT))
Packit 1fb8d4
	{
Packit 1fb8d4
		int status;
Packit 1fb8d4
Packit 1fb8d4
		if (!(securityFlags & SEC_ENCRYPT))
Packit 1fb8d4
			Stream_Rewind(s, RDP_SECURITY_HEADER_LENGTH);
Packit 1fb8d4
Packit 1fb8d4
		status = rdp_recv_out_of_sequence_pdu(license->rdp, s);
Packit 1fb8d4
		if (status < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "unexpected license packet.");
Packit 1fb8d4
			return status;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!license_read_preamble(s, &bMsgType, &flags, &wMsgSize)) /* preamble (4 bytes) */
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_LICENSE("Receiving %s Packet", LICENSE_MESSAGE_STRINGS[bMsgType & 0x1F]);
Packit 1fb8d4
Packit 1fb8d4
	switch (bMsgType)
Packit 1fb8d4
	{
Packit 1fb8d4
		case LICENSE_REQUEST:
Packit 1fb8d4
			if (!license_read_license_request_packet(license, s))
Packit 1fb8d4
				return -1;
Packit 1fb8d4
Packit 1fb8d4
			if (!license_answer_license_request(license))
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case PLATFORM_CHALLENGE:
Packit 1fb8d4
			if (!license_read_platform_challenge_packet(license, s))
Packit 1fb8d4
				return -1;
Packit 1fb8d4
Packit 1fb8d4
			if (!license_send_platform_challenge_response_packet(license))
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case NEW_LICENSE:
Packit 1fb8d4
		case UPGRADE_LICENSE:
Packit 1fb8d4
			if (!license_read_new_or_upgrade_license_packet(license, s))
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ERROR_ALERT:
Packit 1fb8d4
			if (!license_read_error_alert_packet(license, s))
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			WLog_ERR(TAG, "invalid bMsgType:%"PRIu8"", bMsgType);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void license_generate_randoms(rdpLicense* license)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef LICENSE_NULL_CLIENT_RANDOM
Packit 1fb8d4
	ZeroMemory(license->ClientRandom, CLIENT_RANDOM_LENGTH); /* ClientRandom */
Packit 1fb8d4
#else
Packit 1fb8d4
	winpr_RAND(license->ClientRandom, CLIENT_RANDOM_LENGTH); /* ClientRandom */
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#ifdef LICENSE_NULL_PREMASTER_SECRET
Packit 1fb8d4
	ZeroMemory(license->PremasterSecret, PREMASTER_SECRET_LENGTH); /* PremasterSecret */
Packit 1fb8d4
#else
Packit 1fb8d4
	winpr_RAND(license->PremasterSecret, PREMASTER_SECRET_LENGTH); /* PremasterSecret */
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Generate License Cryptographic Keys.
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static BOOL license_generate_keys(rdpLicense* license)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL ret;
Packit 1fb8d4
Packit 1fb8d4
	if (
Packit 1fb8d4
		/* MasterSecret */
Packit 1fb8d4
		!security_master_secret(license->PremasterSecret, license->ClientRandom,
Packit 1fb8d4
								license->ServerRandom, license->MasterSecret) ||
Packit 1fb8d4
		/* SessionKeyBlob */
Packit 1fb8d4
		!security_session_key_blob(license->MasterSecret, license->ClientRandom,
Packit 1fb8d4
							  license->ServerRandom, license->SessionKeyBlob))
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
	security_mac_salt_key(license->SessionKeyBlob, license->ClientRandom,
Packit 1fb8d4
						  license->ServerRandom, license->MacSaltKey); /* MacSaltKey */
Packit 1fb8d4
	ret = security_licensing_encryption_key(license->SessionKeyBlob, license->ClientRandom,
Packit 1fb8d4
									  license->ServerRandom, license->LicensingEncryptionKey); /* LicensingEncryptionKey */
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "ClientRandom:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->ClientRandom, CLIENT_RANDOM_LENGTH);
Packit 1fb8d4
	WLog_DBG(TAG, "ServerRandom:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->ServerRandom, SERVER_RANDOM_LENGTH);
Packit 1fb8d4
	WLog_DBG(TAG, "PremasterSecret:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->PremasterSecret, PREMASTER_SECRET_LENGTH);
Packit 1fb8d4
	WLog_DBG(TAG, "MasterSecret:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->MasterSecret, MASTER_SECRET_LENGTH);
Packit 1fb8d4
	WLog_DBG(TAG, "SessionKeyBlob:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->SessionKeyBlob, SESSION_KEY_BLOB_LENGTH);
Packit 1fb8d4
	WLog_DBG(TAG, "MacSaltKey:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->MacSaltKey, MAC_SALT_KEY_LENGTH);
Packit 1fb8d4
	WLog_DBG(TAG, "LicensingEncryptionKey:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH);
Packit 1fb8d4
#endif
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Generate Unique Hardware Identifier (CLIENT_HARDWARE_ID).\n
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_generate_hwid(rdpLicense* license)
Packit 1fb8d4
{
Packit 1fb8d4
	const BYTE *hashTarget;
Packit 1fb8d4
	size_t targetLen;
Packit 1fb8d4
	BYTE macAddress[6];
Packit 1fb8d4
Packit 1fb8d4
	ZeroMemory(license->HardwareId, HWID_LENGTH);
Packit 1fb8d4
Packit 1fb8d4
	if (license->rdp->settings->OldLicenseBehaviour)
Packit 1fb8d4
	{
Packit 1fb8d4
		ZeroMemory(macAddress, sizeof(macAddress));
Packit 1fb8d4
		hashTarget = macAddress;
Packit 1fb8d4
		targetLen = sizeof(macAddress);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		const char *hostname = license->rdp->settings->ClientHostname;
Packit 1fb8d4
		hashTarget = (const BYTE *)hostname;
Packit 1fb8d4
		targetLen = strlen(hostname);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Allow FIPS override for use of MD5 here, really this does not have to be MD5 as we are just taking a MD5 hash of the 6 bytes of 0's(macAddress) */
Packit 1fb8d4
	/* and filling in the Data1-Data4 fields of the CLIENT_HARDWARE_ID structure(from MS-RDPELE section 2.2.2.3.1). This is for RDP licensing packets */
Packit 1fb8d4
	/* which will already be encrypted under FIPS, so the use of MD5 here is not for sensitive data protection. */
Packit 1fb8d4
	return winpr_Digest_Allow_FIPS(WINPR_MD_MD5, hashTarget, targetLen,
Packit 1fb8d4
			&license->HardwareId[HWID_PLATFORM_ID_LENGTH], WINPR_MD5_DIGEST_LENGTH);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL license_get_server_rsa_public_key(rdpLicense* license)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE* Exponent;
Packit 1fb8d4
	BYTE* Modulus;
Packit 1fb8d4
	int ModulusLength;
Packit 1fb8d4
	rdpSettings* settings = license->rdp->settings;
Packit 1fb8d4
Packit 1fb8d4
	if (license->ServerCertificate->length < 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!certificate_read_server_certificate(license->certificate,
Packit 1fb8d4
				settings->ServerCertificate, settings->ServerCertificateLength))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Exponent = license->certificate->cert_info.exponent;
Packit 1fb8d4
	Modulus = license->certificate->cert_info.Modulus;
Packit 1fb8d4
	ModulusLength = license->certificate->cert_info.ModulusLength;
Packit 1fb8d4
	CopyMemory(license->Exponent, Exponent, 4);
Packit 1fb8d4
	license->ModulusLength = ModulusLength;
Packit 1fb8d4
	license->Modulus = (BYTE*) malloc(ModulusLength);
Packit 1fb8d4
	if (!license->Modulus)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	CopyMemory(license->Modulus, Modulus, ModulusLength);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL license_encrypt_premaster_secret(rdpLicense* license)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE* EncryptedPremasterSecret;
Packit 1fb8d4
Packit 1fb8d4
	if (!license_get_server_rsa_public_key(license))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "Modulus (%"PRIu32" bits):", license->ModulusLength * 8);
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->Modulus, license->ModulusLength);
Packit 1fb8d4
	WLog_DBG(TAG, "Exponent:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->Exponent, 4);
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	EncryptedPremasterSecret = (BYTE*) calloc(1, license->ModulusLength);
Packit 1fb8d4
	if (!EncryptedPremasterSecret)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	license->EncryptedPremasterSecret->type = BB_RANDOM_BLOB;
Packit 1fb8d4
	license->EncryptedPremasterSecret->length = PREMASTER_SECRET_LENGTH;
Packit 1fb8d4
#ifndef LICENSE_NULL_PREMASTER_SECRET
Packit 1fb8d4
	license->EncryptedPremasterSecret->length =
Packit 1fb8d4
		crypto_rsa_public_encrypt(license->PremasterSecret, PREMASTER_SECRET_LENGTH,
Packit 1fb8d4
			license->ModulusLength, license->Modulus, license->Exponent, EncryptedPremasterSecret);
Packit 1fb8d4
#endif
Packit 1fb8d4
	license->EncryptedPremasterSecret->data = EncryptedPremasterSecret;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL license_rc4_with_licenseKey(const rdpLicense* license, const BYTE *input, size_t len, LICENSE_BLOB *target)
Packit 1fb8d4
{
Packit 1fb8d4
	WINPR_RC4_CTX* rc4;
Packit 1fb8d4
	BYTE *buffer = NULL;
Packit 1fb8d4
Packit 1fb8d4
	rc4 = winpr_RC4_New_Allow_FIPS(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH);
Packit 1fb8d4
	if (!rc4)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	buffer = (BYTE*) realloc(target->data, len);
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		goto error_buffer;
Packit 1fb8d4
Packit 1fb8d4
	target->data = buffer;
Packit 1fb8d4
	target->length = len;
Packit 1fb8d4
Packit 1fb8d4
	if (!winpr_RC4_Update(rc4, len, input, buffer))
Packit 1fb8d4
		goto error_update;
Packit 1fb8d4
Packit 1fb8d4
	winpr_RC4_Free(rc4);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
Packit 1fb8d4
error_update:
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
error_buffer:
Packit 1fb8d4
	winpr_RC4_Free(rc4);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Encrypt the input using the license key and MAC the input for a signature
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param license rdpLicense to get keys and salt from
Packit 1fb8d4
 * @param input the input data to encrypt and MAC
Packit 1fb8d4
 * @param len size of input
Packit 1fb8d4
 * @param target a target LICENSE_BLOB where the encrypted input will be stored
Packit 1fb8d4
 * @param mac the signature buffer (16 bytes)
Packit 1fb8d4
 * @return if the operation completed successfully
Packit 1fb8d4
 */
Packit 1fb8d4
static BOOL license_encrypt_and_MAC(rdpLicense* license, const BYTE *input, size_t len, LICENSE_BLOB *target, BYTE *mac)
Packit 1fb8d4
{
Packit 1fb8d4
	return license_rc4_with_licenseKey(license, input, len, target) &&
Packit 1fb8d4
			security_mac_data(license->MacSaltKey, input, len, mac);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Decrypt the input using the license key and check the MAC
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param license rdpLicense to get keys and salt from
Packit 1fb8d4
 * @param input the input data to decrypt and MAC
Packit 1fb8d4
 * @param len size of input
Packit 1fb8d4
 * @param target a target LICENSE_BLOB where the decrypted input will be stored
Packit 1fb8d4
 * @param mac the signature buffer (16 bytes)
Packit 1fb8d4
 * @return if the operation completed successfully
Packit 1fb8d4
 */
Packit 1fb8d4
static BOOL license_decrypt_and_check_MAC(rdpLicense* license, const BYTE *input, size_t len, LICENSE_BLOB *target, const BYTE *packetMac)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE macData[16];
Packit 1fb8d4
Packit 1fb8d4
	return license_rc4_with_licenseKey(license, input, len, target) &&
Packit 1fb8d4
			security_mac_data(license->MacSaltKey, target->data, len, macData) &&
Packit 1fb8d4
			(memcmp(packetMac, macData, sizeof(macData)) == 0);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read Product Information (PRODUCT_INFO).\n
Packit 1fb8d4
 * @msdn{cc241915}
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param productInfo product information
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo)
Packit 1fb8d4
{
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 8)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, productInfo->dwVersion); /* dwVersion (4 bytes) */
Packit 1fb8d4
	Stream_Read_UINT32(s, productInfo->cbCompanyName); /* cbCompanyName (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	/* Name must be >0, but there is no upper limit defined, use UINT32_MAX */
Packit 1fb8d4
	if ((productInfo->cbCompanyName < 2) || (productInfo->cbCompanyName % 2 != 0))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < productInfo->cbCompanyName)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	productInfo->pbProductId = NULL;
Packit 1fb8d4
	productInfo->pbCompanyName = (BYTE*) malloc(productInfo->cbCompanyName);
Packit 1fb8d4
	if (!productInfo->pbCompanyName)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	Stream_Read(s, productInfo->pbCompanyName, productInfo->cbCompanyName);
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, productInfo->cbProductId); /* cbProductId (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if ((productInfo->cbProductId < 2) || (productInfo->cbProductId % 2 != 0))
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < productInfo->cbProductId)
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
	productInfo->pbProductId = (BYTE*) malloc(productInfo->cbProductId);
Packit 1fb8d4
	if (!productInfo->pbProductId)
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
	Stream_Read(s, productInfo->pbProductId, productInfo->cbProductId);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
Packit 1fb8d4
out_fail:
Packit 1fb8d4
	free(productInfo->pbCompanyName);
Packit 1fb8d4
	free(productInfo->pbProductId);
Packit 1fb8d4
	productInfo->pbCompanyName = NULL;
Packit 1fb8d4
	productInfo->pbProductId = NULL;
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Allocate New Product Information (LICENSE_PRODUCT_INFO).\n
Packit 1fb8d4
 * @msdn{cc241915}
Packit 1fb8d4
 * @return new product information
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
LICENSE_PRODUCT_INFO* license_new_product_info()
Packit 1fb8d4
{
Packit 1fb8d4
	LICENSE_PRODUCT_INFO* productInfo;
Packit 1fb8d4
	productInfo = (LICENSE_PRODUCT_INFO*) malloc(sizeof(LICENSE_PRODUCT_INFO));
Packit 1fb8d4
	if (!productInfo)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	productInfo->dwVersion = 0;
Packit 1fb8d4
	productInfo->cbCompanyName = 0;
Packit 1fb8d4
	productInfo->pbCompanyName = NULL;
Packit 1fb8d4
	productInfo->cbProductId = 0;
Packit 1fb8d4
	productInfo->pbProductId = NULL;
Packit 1fb8d4
	return productInfo;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Free Product Information (LICENSE_PRODUCT_INFO).\n
Packit 1fb8d4
 * @msdn{cc241915}
Packit 1fb8d4
 * @param productInfo product information
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void license_free_product_info(LICENSE_PRODUCT_INFO* productInfo)
Packit 1fb8d4
{
Packit 1fb8d4
	if (productInfo)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(productInfo->pbCompanyName);
Packit 1fb8d4
		free(productInfo->pbProductId);
Packit 1fb8d4
		free(productInfo);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read License Binary Blob (LICENSE_BINARY_BLOB).\n
Packit 1fb8d4
 * @msdn{cc240481}
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param blob license binary blob
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_read_binary_blob(wStream* s, LICENSE_BLOB* blob)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 wBlobType;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT16(s, wBlobType); /* wBlobType (2 bytes) */
Packit 1fb8d4
	Stream_Read_UINT16(s, blob->length); /* wBlobLen (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < blob->length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * Server can choose to not send data by setting length to 0.
Packit 1fb8d4
	 * If so, it may not bother to set the type, so shortcut the warning
Packit 1fb8d4
	 */
Packit 1fb8d4
	if ((blob->type != BB_ANY_BLOB) && (blob->length == 0))
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if ((blob->type != wBlobType) && (blob->type != BB_ANY_BLOB))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "license binary blob type (0x%"PRIx16") does not match expected type (0x%"PRIx16").",
Packit 1fb8d4
				wBlobType, blob->type);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	blob->type = wBlobType;
Packit 1fb8d4
	blob->data = (BYTE*) malloc(blob->length);
Packit 1fb8d4
	if (!blob->data)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	Stream_Read(s, blob->data, blob->length); /* blobData */
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write License Binary Blob (LICENSE_BINARY_BLOB).\n
Packit 1fb8d4
 * @msdn{cc240481}
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param blob license binary blob
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_write_binary_blob(wStream* s, const LICENSE_BLOB* blob)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(s, blob->length +  4))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT16(s, blob->type); /* wBlobType (2 bytes) */
Packit 1fb8d4
	Stream_Write_UINT16(s, blob->length); /* wBlobLen (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (blob->length > 0)
Packit 1fb8d4
		Stream_Write(s, blob->data, blob->length); /* blobData */
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL license_write_encrypted_premaster_secret_blob(wStream* s, const LICENSE_BLOB* blob, UINT32 ModulusLength)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 length;
Packit 1fb8d4
	length = ModulusLength + 8;
Packit 1fb8d4
Packit 1fb8d4
	if (blob->length > ModulusLength)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "license_write_encrypted_premaster_secret_blob: invalid blob");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(s, length + 4))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	Stream_Write_UINT16(s, blob->type); /* wBlobType (2 bytes) */
Packit 1fb8d4
	Stream_Write_UINT16(s, length); /* wBlobLen (2 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (blob->length > 0)
Packit 1fb8d4
		Stream_Write(s, blob->data, blob->length); /* blobData */
Packit 1fb8d4
Packit 1fb8d4
	Stream_Zero(s, length - blob->length);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Allocate New License Binary Blob (LICENSE_BINARY_BLOB).\n
Packit 1fb8d4
 * @msdn{cc240481}
Packit 1fb8d4
 * @return new license binary blob
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
LICENSE_BLOB* license_new_binary_blob(UINT16 type)
Packit 1fb8d4
{
Packit 1fb8d4
	LICENSE_BLOB* blob;
Packit 1fb8d4
	blob = (LICENSE_BLOB*) calloc(1, sizeof(LICENSE_BLOB));
Packit 1fb8d4
	if (blob)
Packit 1fb8d4
		blob->type = type;
Packit 1fb8d4
	return blob;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Free License Binary Blob (LICENSE_BINARY_BLOB).\n
Packit 1fb8d4
 * @msdn{cc240481}
Packit 1fb8d4
 * @param blob license binary blob
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void license_free_binary_blob(LICENSE_BLOB* blob)
Packit 1fb8d4
{
Packit 1fb8d4
	if (blob)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(blob->data);
Packit 1fb8d4
		free(blob);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read License Scope List (SCOPE_LIST).\n
Packit 1fb8d4
 * @msdn{cc241916}
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param scopeList scope list
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_read_scope_list(wStream* s, SCOPE_LIST* scopeList)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i;
Packit 1fb8d4
	UINT32 scopeCount;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, scopeCount); /* ScopeCount (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (scopeCount > Stream_GetRemainingLength(s) / 4)  /* every blob is at least 4 bytes */
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	scopeList->count = scopeCount;
Packit 1fb8d4
	scopeList->array = (LICENSE_BLOB*) calloc(scopeCount, sizeof(LICENSE_BLOB));
Packit 1fb8d4
	if (!scopeList->array)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* ScopeArray */
Packit 1fb8d4
	for (i = 0; i < scopeCount; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		scopeList->array[i].type = BB_SCOPE_BLOB;
Packit 1fb8d4
Packit 1fb8d4
		if (!license_read_binary_blob(s, &scopeList->array[i]))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Allocate New License Scope List (SCOPE_LIST).\n
Packit 1fb8d4
 * @msdn{cc241916}
Packit 1fb8d4
 * @return new scope list
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
SCOPE_LIST* license_new_scope_list()
Packit 1fb8d4
{
Packit 1fb8d4
	return (SCOPE_LIST*) calloc(1, sizeof(SCOPE_LIST));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Free License Scope List (SCOPE_LIST).\n
Packit 1fb8d4
 * @msdn{cc241916}
Packit 1fb8d4
 * @param scopeList scope list
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void license_free_scope_list(SCOPE_LIST* scopeList)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i;
Packit 1fb8d4
Packit 1fb8d4
	if (!scopeList)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * We must NOT call license_free_binary_blob() on each scopelist->array[i] element,
Packit 1fb8d4
	 * because scopelist->array was allocated at once, by a single call to malloc. The elements
Packit 1fb8d4
	 * it contains cannot be deallocated separately then.
Packit 1fb8d4
	 * To make things clean, we must deallocate each scopelist->array[].data,
Packit 1fb8d4
	 * and finish by deallocating scopelist->array with a single call to free().
Packit 1fb8d4
	 */
Packit 1fb8d4
	for (i = 0; i < scopeList->count; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(scopeList->array[i].data);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(scopeList->array);
Packit 1fb8d4
	free(scopeList);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL license_send_client_info(rdpLicense *license, const LICENSE_BLOB *calBlob, BYTE *signature)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream *s;
Packit 1fb8d4
Packit 1fb8d4
	/* Client License Information: */
Packit 1fb8d4
	UINT32 PlatformId = PLATFORMID;
Packit 1fb8d4
	UINT32 PreferredKeyExchangeAlg = KEY_EXCHANGE_ALG_RSA;
Packit 1fb8d4
Packit 1fb8d4
	s = license_send_stream_init(license);
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(s, PreferredKeyExchangeAlg); /* PreferredKeyExchangeAlg (4 bytes) */
Packit 1fb8d4
	Stream_Write_UINT32(s, PlatformId); /* PlatformId (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	/* ClientRandom (32 bytes) */
Packit 1fb8d4
	Stream_Write(s, license->ClientRandom, CLIENT_RANDOM_LENGTH);
Packit 1fb8d4
Packit 1fb8d4
	/* Licensing Binary Blob with EncryptedPreMasterSecret: */
Packit 1fb8d4
	if (!license_write_encrypted_premaster_secret_blob(s, license->EncryptedPremasterSecret, license->ModulusLength))
Packit 1fb8d4
		goto error;
Packit 1fb8d4
Packit 1fb8d4
	/* Licensing Binary Blob with LicenseInfo: */
Packit 1fb8d4
	if (!license_write_binary_blob(s, calBlob))
Packit 1fb8d4
		goto error;
Packit 1fb8d4
Packit 1fb8d4
	/* Licensing Binary Blob with EncryptedHWID */
Packit 1fb8d4
	if (!license_write_binary_blob(s, license->EncryptedHardwareId))
Packit 1fb8d4
		goto error;
Packit 1fb8d4
Packit 1fb8d4
	/* MACData */
Packit 1fb8d4
	Stream_Write(s, signature, LICENSING_ENCRYPTION_KEY_LENGTH);
Packit 1fb8d4
Packit 1fb8d4
	return license_send(license, s, LICENSE_INFO);
Packit 1fb8d4
Packit 1fb8d4
error:
Packit 1fb8d4
	Stream_Release(s);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read a LICENSE_REQUEST packet.\n
Packit 1fb8d4
 * @msdn{cc241914}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_read_license_request_packet(rdpLicense* license, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	/* ServerRandom (32 bytes) */
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 32)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read(s, license->ServerRandom, 32);
Packit 1fb8d4
Packit 1fb8d4
	/* ProductInfo */
Packit 1fb8d4
	if (!license_read_product_info(s, license->ProductInfo))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* KeyExchangeList */
Packit 1fb8d4
	if (!license_read_binary_blob(s, license->KeyExchangeList))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* ServerCertificate */
Packit 1fb8d4
	if (!license_read_binary_blob(s, license->ServerCertificate))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* ScopeList */
Packit 1fb8d4
	if (!license_read_scope_list(s, license->ScopeList))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* Parse Server Certificate */
Packit 1fb8d4
	if (!certificate_read_server_certificate(license->certificate,
Packit 1fb8d4
		license->ServerCertificate->data, license->ServerCertificate->length))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!license_generate_keys(license) || !license_generate_hwid(license) ||
Packit 1fb8d4
		!license_encrypt_premaster_secret(license))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "ServerRandom:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->ServerRandom, 32);
Packit 1fb8d4
	license_print_product_info(license->ProductInfo);
Packit 1fb8d4
	license_print_scope_list(license->ScopeList);
Packit 1fb8d4
#endif
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/*
Packit 1fb8d4
 * Read a PLATFORM_CHALLENGE packet.\n
Packit 1fb8d4
 * @msdn{cc241921}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_read_platform_challenge_packet(rdpLicense* license, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE macData[16];
Packit 1fb8d4
	UINT32 ConnectFlags = 0;
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_LICENSE("Receiving Platform Challenge Packet");
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, ConnectFlags); /* ConnectFlags, Reserved (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	/* EncryptedPlatformChallenge */
Packit 1fb8d4
	license->EncryptedPlatformChallenge->type = BB_ANY_BLOB;
Packit 1fb8d4
	if (!license_read_binary_blob(s, license->EncryptedPlatformChallenge))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	license->EncryptedPlatformChallenge->type = BB_ENCRYPTED_DATA_BLOB;
Packit 1fb8d4
Packit 1fb8d4
	/* MACData (16 bytes) */
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 16)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read(s, macData, 16);
Packit 1fb8d4
	if (!license_decrypt_and_check_MAC(license, license->EncryptedPlatformChallenge->data,
Packit 1fb8d4
			license->EncryptedPlatformChallenge->length,
Packit 1fb8d4
			license->PlatformChallenge, macData))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "ConnectFlags: 0x%08"PRIX32"", ConnectFlags);
Packit 1fb8d4
	WLog_DBG(TAG, "EncryptedPlatformChallenge:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->EncryptedPlatformChallenge->data,
Packit 1fb8d4
			license->EncryptedPlatformChallenge->length);
Packit 1fb8d4
	WLog_DBG(TAG, "PlatformChallenge:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->PlatformChallenge->data,
Packit 1fb8d4
			license->PlatformChallenge->length);
Packit 1fb8d4
	WLog_DBG(TAG, "MacData:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, macData, 16);
Packit 1fb8d4
#endif
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
static BOOL license_read_encrypted_blob(const rdpLicense *license, wStream *s, LICENSE_BLOB *target)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 wBlobType, wBlobLen;
Packit 1fb8d4
	BYTE *encryptedData;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT16(s, wBlobType);
Packit 1fb8d4
	if (wBlobType != BB_ENCRYPTED_DATA_BLOB)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "expecting BB_ENCRYPTED_DATA_BLOB blob");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT16(s, wBlobLen);
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < wBlobLen)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	encryptedData = Stream_Pointer(s);
Packit 1fb8d4
	Stream_Seek(s, wBlobLen);
Packit 1fb8d4
	return license_rc4_with_licenseKey(license, encryptedData, wBlobLen, target);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read a NEW_LICENSE packet.\n
Packit 1fb8d4
 * @msdn{cc241926}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_read_new_or_upgrade_license_packet(rdpLicense* license, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 os_major;
Packit 1fb8d4
	UINT32 os_minor;
Packit 1fb8d4
	UINT32 cbScope, cbCompanyName, cbProductId, cbLicenseInfo;
Packit 1fb8d4
	wStream *licenseStream = NULL;
Packit 1fb8d4
	BOOL ret = FALSE;
Packit 1fb8d4
	BYTE computedMac[16];
Packit 1fb8d4
	LICENSE_BLOB *calBlob;
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_LICENSE("Receiving Server New/Upgrade License Packet");
Packit 1fb8d4
Packit 1fb8d4
	calBlob = license_new_binary_blob(BB_DATA_BLOB);
Packit 1fb8d4
	if (!calBlob)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* EncryptedLicenseInfo */
Packit 1fb8d4
	if (!license_read_encrypted_blob(license, s, calBlob))
Packit 1fb8d4
		goto out_free_blob;
Packit 1fb8d4
Packit 1fb8d4
	/* compute MAC and check it */
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 16)
Packit 1fb8d4
		goto out_free_blob;
Packit 1fb8d4
Packit 1fb8d4
	if (!security_mac_data(license->MacSaltKey, calBlob->data, calBlob->length, computedMac))
Packit 1fb8d4
		goto out_free_blob;
Packit 1fb8d4
Packit 1fb8d4
	if (memcmp(computedMac, Stream_Pointer(s), sizeof(computedMac)) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "new or upgrade license MAC mismatch");
Packit 1fb8d4
		goto out_free_blob;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	licenseStream = Stream_New(calBlob->data, calBlob->length);
Packit 1fb8d4
	if (!licenseStream)
Packit 1fb8d4
		goto out_free_blob;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT16(licenseStream, os_minor);
Packit 1fb8d4
	Stream_Read_UINT16(licenseStream, os_major);
Packit 1fb8d4
Packit 1fb8d4
	/* Scope */
Packit 1fb8d4
	Stream_Read_UINT32(licenseStream, cbScope);
Packit 1fb8d4
	if (Stream_GetRemainingLength(licenseStream) < cbScope)
Packit 1fb8d4
		goto out_free_stream;
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "Scope:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(licenseStream), cbScope);
Packit 1fb8d4
#endif
Packit 1fb8d4
	Stream_Seek(licenseStream, cbScope);
Packit 1fb8d4
Packit 1fb8d4
	/* CompanyName */
Packit 1fb8d4
	Stream_Read_UINT32(licenseStream, cbCompanyName);
Packit 1fb8d4
	if (Stream_GetRemainingLength(licenseStream) < cbCompanyName)
Packit 1fb8d4
		goto out_free_stream;
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "Company name:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(licenseStream), cbCompanyName);
Packit 1fb8d4
#endif
Packit 1fb8d4
	Stream_Seek(licenseStream, cbCompanyName);
Packit 1fb8d4
Packit 1fb8d4
	/* productId */
Packit 1fb8d4
	Stream_Read_UINT32(licenseStream, cbProductId);
Packit 1fb8d4
	if (Stream_GetRemainingLength(licenseStream) < cbProductId)
Packit 1fb8d4
		goto out_free_stream;
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "Product id:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(licenseStream), cbProductId);
Packit 1fb8d4
#endif
Packit 1fb8d4
	Stream_Seek(licenseStream, cbProductId);
Packit 1fb8d4
Packit 1fb8d4
	/* licenseInfo */
Packit 1fb8d4
	Stream_Read_UINT32(licenseStream, cbLicenseInfo);
Packit 1fb8d4
	if (Stream_GetRemainingLength(licenseStream) < cbLicenseInfo)
Packit 1fb8d4
		goto out_free_stream;
Packit 1fb8d4
Packit 1fb8d4
	license->state = LICENSE_STATE_COMPLETED;
Packit 1fb8d4
	ret = saveCal(license->rdp->settings, Stream_Pointer(licenseStream), cbLicenseInfo, license->rdp->settings->ClientHostname);
Packit 1fb8d4
Packit 1fb8d4
out_free_stream:
Packit 1fb8d4
	Stream_Free(licenseStream, FALSE);
Packit 1fb8d4
out_free_blob:
Packit 1fb8d4
	license_free_binary_blob(calBlob);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read an ERROR_ALERT packet.\n
Packit 1fb8d4
 * @msdn{cc240482}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_read_error_alert_packet(rdpLicense* license, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 dwErrorCode;
Packit 1fb8d4
	UINT32 dwStateTransition;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 8)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, dwErrorCode); /* dwErrorCode (4 bytes) */
Packit 1fb8d4
	Stream_Read_UINT32(s, dwStateTransition); /* dwStateTransition (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	if (!license_read_binary_blob(s, license->ErrorInfo)) /* bbErrorInfo */
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "dwErrorCode: %s, dwStateTransition: %s",
Packit 1fb8d4
			 error_codes[dwErrorCode], state_transitions[dwStateTransition]);
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	if (dwErrorCode == STATUS_VALID_CLIENT)
Packit 1fb8d4
	{
Packit 1fb8d4
		license->state = LICENSE_STATE_COMPLETED;
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	switch (dwStateTransition)
Packit 1fb8d4
	{
Packit 1fb8d4
		case ST_TOTAL_ABORT:
Packit 1fb8d4
			license->state = LICENSE_STATE_ABORTED;
Packit 1fb8d4
			break;
Packit 1fb8d4
		case ST_NO_TRANSITION:
Packit 1fb8d4
			license->state = LICENSE_STATE_COMPLETED;
Packit 1fb8d4
			break;
Packit 1fb8d4
		case ST_RESET_PHASE_TO_START:
Packit 1fb8d4
			license->state = LICENSE_STATE_AWAIT;
Packit 1fb8d4
			break;
Packit 1fb8d4
		case ST_RESEND_LAST_MESSAGE:
Packit 1fb8d4
			break;
Packit 1fb8d4
		default:
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write a NEW_LICENSE_REQUEST packet.\n
Packit 1fb8d4
 * @msdn{cc241918}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_write_new_license_request_packet(rdpLicense* license, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 PlatformId = PLATFORMID;
Packit 1fb8d4
	UINT32 PreferredKeyExchangeAlg = KEY_EXCHANGE_ALG_RSA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(s, PreferredKeyExchangeAlg); /* PreferredKeyExchangeAlg (4 bytes) */
Packit 1fb8d4
	Stream_Write_UINT32(s, PlatformId); /* PlatformId (4 bytes) */
Packit 1fb8d4
	Stream_Write(s, license->ClientRandom, 32); /* ClientRandom (32 bytes) */
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
	if (/* EncryptedPremasterSecret */
Packit 1fb8d4
		!license_write_encrypted_premaster_secret_blob(s, license->EncryptedPremasterSecret, license->ModulusLength) ||
Packit 1fb8d4
		/* ClientUserName */
Packit 1fb8d4
		!license_write_binary_blob(s, license->ClientUserName) ||
Packit 1fb8d4
		/* ClientMachineName */
Packit 1fb8d4
		!license_write_binary_blob(s, license->ClientMachineName))
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "PreferredKeyExchangeAlg: 0x%08"PRIX32"", PreferredKeyExchangeAlg);
Packit 1fb8d4
	WLog_DBG(TAG, "ClientRandom:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->ClientRandom, 32);
Packit 1fb8d4
	WLog_DBG(TAG, "EncryptedPremasterSecret");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->EncryptedPremasterSecret->data,
Packit 1fb8d4
			license->EncryptedPremasterSecret->length);
Packit 1fb8d4
	WLog_DBG(TAG, "ClientUserName (%"PRIu16"): %s", license->ClientUserName->length,
Packit 1fb8d4
			(char*) license->ClientUserName->data);
Packit 1fb8d4
	WLog_DBG(TAG, "ClientMachineName (%"PRIu16"): %s", license->ClientMachineName->length,
Packit 1fb8d4
			(char*) license->ClientMachineName->data);
Packit 1fb8d4
#endif
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send a NEW_LICENSE_REQUEST packet.\n
Packit 1fb8d4
 * @msdn{cc241918}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_answer_license_request(rdpLicense* license)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	BYTE *license_data = NULL;
Packit 1fb8d4
	int license_size = 0;
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
	char* username;
Packit 1fb8d4
Packit 1fb8d4
	if (!license->rdp->settings->OldLicenseBehaviour)
Packit 1fb8d4
		license_data = loadCalFile(license->rdp->settings, license->rdp->settings->ClientHostname, &license_size);
Packit 1fb8d4
Packit 1fb8d4
	if(license_data)
Packit 1fb8d4
	{
Packit 1fb8d4
		LICENSE_BLOB *calBlob = NULL;
Packit 1fb8d4
		BYTE signature[LICENSING_ENCRYPTION_KEY_LENGTH];
Packit 1fb8d4
Packit 1fb8d4
		DEBUG_LICENSE("Sending Saved License Packet");
Packit 1fb8d4
Packit 1fb8d4
		license->EncryptedHardwareId->type = BB_ENCRYPTED_DATA_BLOB;
Packit 1fb8d4
		if (!license_encrypt_and_MAC(license, license->HardwareId, HWID_LENGTH, license->EncryptedHardwareId, signature))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		calBlob = license_new_binary_blob(BB_DATA_BLOB);
Packit 1fb8d4
		if (!calBlob)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		calBlob->data = license_data;
Packit 1fb8d4
		calBlob->length = license_size;
Packit 1fb8d4
Packit 1fb8d4
		status = license_send_client_info(license, calBlob, signature);
Packit 1fb8d4
		license_free_binary_blob(calBlob);
Packit 1fb8d4
Packit 1fb8d4
		return status;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_LICENSE("Sending New License Packet");
Packit 1fb8d4
Packit 1fb8d4
	s = license_send_stream_init(license);
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	if (license->rdp->settings->Username != NULL)
Packit 1fb8d4
		username = license->rdp->settings->Username;
Packit 1fb8d4
	else
Packit 1fb8d4
		username = "username";
Packit 1fb8d4
Packit 1fb8d4
	license->ClientUserName->data = (BYTE*) username;
Packit 1fb8d4
	license->ClientUserName->length = strlen(username) + 1;
Packit 1fb8d4
	license->ClientMachineName->data = (BYTE*) license->rdp->settings->ClientHostname;
Packit 1fb8d4
	license->ClientMachineName->length = strlen(license->rdp->settings->ClientHostname) + 1;
Packit 1fb8d4
Packit 1fb8d4
	status = license_write_new_license_request_packet(license, s);
Packit 1fb8d4
Packit 1fb8d4
	license->ClientUserName->data = NULL;
Packit 1fb8d4
	license->ClientUserName->length = 0;
Packit 1fb8d4
	license->ClientMachineName->data = NULL;
Packit 1fb8d4
	license->ClientMachineName->length = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!status)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Release(s);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return license_send(license, s, NEW_LICENSE_REQUEST);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write Client Challenge Response Packet.\n
Packit 1fb8d4
 * @msdn{cc241922}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param mac_data signature
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_write_platform_challenge_response_packet(rdpLicense* license, wStream* s, const BYTE* macData)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!license_write_binary_blob(s, license->EncryptedPlatformChallengeResponse) || /* EncryptedPlatformChallengeResponse */
Packit 1fb8d4
		!license_write_binary_blob(s, license->EncryptedHardwareId) || /* EncryptedHWID */
Packit 1fb8d4
		!Stream_EnsureRemainingCapacity(s, 16))
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write(s, macData, 16); /* MACData */
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send Client Challenge Response Packet.\n
Packit 1fb8d4
 * @msdn{cc241922}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_send_platform_challenge_response_packet(rdpLicense* license)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	wStream *challengeRespData;
Packit 1fb8d4
	int length;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	BYTE mac_data[16];
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_LICENSE("Sending Platform Challenge Response Packet");
Packit 1fb8d4
	s = license_send_stream_init(license);
Packit 1fb8d4
	license->EncryptedPlatformChallenge->type = BB_DATA_BLOB;
Packit 1fb8d4
Packit 1fb8d4
	/* prepare the PLATFORM_CHALLENGE_RESPONSE_DATA */
Packit 1fb8d4
	challengeRespData = Stream_New(NULL, 8 + license->PlatformChallenge->length);
Packit 1fb8d4
	if (!challengeRespData)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	Stream_Write_UINT16(challengeRespData, 0x0100); /* wVersion */
Packit 1fb8d4
	Stream_Write_UINT16(challengeRespData, OTHER_PLATFORM_CHALLENGE_TYPE); /* wClientType */
Packit 1fb8d4
	Stream_Write_UINT16(challengeRespData, LICENSE_DETAIL_DETAIL); /* wLicenseDetailLevel */
Packit 1fb8d4
	Stream_Write_UINT16(challengeRespData, license->PlatformChallenge->length); /* cbChallenge */
Packit 1fb8d4
	Stream_Write(challengeRespData, license->PlatformChallenge->data, license->PlatformChallenge->length); /* pbChallenge */
Packit 1fb8d4
	Stream_SealLength(challengeRespData);
Packit 1fb8d4
Packit 1fb8d4
	/* compute MAC of PLATFORM_CHALLENGE_RESPONSE_DATA + HWID */
Packit 1fb8d4
	length = Stream_Length(challengeRespData) + HWID_LENGTH;
Packit 1fb8d4
	buffer = (BYTE*) malloc(length);
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Free(challengeRespData, TRUE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	CopyMemory(buffer, Stream_Buffer(challengeRespData), Stream_Length(challengeRespData));
Packit 1fb8d4
	CopyMemory(&buffer[Stream_Length(challengeRespData)], license->HardwareId, HWID_LENGTH);
Packit 1fb8d4
	status = security_mac_data(license->MacSaltKey, buffer, length, mac_data);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
Packit 1fb8d4
	if (!status)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Free(challengeRespData, TRUE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	license->EncryptedHardwareId->type = BB_ENCRYPTED_DATA_BLOB;
Packit 1fb8d4
	if (!license_rc4_with_licenseKey(license, license->HardwareId, HWID_LENGTH, license->EncryptedHardwareId))
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Free(challengeRespData, TRUE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = license_rc4_with_licenseKey(license, Stream_Buffer(challengeRespData),
Packit 1fb8d4
			Stream_Length(challengeRespData),
Packit 1fb8d4
			license->EncryptedPlatformChallengeResponse);
Packit 1fb8d4
	Stream_Free(challengeRespData, TRUE);
Packit 1fb8d4
	if (!status)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_LICENSE
Packit 1fb8d4
	WLog_DBG(TAG, "LicensingEncryptionKey:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->LicensingEncryptionKey, 16);
Packit 1fb8d4
	WLog_DBG(TAG, "HardwareId:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->HardwareId, HWID_LENGTH);
Packit 1fb8d4
	WLog_DBG(TAG, "EncryptedHardwareId:");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, license->EncryptedHardwareId->data, HWID_LENGTH);
Packit 1fb8d4
#endif
Packit 1fb8d4
	if (license_write_platform_challenge_response_packet(license, s, mac_data))
Packit 1fb8d4
		return license_send(license, s, PLATFORM_CHALLENGE_RESPONSE);
Packit 1fb8d4
Packit 1fb8d4
	Stream_Release(s);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send Server License Error - Valid Client Packet.\n
Packit 1fb8d4
 * @msdn{cc241922}
Packit 1fb8d4
 * @param license license module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL license_send_valid_client_error_packet(rdpLicense* license)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s = license_send_stream_init(license);
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_LICENSE("Sending Error Alert Packet");
Packit 1fb8d4
	Stream_Write_UINT32(s, STATUS_VALID_CLIENT); /* dwErrorCode */
Packit 1fb8d4
	Stream_Write_UINT32(s, ST_NO_TRANSITION); /* dwStateTransition */
Packit 1fb8d4
Packit 1fb8d4
	if (license_write_binary_blob(s, license->ErrorInfo))
Packit 1fb8d4
		return license_send(license, s, ERROR_ALERT);
Packit 1fb8d4
Packit 1fb8d4
	Stream_Release(s);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Instantiate new license module.
Packit 1fb8d4
 * @param rdp RDP module
Packit 1fb8d4
 * @return new license module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
rdpLicense* license_new(rdpRdp* rdp)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpLicense* license;
Packit 1fb8d4
	license = (rdpLicense*) calloc(1, sizeof(rdpLicense));
Packit 1fb8d4
	if (!license)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	license->rdp = rdp;
Packit 1fb8d4
	license->state = LICENSE_STATE_AWAIT;
Packit 1fb8d4
	if (!(license->certificate = certificate_new()))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->ProductInfo = license_new_product_info()))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->ErrorInfo = license_new_binary_blob(BB_ERROR_BLOB)))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->KeyExchangeList = license_new_binary_blob(BB_KEY_EXCHG_ALG_BLOB)))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->ServerCertificate = license_new_binary_blob(BB_CERTIFICATE_BLOB)))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->ClientUserName = license_new_binary_blob(BB_CLIENT_USER_NAME_BLOB)))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->ClientMachineName = license_new_binary_blob(BB_CLIENT_MACHINE_NAME_BLOB)))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->PlatformChallenge = license_new_binary_blob(BB_ANY_BLOB)))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->EncryptedPlatformChallenge = license_new_binary_blob(BB_ANY_BLOB)))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->EncryptedPlatformChallengeResponse = license_new_binary_blob(BB_ENCRYPTED_DATA_BLOB)))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->EncryptedPremasterSecret = license_new_binary_blob(BB_ANY_BLOB)))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->EncryptedHardwareId = license_new_binary_blob(BB_ENCRYPTED_DATA_BLOB)))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
	if (!(license->ScopeList = license_new_scope_list()))
Packit 1fb8d4
		goto out_error;
Packit 1fb8d4
Packit 1fb8d4
	license_generate_randoms(license);
Packit 1fb8d4
Packit 1fb8d4
	return license;
Packit 1fb8d4
Packit 1fb8d4
out_error:
Packit 1fb8d4
	license_free(license);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Free license module.
Packit 1fb8d4
 * @param license license module to be freed
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void license_free(rdpLicense* license)
Packit 1fb8d4
{
Packit 1fb8d4
	if (license)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(license->Modulus);
Packit 1fb8d4
		certificate_free(license->certificate);
Packit 1fb8d4
		license_free_product_info(license->ProductInfo);
Packit 1fb8d4
		license_free_binary_blob(license->ErrorInfo);
Packit 1fb8d4
		license_free_binary_blob(license->KeyExchangeList);
Packit 1fb8d4
		license_free_binary_blob(license->ServerCertificate);
Packit 1fb8d4
		license_free_binary_blob(license->ClientUserName);
Packit 1fb8d4
		license_free_binary_blob(license->ClientMachineName);
Packit 1fb8d4
		license_free_binary_blob(license->PlatformChallenge);
Packit 1fb8d4
		license_free_binary_blob(license->EncryptedPlatformChallenge);
Packit 1fb8d4
		license_free_binary_blob(license->EncryptedPlatformChallengeResponse);
Packit 1fb8d4
		license_free_binary_blob(license->EncryptedPremasterSecret);
Packit 1fb8d4
		license_free_binary_blob(license->EncryptedHardwareId);
Packit 1fb8d4
		license_free_scope_list(license->ScopeList);
Packit 1fb8d4
		free(license);
Packit 1fb8d4
	}
Packit 1fb8d4
}