From b6e6575bf63e8ac6c8353b0670dcbcba4a89d078 Mon Sep 17 00:00:00 2001 From: David Fort Date: Wed, 31 Oct 2018 10:27:31 +0100 Subject: [PATCH] license: support CAL license This patch simplifies the licensing code mutualizing encryption / decryption routines. It also adds the support for client_info packet that allows to send a previously saved CAL file. --- client/common/cmdline.c | 4 + client/common/cmdline.h | 1 + include/freerdp/settings.h | 3 +- libfreerdp/core/license.c | 826 +++++++++++++++++++++++++------------ libfreerdp/core/license.h | 1 + 5 files changed, 581 insertions(+), 254 deletions(-) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index d8880146e..423049bf3 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -2679,6 +2679,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->DesktopOrientation = val; } + CommandLineSwitchCase(arg, "old-license") + { + settings->OldLicenseBehaviour = TRUE; + } CommandLineSwitchCase(arg, "scale") { unsigned long scaleFactor = strtoul(arg->Value, NULL, 0); diff --git a/client/common/cmdline.h b/client/common/cmdline.h index e2f700c77..5d1ccab3d 100644 --- a/client/common/cmdline.h +++ b/client/common/cmdline.h @@ -126,6 +126,7 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "nsc", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "nscodec", "NSCodec support" }, { "offscreen-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "offscreen bitmap cache" }, { "orientation", COMMAND_LINE_VALUE_REQUIRED, "0|90|180|270", NULL, NULL, -1, NULL, "Orientation of display in degrees" }, + { "old-license", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Use the old license workflow (no CAL and hwId set to 0)"}, { "p", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Password" }, { "parallel", COMMAND_LINE_VALUE_OPTIONAL, "[,]", NULL, NULL, -1, NULL, "Redirect parallel device" }, { "parent-window", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Parent window id" }, diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 9feb945f3..e816f3f8d 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -1156,7 +1156,8 @@ struct rdp_settings ALIGN64 BOOL AuthenticationOnly; /* 1603 */ ALIGN64 BOOL CredentialsFromStdin; /* 1604 */ ALIGN64 BOOL UnmapButtons; /* 1605 */ - UINT64 padding1664[1664 - 1606]; /* 1606 */ + ALIGN64 BOOL OldLicenseBehaviour; /* 1606 */ + UINT64 padding1664[1664 - 1607]; /* 1607 */ /* Names */ ALIGN64 char* ComputerName; /* 1664 */ diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c index ffbdbddb6..f15c7c272 100644 --- a/libfreerdp/core/license.c +++ b/libfreerdp/core/license.c @@ -4,6 +4,7 @@ * * Copyright 2011-2013 Marc-Andre Moreau * Copyright 2014 Norbert Federa + * Copyright 2018 David Fort * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +25,9 @@ #include #include +#include +#include + #include #include "redirection.h" @@ -33,8 +37,10 @@ #define TAG FREERDP_TAG("core.license") -/* #define LICENSE_NULL_CLIENT_RANDOM 1 */ -/* #define LICENSE_NULL_PREMASTER_SECRET 1 */ +#if 0 +#define LICENSE_NULL_CLIENT_RANDOM 1 +#define LICENSE_NULL_PREMASTER_SECRET 1 +#endif static wStream* license_send_stream_init(rdpLicense* license); @@ -42,7 +48,6 @@ static void license_generate_randoms(rdpLicense* license); static BOOL license_generate_keys(rdpLicense* license); static BOOL license_generate_hwid(rdpLicense* license); static BOOL license_encrypt_premaster_secret(rdpLicense* license); -static BOOL license_decrypt_platform_challenge(rdpLicense* license); static LICENSE_PRODUCT_INFO* license_new_product_info(void); static void license_free_product_info(LICENSE_PRODUCT_INFO* productInfo); @@ -51,7 +56,7 @@ static BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productI static LICENSE_BLOB* license_new_binary_blob(UINT16 type); static void license_free_binary_blob(LICENSE_BLOB* blob); static BOOL license_read_binary_blob(wStream* s, LICENSE_BLOB* blob); -static BOOL license_write_binary_blob(wStream* s, LICENSE_BLOB* blob); +static BOOL license_write_binary_blob(wStream* s, const LICENSE_BLOB* blob); static SCOPE_LIST* license_new_scope_list(void); static void license_free_scope_list(SCOPE_LIST* scopeList); @@ -59,16 +64,18 @@ static BOOL license_read_scope_list(wStream* s, SCOPE_LIST* scopeList); static BOOL license_read_license_request_packet(rdpLicense* license, wStream* s); static BOOL license_read_platform_challenge_packet(rdpLicense* license, wStream* s); -static void license_read_new_license_packet(rdpLicense* license, wStream* s); -static void license_read_upgrade_license_packet(rdpLicense* license, wStream* s); +static BOOL license_read_new_or_upgrade_license_packet(rdpLicense* license, wStream* s); static BOOL license_read_error_alert_packet(rdpLicense* license, wStream* s); static BOOL license_write_new_license_request_packet(rdpLicense* license, wStream* s); -static BOOL license_send_new_license_request_packet(rdpLicense* license); +static BOOL license_answer_license_request(rdpLicense* license); -static BOOL license_write_platform_challenge_response_packet( - rdpLicense* license, wStream* s, BYTE* mac_data); +static BOOL license_write_platform_challenge_response_packet(rdpLicense* license, wStream* s, + const BYTE* mac_data); static BOOL license_send_platform_challenge_response_packet(rdpLicense* license); +static BOOL license_send_client_info(rdpLicense* license, const LICENSE_BLOB *calBlob, BYTE* signature); + +#define PLATFORMID (CLIENT_OS_ID_WINNT_POST_52 | CLIENT_IMAGE_ID_MICROSOFT) #ifdef WITH_DEBUG_LICENSE @@ -116,14 +123,14 @@ static const char* const state_transitions[] = "ST_RESEND_LAST_MESSAGE" }; -static void license_print_product_info(LICENSE_PRODUCT_INFO* productInfo) +static void license_print_product_info(const LICENSE_PRODUCT_INFO* productInfo) { char* CompanyName = NULL; char* ProductId = NULL; ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) productInfo->pbCompanyName, - productInfo->cbCompanyName / 2, &CompanyName, 0, NULL, NULL); + productInfo->cbCompanyName / 2, &CompanyName, 0, NULL, NULL); ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) productInfo->pbProductId, - productInfo->cbProductId / 2, &ProductId, 0, NULL, NULL); + productInfo->cbProductId / 2, &ProductId, 0, NULL, NULL); WLog_INFO(TAG, "ProductInfo:"); WLog_INFO(TAG, "\tdwVersion: 0x%08"PRIX32"", productInfo->dwVersion); WLog_INFO(TAG, "\tCompanyName: %s", CompanyName); @@ -132,21 +139,172 @@ static void license_print_product_info(LICENSE_PRODUCT_INFO* productInfo) free(ProductId); } -static void license_print_scope_list(SCOPE_LIST* scopeList) +static void license_print_scope_list(const SCOPE_LIST* scopeList) { int index; - LICENSE_BLOB* scope; + const LICENSE_BLOB* scope; WLog_INFO(TAG, "ScopeList (%"PRIu32"):", scopeList->count); for (index = 0; index < scopeList->count; index++) { scope = &scopeList->array[index]; - WLog_INFO(TAG, "\t%s", (char*) scope->data); + WLog_INFO(TAG, "\t%s", (const char*) scope->data); } } - #endif + +static const char licenseStore[] = "licenses"; + +static BOOL computeCalHash(const char *hostname, char *hashStr) +{ + WINPR_DIGEST_CTX* sha1 = NULL; + BOOL ret = FALSE; + BYTE hash[20]; + int i; + + if (!(sha1 = winpr_Digest_New())) + goto out; + if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1)) + goto out; + if (!winpr_Digest_Update(sha1, (const BYTE *)hostname, strlen(hostname))) + goto out; + if (!winpr_Digest_Final(sha1, hash, sizeof(hash))) + goto out; + + for (i = 0; i < sizeof(hash); i++, hashStr += 2) + sprintf_s(hashStr, 3, "%.2x", hash[i]); + + ret = TRUE; +out: + winpr_Digest_Free(sha1); + return ret; +} + +static BOOL saveCal(rdpSettings *settings, const BYTE *data, int length, char *hostname) +{ + char hash[41]; + FILE *fp; + char *licenseStorePath = NULL; + char filename[MAX_PATH], filenameNew[MAX_PATH]; + char *filepath = NULL, *filepathNew = NULL; + size_t written; + BOOL ret = FALSE; + + if (!PathFileExistsA(settings->ConfigPath)) + { + if (!PathMakePathA(settings->ConfigPath, 0)) + { + WLog_ERR(TAG, "error creating directory '%s'", settings->ConfigPath); + goto out; + } + WLog_INFO(TAG, "creating directory %s", settings->ConfigPath); + } + + if (!(licenseStorePath = GetCombinedPath(settings->ConfigPath, licenseStore))) + goto out; + + if (!PathFileExistsA(licenseStorePath)) + { + if (!PathMakePathA(licenseStorePath, 0)) + { + WLog_ERR(TAG, "error creating directory '%s'", licenseStorePath); + goto out; + } + WLog_INFO(TAG, "creating directory %s", licenseStorePath); + } + + if (!computeCalHash(hostname, hash)) + goto out; + sprintf_s(filename, sizeof(filename)-1, "%s.cal", hash); + sprintf_s(filenameNew, sizeof(filenameNew)-1, "%s.cal.new", hash); + + if (!(filepath = GetCombinedPath(licenseStorePath, filename))) + goto out; + + if (!(filepathNew = GetCombinedPath(licenseStorePath, filenameNew))) + goto out; + + fp = fopen(filepathNew, "wb"); + if (!fp) + goto out; + + written = fwrite(data, length, 1, fp); + fclose(fp); + + if (written != 1) + { + DeleteFile(filepathNew); + goto out; + } + + ret = MoveFileEx(filepathNew, filepath, MOVEFILE_REPLACE_EXISTING); + +out: + free(filepathNew); + free(filepath); + free(licenseStorePath); + return ret; +} + +static BYTE *loadCalFile(rdpSettings *settings, const char* hostname, int *dataLen) +{ + char *licenseStorePath = NULL, *calPath = NULL; + char calFilename[MAX_PATH]; + char hash[41]; + int length, status; + FILE *fp; + BYTE *ret = NULL; + + if (!computeCalHash(hostname, hash)) + { + WLog_ERR(TAG, "loadCalFile: unable to compute hostname hash"); + return NULL; + } + + sprintf_s(calFilename, sizeof(calFilename)-1, "%s.cal", hash); + + if (!(licenseStorePath = GetCombinedPath(settings->ConfigPath, licenseStore))) + return NULL; + + if (!(calPath = GetCombinedPath(licenseStorePath, calFilename))) + goto error_path; + + fp = fopen(calPath, "rb"); + if (!fp) + goto error_open; + + _fseeki64(fp, 0, SEEK_END); + length = _ftelli64(fp); + _fseeki64(fp, 0, SEEK_SET); + + ret = (BYTE *)malloc(length); + if (!ret) + goto error_malloc; + + status = fread(ret, length, 1, fp); + if (status <= 0) + goto error_read; + + *dataLen = length; + + fclose(fp); + free(calPath); + free(licenseStorePath); + return ret; + +error_read: + free(ret); +error_malloc: + fclose(fp); +error_open: + free(calPath); +error_path: + free(licenseStorePath); + return NULL; +} + + /** * Read a licensing preamble.\n * @msdn{cc240480} @@ -200,6 +358,7 @@ wStream* license_send_stream_init(rdpLicense* license) { wStream* s; BOOL do_crypt = license->rdp->do_crypt; + license->rdp->sec_flags = SEC_LICENSE_PKT; /** @@ -217,17 +376,16 @@ wStream* license_send_stream_init(rdpLicense* license) } s = rdp_send_stream_init(license->rdp); - if (!s) return NULL; + license->rdp->do_crypt = do_crypt; license->PacketHeaderLength = Stream_GetPosition(s); - if (!Stream_SafeSeek(s, LICENSE_PREAMBLE_LENGTH)) goto fail; - return s; + fail: Stream_Release(s); return NULL; @@ -240,71 +398,15 @@ fail: * @param s stream */ -static BOOL license_send(rdpLicense* license, BYTE type) +static BOOL license_send(rdpLicense* license, wStream* s, BYTE type) { - BOOL rc = FALSE; size_t length; BYTE flags; UINT16 wMsgSize; - rdpRdp* rdp; - wStream* s = license_send_stream_init(license); + rdpRdp* rdp = license->rdp; + BOOL ret; - if (!s) - return FALSE; - - if (!license || !license->rdp) - goto fail; - - rdp = license->rdp; DEBUG_LICENSE("Sending %s Packet", LICENSE_MESSAGE_STRINGS[type & 0x1F]); - - switch (type) - { - case NEW_LICENSE_REQUEST: - if (!license_write_new_license_request_packet(license, s)) - goto fail; - - break; - - case PLATFORM_CHALLENGE_RESPONSE: - { - BYTE mac_data[16]; - size_t length = license->PlatformChallenge->length + HWID_LENGTH; - BYTE* buffer = (BYTE*) malloc(length); - - if (!buffer) - goto fail; - - CopyMemory(buffer, license->PlatformChallenge->data, license->PlatformChallenge->length); - CopyMemory(&buffer[license->PlatformChallenge->length], license->HardwareId, HWID_LENGTH); - rc = security_mac_data(license->MacSaltKey, buffer, length, mac_data); - free(buffer); - - if (!rc) - goto fail; - - if (!license_write_platform_challenge_response_packet(license, s, mac_data)) - goto fail; - } - break; - - case ERROR_ALERT: - { - if (!Stream_EnsureRemainingCapacity(s, 8)) - goto fail; - - Stream_Write_UINT32(s, STATUS_VALID_CLIENT); /* dwErrorCode */ - Stream_Write_UINT32(s, ST_NO_TRANSITION); /* dwStateTransition */ - - if (!license_write_binary_blob(s, license->ErrorInfo)) - goto fail; - } - break; - - default: - goto fail; - } - length = Stream_GetPosition(s); wMsgSize = length - license->PacketHeaderLength; Stream_SetPosition(s, license->PacketHeaderLength); @@ -318,21 +420,17 @@ static BOOL license_send(rdpLicense* license, BYTE type) if (!rdp->settings->ServerMode) flags |= EXTENDED_ERROR_MSG_SUPPORTED; - if (!license_write_preamble(s, type, flags, wMsgSize)) - goto fail; + if(!license_write_preamble(s, type, flags, wMsgSize)) + return FALSE; #ifdef WITH_DEBUG_LICENSE - WLog_DBG(TAG, "Sending %s Packet, length %"PRIu16"", LICENSE_MESSAGE_STRINGS[type & 0x1F], - wMsgSize); + WLog_DBG(TAG, "Sending %s Packet, length %"PRIu16"", LICENSE_MESSAGE_STRINGS[type & 0x1F], wMsgSize); winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(s) - LICENSE_PREAMBLE_LENGTH, wMsgSize); #endif Stream_SetPosition(s, length); - rc = rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID); + ret = rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID); rdp->sec_flags = 0; - return rc; -fail: - Stream_Release(s); - return FALSE; + return ret; } /** @@ -378,7 +476,6 @@ int license_recv(rdpLicense* license, wStream* s) Stream_Rewind(s, RDP_SECURITY_HEADER_LENGTH); status = rdp_recv_out_of_sequence_pdu(license->rdp, s); - if (status < 0) { WLog_ERR(TAG, "unexpected license packet."); @@ -399,9 +496,8 @@ int license_recv(rdpLicense* license, wStream* s) if (!license_read_license_request_packet(license, s)) return -1; - if (!license_send_new_license_request_packet(license)) + if (!license_answer_license_request(license)) return -1; - break; case PLATFORM_CHALLENGE: @@ -410,26 +506,22 @@ int license_recv(rdpLicense* license, wStream* s) if (!license_send_platform_challenge_response_packet(license)) return -1; - break; case NEW_LICENSE: - license_read_new_license_packet(license, s); - break; - case UPGRADE_LICENSE: - license_read_upgrade_license_packet(license, s); + if (!license_read_new_or_upgrade_license_packet(license, s)) + return -1; break; case ERROR_ALERT: if (!license_read_error_alert_packet(license, s)) return -1; - break; default: WLog_ERR(TAG, "invalid bMsgType:%"PRIu8"", bMsgType); - return FALSE; + return -1; } return 0; @@ -437,12 +529,15 @@ int license_recv(rdpLicense* license, wStream* s) void license_generate_randoms(rdpLicense* license) { +#ifdef LICENSE_NULL_CLIENT_RANDOM ZeroMemory(license->ClientRandom, CLIENT_RANDOM_LENGTH); /* ClientRandom */ - ZeroMemory(license->PremasterSecret, PREMASTER_SECRET_LENGTH); /* PremasterSecret */ -#ifndef LICENSE_NULL_CLIENT_RANDOM +#else winpr_RAND(license->ClientRandom, CLIENT_RANDOM_LENGTH); /* ClientRandom */ #endif -#ifndef LICENSE_NULL_PREMASTER_SECRET + +#ifdef LICENSE_NULL_PREMASTER_SECRET + ZeroMemory(license->PremasterSecret, PREMASTER_SECRET_LENGTH); /* PremasterSecret */ +#else winpr_RAND(license->PremasterSecret, PREMASTER_SECRET_LENGTH); /* PremasterSecret */ #endif } @@ -452,25 +547,24 @@ void license_generate_randoms(rdpLicense* license) * @param license license module */ -BOOL license_generate_keys(rdpLicense* license) +static BOOL license_generate_keys(rdpLicense* license) { BOOL ret; if ( - /* MasterSecret */ - !security_master_secret(license->PremasterSecret, license->ClientRandom, - license->ServerRandom, license->MasterSecret) || - /* SessionKeyBlob */ - !security_session_key_blob(license->MasterSecret, license->ClientRandom, - license->ServerRandom, license->SessionKeyBlob)) + /* MasterSecret */ + !security_master_secret(license->PremasterSecret, license->ClientRandom, + license->ServerRandom, license->MasterSecret) || + /* SessionKeyBlob */ + !security_session_key_blob(license->MasterSecret, license->ClientRandom, + license->ServerRandom, license->SessionKeyBlob)) { return FALSE; } - security_mac_salt_key(license->SessionKeyBlob, license->ClientRandom, - license->ServerRandom, license->MacSaltKey); /* MacSaltKey */ + license->ServerRandom, license->MacSaltKey); /* MacSaltKey */ ret = security_licensing_encryption_key(license->SessionKeyBlob, license->ClientRandom, - license->ServerRandom, license->LicensingEncryptionKey); /* LicensingEncryptionKey */ + license->ServerRandom, license->LicensingEncryptionKey); /* LicensingEncryptionKey */ #ifdef WITH_DEBUG_LICENSE WLog_DBG(TAG, "ClientRandom:"); winpr_HexDump(TAG, WLOG_DEBUG, license->ClientRandom, CLIENT_RANDOM_LENGTH); @@ -497,18 +591,30 @@ BOOL license_generate_keys(rdpLicense* license) BOOL license_generate_hwid(rdpLicense* license) { + const BYTE *hashTarget; + size_t targetLen; BYTE macAddress[6]; - ZeroMemory(macAddress, sizeof(macAddress)); + ZeroMemory(license->HardwareId, HWID_LENGTH); + if (license->rdp->settings->OldLicenseBehaviour) + { + ZeroMemory(macAddress, sizeof(macAddress)); + hashTarget = macAddress; + targetLen = sizeof(macAddress); + } + else + { + const char *hostname = license->rdp->settings->ClientHostname; + hashTarget = (const BYTE *)hostname; + targetLen = strlen(hostname); + } + /* 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) */ /* 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 */ /* which will already be encrypted under FIPS, so the use of MD5 here is not for sensitive data protection. */ - if (!winpr_Digest_Allow_FIPS(WINPR_MD_MD5, macAddress, sizeof(macAddress), - &license->HardwareId[HWID_PLATFORM_ID_LENGTH], WINPR_MD5_DIGEST_LENGTH)) - return FALSE; - - return TRUE; + return winpr_Digest_Allow_FIPS(WINPR_MD_MD5, hashTarget, targetLen, + &license->HardwareId[HWID_PLATFORM_ID_LENGTH], WINPR_MD5_DIGEST_LENGTH); } BOOL license_get_server_rsa_public_key(rdpLicense* license) @@ -521,8 +627,8 @@ BOOL license_get_server_rsa_public_key(rdpLicense* license) if (license->ServerCertificate->length < 1) { if (!certificate_read_server_certificate(license->certificate, - settings->ServerCertificate, settings->ServerCertificateLength)) - return FALSE; + settings->ServerCertificate, settings->ServerCertificateLength)) + return FALSE; } Exponent = license->certificate->cert_info.exponent; @@ -531,10 +637,8 @@ BOOL license_get_server_rsa_public_key(rdpLicense* license) CopyMemory(license->Exponent, Exponent, 4); license->ModulusLength = ModulusLength; license->Modulus = (BYTE*) malloc(ModulusLength); - if (!license->Modulus) return FALSE; - CopyMemory(license->Modulus, Modulus, ModulusLength); return TRUE; } @@ -552,8 +656,8 @@ BOOL license_encrypt_premaster_secret(rdpLicense* license) WLog_DBG(TAG, "Exponent:"); winpr_HexDump(TAG, WLOG_DEBUG, license->Exponent, 4); #endif - EncryptedPremasterSecret = (BYTE*) calloc(1, license->ModulusLength); + EncryptedPremasterSecret = (BYTE*) calloc(1, license->ModulusLength); if (!EncryptedPremasterSecret) return FALSE; @@ -561,43 +665,78 @@ BOOL license_encrypt_premaster_secret(rdpLicense* license) license->EncryptedPremasterSecret->length = PREMASTER_SECRET_LENGTH; #ifndef LICENSE_NULL_PREMASTER_SECRET license->EncryptedPremasterSecret->length = - crypto_rsa_public_encrypt(license->PremasterSecret, PREMASTER_SECRET_LENGTH, - license->ModulusLength, license->Modulus, license->Exponent, EncryptedPremasterSecret); + crypto_rsa_public_encrypt(license->PremasterSecret, PREMASTER_SECRET_LENGTH, + license->ModulusLength, license->Modulus, license->Exponent, EncryptedPremasterSecret); #endif license->EncryptedPremasterSecret->data = EncryptedPremasterSecret; return TRUE; } -BOOL license_decrypt_platform_challenge(rdpLicense* license) +static BOOL license_rc4_with_licenseKey(const rdpLicense* license, const BYTE *input, size_t len, LICENSE_BLOB *target) { - BOOL rc; WINPR_RC4_CTX* rc4; - license->PlatformChallenge->data = (BYTE*)malloc(license->EncryptedPlatformChallenge->length); + BYTE *buffer = NULL; - if (!license->PlatformChallenge->data) + rc4 = winpr_RC4_New_Allow_FIPS(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH); + if (!rc4) return FALSE; - license->PlatformChallenge->length = license->EncryptedPlatformChallenge->length; + buffer = (BYTE*) realloc(target->data, len); + if (!buffer) + goto error_buffer; - /* Allow FIPS override for use of RC4 here, this is only used for decrypting the MACData field of the */ - /* Server Platform Challenge packet (from MS-RDPELE section 2.2.2.4). This is for RDP licensing packets */ - /* which will already be encrypted under FIPS, so the use of RC4 here is not for sensitive data protection. */ - if ((rc4 = winpr_RC4_New_Allow_FIPS(license->LicensingEncryptionKey, - LICENSING_ENCRYPTION_KEY_LENGTH)) == NULL) - { - free(license->PlatformChallenge->data); - license->PlatformChallenge->data = NULL; - license->PlatformChallenge->length = 0; - return FALSE; - } + target->data = buffer; + target->length = len; + + if (!winpr_RC4_Update(rc4, len, input, buffer)) + goto error_update; - rc = winpr_RC4_Update(rc4, license->EncryptedPlatformChallenge->length, - license->EncryptedPlatformChallenge->data, - license->PlatformChallenge->data); winpr_RC4_Free(rc4); - return rc; + return TRUE; + +error_update: + free(buffer); +error_buffer: + winpr_RC4_Free(rc4); + return FALSE; } +/** + * Encrypt the input using the license key and MAC the input for a signature + * + * @param license rdpLicense to get keys and salt from + * @param input the input data to encrypt and MAC + * @param len size of input + * @param target a target LICENSE_BLOB where the encrypted input will be stored + * @param mac the signature buffer (16 bytes) + * @return if the operation completed successfully + */ +static BOOL license_encrypt_and_MAC(rdpLicense* license, const BYTE *input, size_t len, LICENSE_BLOB *target, BYTE *mac) +{ + return license_rc4_with_licenseKey(license, input, len, target) && + security_mac_data(license->MacSaltKey, input, len, mac); +} + +/** + * Decrypt the input using the license key and check the MAC + * + * @param license rdpLicense to get keys and salt from + * @param input the input data to decrypt and MAC + * @param len size of input + * @param target a target LICENSE_BLOB where the decrypted input will be stored + * @param mac the signature buffer (16 bytes) + * @return if the operation completed successfully + */ +static BOOL license_decrypt_and_check_MAC(rdpLicense* license, const BYTE *input, size_t len, LICENSE_BLOB *target, const BYTE *packetMac) +{ + BYTE macData[16]; + + return license_rc4_with_licenseKey(license, input, len, target) && + security_mac_data(license->MacSaltKey, target->data, len, macData) && + (memcmp(packetMac, macData, sizeof(macData)) == 0); +} + + /** * Read Product Information (PRODUCT_INFO).\n * @msdn{cc241915} @@ -622,10 +761,8 @@ BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo) productInfo->pbProductId = NULL; productInfo->pbCompanyName = (BYTE*) malloc(productInfo->cbCompanyName); - if (!productInfo->pbCompanyName) return FALSE; - Stream_Read(s, productInfo->pbCompanyName, productInfo->cbCompanyName); if (Stream_GetRemainingLength(s) < 4) @@ -640,12 +777,11 @@ BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo) goto out_fail; productInfo->pbProductId = (BYTE*) malloc(productInfo->cbProductId); - if (!productInfo->pbProductId) goto out_fail; - Stream_Read(s, productInfo->pbProductId, productInfo->cbProductId); return TRUE; + out_fail: free(productInfo->pbCompanyName); free(productInfo->pbProductId); @@ -664,10 +800,8 @@ LICENSE_PRODUCT_INFO* license_new_product_info() { LICENSE_PRODUCT_INFO* productInfo; productInfo = (LICENSE_PRODUCT_INFO*) malloc(sizeof(LICENSE_PRODUCT_INFO)); - if (!productInfo) return NULL; - productInfo->dwVersion = 0; productInfo->cbCompanyName = 0; productInfo->pbCompanyName = NULL; @@ -722,15 +856,13 @@ BOOL license_read_binary_blob(wStream* s, LICENSE_BLOB* blob) if ((blob->type != wBlobType) && (blob->type != BB_ANY_BLOB)) { WLog_ERR(TAG, "license binary blob type (0x%"PRIx16") does not match expected type (0x%"PRIx16").", - wBlobType, blob->type); + wBlobType, blob->type); } blob->type = wBlobType; blob->data = (BYTE*) malloc(blob->length); - if (!blob->data) return FALSE; - Stream_Read(s, blob->data, blob->length); /* blobData */ return TRUE; } @@ -742,25 +874,20 @@ BOOL license_read_binary_blob(wStream* s, LICENSE_BLOB* blob) * @param blob license binary blob */ -BOOL license_write_binary_blob(wStream* s, LICENSE_BLOB* blob) +BOOL license_write_binary_blob(wStream* s, const LICENSE_BLOB* blob) { if (!Stream_EnsureRemainingCapacity(s, blob->length + 4)) - { - Stream_Release(s); return FALSE; - } Stream_Write_UINT16(s, blob->type); /* wBlobType (2 bytes) */ Stream_Write_UINT16(s, blob->length); /* wBlobLen (2 bytes) */ if (blob->length > 0) Stream_Write(s, blob->data, blob->length); /* blobData */ - return TRUE; } -static BOOL license_write_encrypted_premaster_secret_blob(wStream* s, LICENSE_BLOB* blob, - UINT32 ModulusLength) +BOOL license_write_encrypted_premaster_secret_blob(wStream* s, const LICENSE_BLOB* blob, UINT32 ModulusLength) { UINT32 length; length = ModulusLength + 8; @@ -773,7 +900,6 @@ static BOOL license_write_encrypted_premaster_secret_blob(wStream* s, LICENSE_BL if (!Stream_EnsureRemainingCapacity(s, length + 4)) return FALSE; - Stream_Write_UINT16(s, blob->type); /* wBlobType (2 bytes) */ Stream_Write_UINT16(s, length); /* wBlobLen (2 bytes) */ @@ -794,10 +920,8 @@ LICENSE_BLOB* license_new_binary_blob(UINT16 type) { LICENSE_BLOB* blob; blob = (LICENSE_BLOB*) calloc(1, sizeof(LICENSE_BLOB)); - if (blob) blob->type = type; - return blob; } @@ -838,7 +962,6 @@ BOOL license_read_scope_list(wStream* s, SCOPE_LIST* scopeList) scopeList->count = scopeCount; scopeList->array = (LICENSE_BLOB*) calloc(scopeCount, sizeof(LICENSE_BLOB)); - if (!scopeList->array) return FALSE; @@ -894,6 +1017,46 @@ void license_free_scope_list(SCOPE_LIST* scopeList) free(scopeList); } +BOOL license_send_client_info(rdpLicense *license, const LICENSE_BLOB *calBlob, BYTE *signature) +{ + wStream *s; + + /* Client License Information: */ + UINT32 PlatformId = PLATFORMID; + UINT32 PreferredKeyExchangeAlg = KEY_EXCHANGE_ALG_RSA; + + s = license_send_stream_init(license); + if (!s) + return FALSE; + + Stream_Write_UINT32(s, PreferredKeyExchangeAlg); /* PreferredKeyExchangeAlg (4 bytes) */ + Stream_Write_UINT32(s, PlatformId); /* PlatformId (4 bytes) */ + + /* ClientRandom (32 bytes) */ + Stream_Write(s, license->ClientRandom, CLIENT_RANDOM_LENGTH); + + /* Licensing Binary Blob with EncryptedPreMasterSecret: */ + if (!license_write_encrypted_premaster_secret_blob(s, license->EncryptedPremasterSecret, license->ModulusLength)) + goto error; + + /* Licensing Binary Blob with LicenseInfo: */ + if (!license_write_binary_blob(s, calBlob)) + goto error; + + /* Licensing Binary Blob with EncryptedHWID */ + if (!license_write_binary_blob(s, license->EncryptedHardwareId)) + goto error; + + /* MACData */ + Stream_Write(s, signature, LICENSING_ENCRYPTION_KEY_LENGTH); + + return license_send(license, s, LICENSE_INFO); + +error: + Stream_Release(s); + return FALSE; +} + /** * Read a LICENSE_REQUEST packet.\n * @msdn{cc241914} @@ -927,11 +1090,11 @@ BOOL license_read_license_request_packet(rdpLicense* license, wStream* s) /* Parse Server Certificate */ if (!certificate_read_server_certificate(license->certificate, - license->ServerCertificate->data, license->ServerCertificate->length)) + license->ServerCertificate->data, license->ServerCertificate->length)) return FALSE; if (!license_generate_keys(license) || !license_generate_hwid(license) || - !license_encrypt_premaster_secret(license)) + !license_encrypt_premaster_secret(license)) return FALSE; #ifdef WITH_DEBUG_LICENSE @@ -943,7 +1106,7 @@ BOOL license_read_license_request_packet(rdpLicense* license, wStream* s) return TRUE; } -/** +/* * Read a PLATFORM_CHALLENGE packet.\n * @msdn{cc241921} * @param license license module @@ -952,44 +1115,73 @@ BOOL license_read_license_request_packet(rdpLicense* license, wStream* s) BOOL license_read_platform_challenge_packet(rdpLicense* license, wStream* s) { - BYTE MacData[16]; + BYTE macData[16]; UINT32 ConnectFlags = 0; + DEBUG_LICENSE("Receiving Platform Challenge Packet"); if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Read_UINT32(s, ConnectFlags); /* ConnectFlags, Reserved (4 bytes) */ + /* EncryptedPlatformChallenge */ license->EncryptedPlatformChallenge->type = BB_ANY_BLOB; - if (!license_read_binary_blob(s, license->EncryptedPlatformChallenge)) return FALSE; - license->EncryptedPlatformChallenge->type = BB_ENCRYPTED_DATA_BLOB; + /* MACData (16 bytes) */ if (Stream_GetRemainingLength(s) < 16) return FALSE; - Stream_Read(s, MacData, 16); /* MACData (16 bytes) */ - - if (!license_decrypt_platform_challenge(license)) + Stream_Read(s, macData, 16); + if (!license_decrypt_and_check_MAC(license, license->EncryptedPlatformChallenge->data, + license->EncryptedPlatformChallenge->length, + license->PlatformChallenge, macData)) return FALSE; #ifdef WITH_DEBUG_LICENSE WLog_DBG(TAG, "ConnectFlags: 0x%08"PRIX32"", ConnectFlags); WLog_DBG(TAG, "EncryptedPlatformChallenge:"); winpr_HexDump(TAG, WLOG_DEBUG, license->EncryptedPlatformChallenge->data, - license->EncryptedPlatformChallenge->length); + license->EncryptedPlatformChallenge->length); WLog_DBG(TAG, "PlatformChallenge:"); winpr_HexDump(TAG, WLOG_DEBUG, license->PlatformChallenge->data, - license->PlatformChallenge->length); + license->PlatformChallenge->length); WLog_DBG(TAG, "MacData:"); - winpr_HexDump(TAG, WLOG_DEBUG, MacData, 16); + winpr_HexDump(TAG, WLOG_DEBUG, macData, 16); #endif return TRUE; } + +static BOOL license_read_encrypted_blob(const rdpLicense *license, wStream *s, LICENSE_BLOB *target) +{ + UINT16 wBlobType, wBlobLen; + BYTE *encryptedData; + + if (Stream_GetRemainingLength(s) < 4) + return FALSE; + + Stream_Read_UINT16(s, wBlobType); + if (wBlobType != BB_ENCRYPTED_DATA_BLOB) + { + WLog_ERR(TAG, "expecting BB_ENCRYPTED_DATA_BLOB blob"); + return FALSE; + } + + Stream_Read_UINT16(s, wBlobLen); + + if (Stream_GetRemainingLength(s) < wBlobLen) + return FALSE; + + encryptedData = Stream_Pointer(s); + Stream_Seek(s, wBlobLen); + return license_rc4_with_licenseKey(license, encryptedData, wBlobLen, target); +} + + /** * Read a NEW_LICENSE packet.\n * @msdn{cc241926} @@ -997,24 +1189,91 @@ BOOL license_read_platform_challenge_packet(rdpLicense* license, wStream* s) * @param s stream */ -void license_read_new_license_packet(rdpLicense* license, wStream* s) +BOOL license_read_new_or_upgrade_license_packet(rdpLicense* license, wStream* s) { - DEBUG_LICENSE("Receiving New License Packet"); + UINT32 os_major; + UINT32 os_minor; + UINT32 cbScope, cbCompanyName, cbProductId, cbLicenseInfo; + wStream *licenseStream = NULL; + BOOL ret = FALSE; + BYTE computedMac[16]; + LICENSE_BLOB *calBlob; + + DEBUG_LICENSE("Receiving Server New/Upgrade License Packet"); + + calBlob = license_new_binary_blob(BB_DATA_BLOB); + if (!calBlob) + return FALSE; + + /* EncryptedLicenseInfo */ + if (!license_read_encrypted_blob(license, s, calBlob)) + goto out_free_blob; + + /* compute MAC and check it */ + if (Stream_GetRemainingLength(s) < 16) + goto out_free_blob; + + if (!security_mac_data(license->MacSaltKey, calBlob->data, calBlob->length, computedMac)) + goto out_free_blob; + + if (memcmp(computedMac, Stream_Pointer(s), sizeof(computedMac)) != 0) + { + WLog_ERR(TAG, "new or upgrade license MAC mismatch"); + goto out_free_blob; + } + + licenseStream = Stream_New(calBlob->data, calBlob->length); + if (!licenseStream) + goto out_free_blob; + + Stream_Read_UINT16(licenseStream, os_minor); + Stream_Read_UINT16(licenseStream, os_major); + + /* Scope */ + Stream_Read_UINT32(licenseStream, cbScope); + if (Stream_GetRemainingLength(licenseStream) < cbScope) + goto out_free_stream; +#ifdef WITH_DEBUG_LICENSE + WLog_DBG(TAG, "Scope:"); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(licenseStream), cbScope); +#endif + Stream_Seek(licenseStream, cbScope); + + /* CompanyName */ + Stream_Read_UINT32(licenseStream, cbCompanyName); + if (Stream_GetRemainingLength(licenseStream) < cbCompanyName) + goto out_free_stream; +#ifdef WITH_DEBUG_LICENSE + WLog_DBG(TAG, "Company name:"); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(licenseStream), cbCompanyName); +#endif + Stream_Seek(licenseStream, cbCompanyName); + + /* productId */ + Stream_Read_UINT32(licenseStream, cbProductId); + if (Stream_GetRemainingLength(licenseStream) < cbProductId) + goto out_free_stream; +#ifdef WITH_DEBUG_LICENSE + WLog_DBG(TAG, "Product id:"); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(licenseStream), cbProductId); +#endif + Stream_Seek(licenseStream, cbProductId); + + /* licenseInfo */ + Stream_Read_UINT32(licenseStream, cbLicenseInfo); + if (Stream_GetRemainingLength(licenseStream) < cbLicenseInfo) + goto out_free_stream; + license->state = LICENSE_STATE_COMPLETED; + ret = saveCal(license->rdp->settings, Stream_Pointer(licenseStream), cbLicenseInfo, license->rdp->settings->ClientHostname); + +out_free_stream: + Stream_Free(licenseStream, FALSE); +out_free_blob: + license_free_binary_blob(calBlob); + return ret; } -/** - * Read an UPGRADE_LICENSE packet.\n - * @msdn{cc241924} - * @param license license module - * @param s stream - */ - -void license_read_upgrade_license_packet(rdpLicense* license, wStream* s) -{ - DEBUG_LICENSE("Receiving Upgrade License Packet"); - license->state = LICENSE_STATE_COMPLETED; -} /** * Read an ERROR_ALERT packet.\n @@ -1039,7 +1298,7 @@ BOOL license_read_error_alert_packet(rdpLicense* license, wStream* s) #ifdef WITH_DEBUG_LICENSE WLog_DBG(TAG, "dwErrorCode: %s, dwStateTransition: %s", - error_codes[dwErrorCode], state_transitions[dwStateTransition]); + error_codes[dwErrorCode], state_transitions[dwStateTransition]); #endif if (dwErrorCode == STATUS_VALID_CLIENT) @@ -1053,18 +1312,14 @@ BOOL license_read_error_alert_packet(rdpLicense* license, wStream* s) case ST_TOTAL_ABORT: license->state = LICENSE_STATE_ABORTED; break; - case ST_NO_TRANSITION: license->state = LICENSE_STATE_COMPLETED; break; - case ST_RESET_PHASE_TO_START: license->state = LICENSE_STATE_AWAIT; break; - case ST_RESEND_LAST_MESSAGE: break; - default: break; } @@ -1081,22 +1336,21 @@ BOOL license_read_error_alert_packet(rdpLicense* license, wStream* s) BOOL license_write_new_license_request_packet(rdpLicense* license, wStream* s) { - UINT32 PlatformId; + UINT32 PlatformId = PLATFORMID; UINT32 PreferredKeyExchangeAlg = KEY_EXCHANGE_ALG_RSA; - PlatformId = CLIENT_OS_ID_WINNT_POST_52 | CLIENT_IMAGE_ID_MICROSOFT; + Stream_Write_UINT32(s, PreferredKeyExchangeAlg); /* PreferredKeyExchangeAlg (4 bytes) */ Stream_Write_UINT32(s, PlatformId); /* PlatformId (4 bytes) */ Stream_Write(s, license->ClientRandom, 32); /* ClientRandom (32 bytes) */ - /* EncryptedPremasterSecret */ - if (!license_write_encrypted_premaster_secret_blob(s, license->EncryptedPremasterSecret, - license->ModulusLength) || - /* ClientUserName */ - !license_write_binary_blob(s, license->ClientUserName) || - /* ClientMachineName */ - !license_write_binary_blob(s, license->ClientMachineName)) + + if (/* EncryptedPremasterSecret */ + !license_write_encrypted_premaster_secret_blob(s, license->EncryptedPremasterSecret, license->ModulusLength) || + /* ClientUserName */ + !license_write_binary_blob(s, license->ClientUserName) || + /* ClientMachineName */ + !license_write_binary_blob(s, license->ClientMachineName)) { - Stream_Release(s); return FALSE; } @@ -1106,26 +1360,61 @@ BOOL license_write_new_license_request_packet(rdpLicense* license, wStream* s) winpr_HexDump(TAG, WLOG_DEBUG, license->ClientRandom, 32); WLog_DBG(TAG, "EncryptedPremasterSecret"); winpr_HexDump(TAG, WLOG_DEBUG, license->EncryptedPremasterSecret->data, - license->EncryptedPremasterSecret->length); + license->EncryptedPremasterSecret->length); WLog_DBG(TAG, "ClientUserName (%"PRIu16"): %s", license->ClientUserName->length, - (char*) license->ClientUserName->data); + (char*) license->ClientUserName->data); WLog_DBG(TAG, "ClientMachineName (%"PRIu16"): %s", license->ClientMachineName->length, - (char*) license->ClientMachineName->data); + (char*) license->ClientMachineName->data); #endif return TRUE; } + /** * Send a NEW_LICENSE_REQUEST packet.\n * @msdn{cc241918} * @param license license module */ -BOOL license_send_new_license_request_packet(rdpLicense* license) +BOOL license_answer_license_request(rdpLicense* license) { + wStream* s; + BYTE *license_data = NULL; + int license_size = 0; + BOOL status; char* username; + + if (!license->rdp->settings->OldLicenseBehaviour) + license_data = loadCalFile(license->rdp->settings, license->rdp->settings->ClientHostname, &license_size); + + if(license_data) + { + LICENSE_BLOB *calBlob = NULL; + BYTE signature[LICENSING_ENCRYPTION_KEY_LENGTH]; + + DEBUG_LICENSE("Sending Saved License Packet"); + + license->EncryptedHardwareId->type = BB_ENCRYPTED_DATA_BLOB; + if (!license_encrypt_and_MAC(license, license->HardwareId, HWID_LENGTH, license->EncryptedHardwareId, signature)) + return FALSE; + + calBlob = license_new_binary_blob(BB_DATA_BLOB); + if (!calBlob) + return FALSE; + calBlob->data = license_data; + calBlob->length = license_size; + + status = license_send_client_info(license, calBlob, signature); + license_free_binary_blob(calBlob); + + return status; + } + DEBUG_LICENSE("Sending New License Packet"); + s = license_send_stream_init(license); + if (!s) + return FALSE; if (license->rdp->settings->Username != NULL) username = license->rdp->settings->Username; else @@ -1136,14 +1425,20 @@ BOOL license_send_new_license_request_packet(rdpLicense* license) license->ClientMachineName->data = (BYTE*) license->rdp->settings->ClientHostname; license->ClientMachineName->length = strlen(license->rdp->settings->ClientHostname) + 1; - if (!license_send(license, NEW_LICENSE_REQUEST)) - return FALSE; + status = license_write_new_license_request_packet(license, s); license->ClientUserName->data = NULL; license->ClientUserName->length = 0; license->ClientMachineName->data = NULL; license->ClientMachineName->length = 0; - return TRUE; + + if (!status) + { + Stream_Release(s); + return FALSE; + } + + return license_send(license, s, NEW_LICENSE_REQUEST); } /** @@ -1154,15 +1449,12 @@ BOOL license_send_new_license_request_packet(rdpLicense* license) * @param mac_data signature */ -BOOL license_write_platform_challenge_response_packet(rdpLicense* license, wStream* s, - BYTE* macData) +BOOL license_write_platform_challenge_response_packet(rdpLicense* license, wStream* s, const BYTE* macData) { - if (!license_write_binary_blob(s, license->EncryptedPlatformChallenge) || - /* EncryptedPlatformChallengeResponse */ - !license_write_binary_blob(s, license->EncryptedHardwareId) || /* EncryptedHWID */ - !Stream_EnsureRemainingCapacity(s, 16)) + if (!license_write_binary_blob(s, license->EncryptedPlatformChallengeResponse) || /* EncryptedPlatformChallengeResponse */ + !license_write_binary_blob(s, license->EncryptedHardwareId) || /* EncryptedHWID */ + !Stream_EnsureRemainingCapacity(s, 16)) { - Stream_Release(s); return FALSE; } @@ -1170,6 +1462,7 @@ BOOL license_write_platform_challenge_response_packet(rdpLicense* license, wStre return TRUE; } + /** * Send Client Challenge Response Packet.\n * @msdn{cc241922} @@ -1178,37 +1471,62 @@ BOOL license_write_platform_challenge_response_packet(rdpLicense* license, wStre BOOL license_send_platform_challenge_response_packet(rdpLicense* license) { + wStream* s; + wStream *challengeRespData; + int length; BYTE* buffer; - WINPR_RC4_CTX* rc4; + BYTE mac_data[16]; BOOL status; + DEBUG_LICENSE("Sending Platform Challenge Response Packet"); + s = license_send_stream_init(license); license->EncryptedPlatformChallenge->type = BB_DATA_BLOB; - /* Allow FIPS override for use of RC4 here, this is only used for encrypting the EncryptedHWID field of the */ - /* Client Platform Challenge Response packet (from MS-RDPELE section 2.2.2.5). This is for RDP licensing packets */ - /* which will already be encrypted under FIPS, so the use of RC4 here is not for sensitive data protection. */ - rc4 = winpr_RC4_New_Allow_FIPS(license->LicensingEncryptionKey, - LICENSING_ENCRYPTION_KEY_LENGTH); - if (!rc4) + /* prepare the PLATFORM_CHALLENGE_RESPONSE_DATA */ + challengeRespData = Stream_New(NULL, 8 + license->PlatformChallenge->length); + if (!challengeRespData) return FALSE; + Stream_Write_UINT16(challengeRespData, 0x0100); /* wVersion */ + Stream_Write_UINT16(challengeRespData, OTHER_PLATFORM_CHALLENGE_TYPE); /* wClientType */ + Stream_Write_UINT16(challengeRespData, LICENSE_DETAIL_DETAIL); /* wLicenseDetailLevel */ + Stream_Write_UINT16(challengeRespData, license->PlatformChallenge->length); /* cbChallenge */ + Stream_Write(challengeRespData, license->PlatformChallenge->data, license->PlatformChallenge->length); /* pbChallenge */ + Stream_SealLength(challengeRespData); - buffer = (BYTE*) malloc(HWID_LENGTH); - + /* compute MAC of PLATFORM_CHALLENGE_RESPONSE_DATA + HWID */ + length = Stream_Length(challengeRespData) + HWID_LENGTH; + buffer = (BYTE*) malloc(length); if (!buffer) - return FALSE; - - status = winpr_RC4_Update(rc4, HWID_LENGTH, license->HardwareId, buffer); - winpr_RC4_Free(rc4); - - if (!status) { - free(buffer); + Stream_Free(challengeRespData, TRUE); return FALSE; } - license->EncryptedHardwareId->type = BB_DATA_BLOB; - license->EncryptedHardwareId->data = buffer; - license->EncryptedHardwareId->length = HWID_LENGTH; + CopyMemory(buffer, Stream_Buffer(challengeRespData), Stream_Length(challengeRespData)); + CopyMemory(&buffer[Stream_Length(challengeRespData)], license->HardwareId, HWID_LENGTH); + status = security_mac_data(license->MacSaltKey, buffer, length, mac_data); + free(buffer); + + if (!status) + { + Stream_Free(challengeRespData, TRUE); + return FALSE; + } + + license->EncryptedHardwareId->type = BB_ENCRYPTED_DATA_BLOB; + if (!license_rc4_with_licenseKey(license, license->HardwareId, HWID_LENGTH, license->EncryptedHardwareId)) + { + Stream_Free(challengeRespData, TRUE); + return FALSE; + } + + status = license_rc4_with_licenseKey(license, Stream_Buffer(challengeRespData), + Stream_Length(challengeRespData), + license->EncryptedPlatformChallengeResponse); + Stream_Free(challengeRespData, TRUE); + if (!status) + return FALSE; + #ifdef WITH_DEBUG_LICENSE WLog_DBG(TAG, "LicensingEncryptionKey:"); winpr_HexDump(TAG, WLOG_DEBUG, license->LicensingEncryptionKey, 16); @@ -1217,7 +1535,11 @@ BOOL license_send_platform_challenge_response_packet(rdpLicense* license) WLog_DBG(TAG, "EncryptedHardwareId:"); winpr_HexDump(TAG, WLOG_DEBUG, license->EncryptedHardwareId->data, HWID_LENGTH); #endif - return license_send(license, PLATFORM_CHALLENGE_RESPONSE); + if (license_write_platform_challenge_response_packet(license, s, mac_data)) + return license_send(license, s, PLATFORM_CHALLENGE_RESPONSE); + + Stream_Release(s); + return FALSE; } /** @@ -1229,12 +1551,18 @@ BOOL license_send_platform_challenge_response_packet(rdpLicense* license) BOOL license_send_valid_client_error_packet(rdpLicense* license) { wStream* s = license_send_stream_init(license); - if (!s) return FALSE; DEBUG_LICENSE("Sending Error Alert Packet"); - return license_send(license, ERROR_ALERT); + Stream_Write_UINT32(s, STATUS_VALID_CLIENT); /* dwErrorCode */ + Stream_Write_UINT32(s, ST_NO_TRANSITION); /* dwStateTransition */ + + if (license_write_binary_blob(s, license->ErrorInfo)) + return license_send(license, s, ERROR_ALERT); + + Stream_Release(s); + return FALSE; } /** @@ -1247,51 +1575,42 @@ rdpLicense* license_new(rdpRdp* rdp) { rdpLicense* license; license = (rdpLicense*) calloc(1, sizeof(rdpLicense)); - if (!license) return NULL; license->rdp = rdp; license->state = LICENSE_STATE_AWAIT; - if (!(license->certificate = certificate_new())) goto out_error; - if (!(license->ProductInfo = license_new_product_info())) goto out_error; - if (!(license->ErrorInfo = license_new_binary_blob(BB_ERROR_BLOB))) goto out_error; - if (!(license->KeyExchangeList = license_new_binary_blob(BB_KEY_EXCHG_ALG_BLOB))) goto out_error; - if (!(license->ServerCertificate = license_new_binary_blob(BB_CERTIFICATE_BLOB))) goto out_error; - if (!(license->ClientUserName = license_new_binary_blob(BB_CLIENT_USER_NAME_BLOB))) goto out_error; - if (!(license->ClientMachineName = license_new_binary_blob(BB_CLIENT_MACHINE_NAME_BLOB))) goto out_error; - if (!(license->PlatformChallenge = license_new_binary_blob(BB_ANY_BLOB))) goto out_error; - if (!(license->EncryptedPlatformChallenge = license_new_binary_blob(BB_ANY_BLOB))) goto out_error; - + if (!(license->EncryptedPlatformChallengeResponse = license_new_binary_blob(BB_ENCRYPTED_DATA_BLOB))) + goto out_error; if (!(license->EncryptedPremasterSecret = license_new_binary_blob(BB_ANY_BLOB))) goto out_error; - if (!(license->EncryptedHardwareId = license_new_binary_blob(BB_ENCRYPTED_DATA_BLOB))) goto out_error; - if (!(license->ScopeList = license_new_scope_list())) goto out_error; license_generate_randoms(license); + return license; + out_error: license_free(license); return NULL; @@ -1316,6 +1635,7 @@ void license_free(rdpLicense* license) license_free_binary_blob(license->ClientMachineName); license_free_binary_blob(license->PlatformChallenge); license_free_binary_blob(license->EncryptedPlatformChallenge); + license_free_binary_blob(license->EncryptedPlatformChallengeResponse); license_free_binary_blob(license->EncryptedPremasterSecret); license_free_binary_blob(license->EncryptedHardwareId); license_free_scope_list(license->ScopeList); diff --git a/libfreerdp/core/license.h b/libfreerdp/core/license.h index 410337c6e..2f1c284c0 100644 --- a/libfreerdp/core/license.h +++ b/libfreerdp/core/license.h @@ -196,6 +196,7 @@ struct rdp_license LICENSE_BLOB* PlatformChallenge; LICENSE_BLOB* EncryptedPremasterSecret; LICENSE_BLOB* EncryptedPlatformChallenge; + LICENSE_BLOB *EncryptedPlatformChallengeResponse; LICENSE_BLOB* EncryptedHardwareId; SCOPE_LIST* ScopeList; UINT32 PacketHeaderLength;