libfreerdp-core: add new unit tests for licensing, fix encryption of premaster secret

This commit is contained in:
Marc-André Moreau 2011-07-15 01:11:09 -04:00
parent 08c14ddf33
commit 288aacb6e9
8 changed files with 294 additions and 54 deletions

View File

@ -46,6 +46,9 @@ int add_license_suite(void)
add_test_suite(license);
add_test_function(license);
add_test_function(license_generate_keys);
add_test_function(license_encrypt_premaster_secret);
add_test_function(license_decrypt_platform_challenge);
return 0;
}
@ -322,6 +325,7 @@ void test_license(void)
s->p = s->data + LICENSE_PREAMBLE_LENGTH;
license_read_license_request_packet(license, s);
#if 0
printf("\n");
printf("client random:\n");
@ -361,14 +365,136 @@ void test_license(void)
freerdp_hexdump(license->certificate->cert_info.exponent, 4);
printf("\n");
/* the encrypted premaster secret is 256 + 8 bytes long, with 8 bytes of padding */
printf("encrypted premaster secret:\n");
freerdp_hexdump(license->encrypted_pre_master_secret->data,
license->encrypted_pre_master_secret->length);
freerdp_hexdump(license->encrypted_premaster_secret->data,
license->encrypted_premaster_secret->length);
printf("\n");
#endif
s->data = server_platform_challenge;
s->p = s->data + LICENSE_PREAMBLE_LENGTH;
license_read_platform_challenge_packet(license, s);
}
uint8 test_client_random[32] =
"\xdc\x73\xa0\xc8\x69\x25\x6b\x18\xaf\x0b\x94\x7a\xa9\xa5\x20\xaf"
"\x8b\xbc\x0d\xcc\xa3\x95\xb7\xb9\xeb\x81\x5d\xbe\x0a\x10\x9c\xd8";
uint8 test_server_random[32] =
"\x16\x7e\xf8\x71\x48\x16\x1a\x4f\xa5\x2c\xcd\x73\x63\x60\xa6\xc3"
"\xb9\x19\x1b\x4b\x6b\xb2\x0a\xb8\xec\xf1\x8d\x95\x4e\xa8\x21\xc5";
uint8 test_premaster_secret[48] =
"\xcf\x7a\xdb\xcb\xfb\x0e\x15\x23\x87\x1c\x84\x81\xba\x9d\x4e\x15"
"\xbb\xd2\x56\xbd\xd8\xf7\xf3\x16\xcc\x35\x3b\xe1\x93\x42\x78\xdd"
"\x92\x9a\xe4\x7a\xe2\x99\xd4\x73\xb1\xaa\x6f\x55\x94\x3b\xc9\xbc";
uint8 test_modulus[64] =
"\x23\xc9\xec\x0e\x9f\x1e\x0e\x1a\x78\xaf\xa5\x14\xd4\xf5\x45\xe4"
"\x04\x6e\xf4\x01\xe9\xdf\x45\xd1\xc2\xae\xf4\x7f\xd3\xb9\xcb\xf3"
"\x1a\x23\xa1\x0d\x4b\xd4\xd1\x4a\xd2\xd1\xc9\x7c\xab\x24\x8b\xb1"
"\x5a\x93\xca\x34\x44\x17\xb5\xe4\xfe\xf7\x9a\xaa\x72\x0d\x41\x95";
uint8 test_exponent[4] = "\x01\x00\x01\x00";
uint8 test_master_secret[48] =
"\xbe\x51\xee\x63\x23\x90\xd0\xf4\x3a\xce\x3a\x37\x65\xc3\xdd\xcf"
"\xed\xf0\xc8\x19\xed\x77\x33\x4e\xfd\x2b\x7d\x5a\xe2\xca\xf3\x0a"
"\xf1\x16\xe5\x0c\x78\x59\x7e\xd4\x4b\x57\xce\x17\x60\x3a\x5a\xb3";
uint8 test_session_key_blob[48] =
"\x07\x4f\xa0\x2e\xee\xc4\x5a\x46\x21\x8c\xae\x01\x45\x02\x26\xe4"
"\x54\x6b\x59\x10\xcc\x5b\xd1\x96\xd0\x5c\xeb\xc2\x96\x9b\x44\x7b"
"\x1c\xd9\x66\xb1\x9e\x24\xaa\x60\x4f\x89\xd1\x4e\xf8\xb9\x55\x3b";
uint8 test_mac_salt_key[16] =
"\x07\x4f\xa0\x2e\xee\xc4\x5a\x46\x21\x8c\xae\x01\x45\x02\x26\xe4";
uint8 test_licensing_encryption_key[16] =
"\xf3\xb1\xe0\x3b\xfe\xb4\xf2\xc5\x28\xa9\x48\xcd\x90\xf1\x93\xe5";
uint8 test_encrypted_premaster_secret[64] =
"\x6b\xbc\x77\x9f\x20\x0c\x98\x39\xc1\x85\x77\xc8\x19\x87\xd8\x82"
"\x93\xbd\x21\x69\x5f\x87\xe0\xd6\x4e\xad\x5e\x23\x13\x80\x8c\x63"
"\x3e\xd6\x6e\x60\xc9\x40\xe9\x86\x08\x8c\xd5\xaa\xa9\x54\xfe\x27"
"\x4c\x1f\x87\x57\xde\xca\xd4\xc7\x1e\x46\x9e\x00\x7a\xdb\x47\x23";
void test_license_generate_keys(void)
{
STREAM* s;
s = stream_new(0);
memcpy(license->client_random, client_random, sizeof(client_random));
memcpy(license->server_random, test_server_random, sizeof(test_server_random));
memcpy(license->premaster_secret, premaster_secret, sizeof(premaster_secret));
memcpy(license->certificate->cert_info.exponent, test_exponent, sizeof(test_exponent));
memcpy(license->certificate->cert_info.modulus.data, test_modulus, sizeof(test_modulus));
license->certificate->cert_info.modulus.length = sizeof(test_modulus);
license_generate_keys(license);
license_encrypt_premaster_secret(license);
s->data = license->master_secret;
s->p = s->data + sizeof(test_master_secret);
ASSERT_STREAM(s, test_master_secret, sizeof(test_master_secret));
s->data = license->session_key_blob;
s->p = s->data + sizeof(test_session_key_blob);
ASSERT_STREAM(s, test_session_key_blob, sizeof(test_session_key_blob));
s->data = license->mac_salt_key;
s->p = s->data + sizeof(test_mac_salt_key);
ASSERT_STREAM(s, test_mac_salt_key, sizeof(test_mac_salt_key));
s->data = license->licensing_encryption_key;
s->p = s->data + sizeof(test_licensing_encryption_key);
ASSERT_STREAM(s, test_licensing_encryption_key, sizeof(test_licensing_encryption_key));
s->data = license->encrypted_premaster_secret->data;
s->p = s->data + sizeof(test_encrypted_premaster_secret);
ASSERT_STREAM(s, test_encrypted_premaster_secret, sizeof(test_encrypted_premaster_secret));
}
void test_license_encrypt_premaster_secret(void)
{
STREAM* s;
s = stream_new(0);
memcpy(license->premaster_secret, premaster_secret, sizeof(premaster_secret));
memcpy(license->certificate->cert_info.exponent, test_exponent, sizeof(test_exponent));
memcpy(license->certificate->cert_info.modulus.data, test_modulus, sizeof(test_modulus));
license->certificate->cert_info.modulus.length = sizeof(test_modulus);
s->data = license->encrypted_premaster_secret->data;
s->p = s->data + sizeof(test_encrypted_premaster_secret);
ASSERT_STREAM(s, test_encrypted_premaster_secret, sizeof(test_encrypted_premaster_secret));
}
uint8 test_encrypted_platform_challenge[10] =
"\x84\x0a\x42\x50\xad\x5e\xc1\x29\x30\xbd";
uint8 test_platform_challenge[10] =
"\x54\x00\x45\x00\x53\x00\x54\x00\x00\x00";
void test_license_decrypt_platform_challenge(void)
{
STREAM* s;
s = stream_new(0);
memcpy(license->licensing_encryption_key, test_licensing_encryption_key,
sizeof(test_licensing_encryption_key));
license->encrypted_platform_challenge->data =
(uint8*) xmalloc(sizeof(test_encrypted_platform_challenge));
license->encrypted_platform_challenge->length =
sizeof(test_encrypted_platform_challenge);
memcpy(license->encrypted_platform_challenge->data, test_encrypted_platform_challenge,
sizeof(test_encrypted_platform_challenge));
license_decrypt_platform_challenge(license);
s->data = license->platform_challenge->data;
s->p = s->data + sizeof(test_platform_challenge);
ASSERT_STREAM(s, test_platform_challenge, sizeof(test_platform_challenge));
}

View File

@ -24,3 +24,6 @@ int clean_license_suite(void);
int add_license_suite(void);
void test_license(void);
void test_license_generate_keys(void);
void test_license_encrypt_premaster_secret(void);
void test_license_decrypt_platform_challenge(void);

View File

@ -251,7 +251,7 @@ void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate,
uint32 certLength;
uint32 numCertBlobs;
printf("\nServer X.509 Certificate Chain\n");
DEBUG_CERTIFICATE("Server X.509 Certificate Chain");
stream_read_uint32(s, numCertBlobs); /* numCertBlobs */
@ -261,7 +261,7 @@ void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate,
{
stream_read_uint32(s, certLength);
printf("\nX.509 Certificate #%d, length:%d", i + 1, certLength);
DEBUG_CERTIFICATE("\nX.509 Certificate #%d, length:%d", i + 1, certLength);
certificate->x509_cert_chain->array[i].data = (uint8*) xmalloc(certLength);
stream_read(s, certificate->x509_cert_chain->array[i].data, certLength);
@ -269,25 +269,17 @@ void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate,
if (numCertBlobs - i == 2)
{
printf(", License Server Certificate\n");
//freerdp_hexdump(certificate->x509_cert_chain->array[i].data, certificate->x509_cert_chain->array[i].length);
//certificate_read_x509_certificate(&certificate->x509_cert_chain->array[i], &certificate->cert_info);
//printf("license modulus (%d):\n", certificate->cert_info.modulus.length);
//freerdp_hexdump(certificate->cert_info.modulus.data, certificate->cert_info.modulus.length);
//printf("license exponent:\n");
//freerdp_hexdump(certificate->cert_info.exponent, 4);
CERT_INFO cert_info;
DEBUG_CERTIFICATE("License Server Certificate");
certificate_read_x509_certificate(&certificate->x509_cert_chain->array[i], &cert_info);
DEBUG_LICENSE("modulus length:%d", cert_info.modulus.length);
}
else if (numCertBlobs - i == 1)
{
printf(", Terminal Server Certificate\n");
//freerdp_hexdump(certificate->x509_cert_chain->array[i].data, certificate->x509_cert_chain->array[i].length);
DEBUG_CERTIFICATE("Terminal Server Certificate");
certificate_read_x509_certificate(&certificate->x509_cert_chain->array[i], &certificate->cert_info);
printf("modulus length:%d\n", certificate->cert_info.modulus.length);
DEBUG_CERTIFICATE("modulus length:%d", certificate->cert_info.modulus.length);
}
else
printf("\n");
}
}

View File

@ -74,4 +74,12 @@ void certificate_read_server_certificate(rdpCertificate* certificate, uint8* ser
rdpCertificate* certificate_new(rdpRdp* rdp);
void certificate_free(rdpCertificate* certificate);
//#define WITH_DEBUG_CERTIFICATE 1
#ifdef WITH_DEBUG_CERTIFICATE
#define DEBUG_CERTIFICATE(fmt, ...) DEBUG_CLASS(CERTIFICATE, fmt, ## __VA_ARGS__)
#else
#define DEBUG_CERTIFICATE(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
#endif /* __CERTIFICATE_H */

View File

@ -127,29 +127,62 @@ exit:
return status;
}
void crypto_rsa(int length, uint8* in, uint8* out, uint32 modulus_length, uint8* modulus, uint8* exponent)
void crypto_rsa_encrypt(uint8* input, int length, uint32 key_length, uint8* modulus, uint8* exponent, uint8* output)
{
BN_CTX *ctx;
int out_length;
int output_length;
uint8* input_reverse;
uint8* modulus_reverse;
uint8* exponent_reverse;
BIGNUM mod, exp, x, y;
input_reverse = (uint8*) xmalloc(2 * MODULUS_MAX_SIZE + EXPONENT_MAX_SIZE);
modulus_reverse = input_reverse + MODULUS_MAX_SIZE;
exponent_reverse = modulus_reverse + MODULUS_MAX_SIZE;
memcpy(modulus_reverse, modulus, key_length);
crypto_reverse(modulus_reverse, key_length);
memcpy(exponent_reverse, exponent, EXPONENT_MAX_SIZE);
crypto_reverse(exponent_reverse, EXPONENT_MAX_SIZE);
memcpy(input_reverse, input, length);
crypto_reverse(input_reverse, length);
ctx = BN_CTX_new();
BN_init(&mod);
BN_init(&exp);
BN_init(&x);
BN_init(&y);
BN_bin2bn(modulus, modulus_length, &mod);
BN_bin2bn(exponent, 4, &exp);
BN_bin2bn(in, length, &x);
BN_bin2bn(modulus_reverse, key_length, &mod);
BN_bin2bn(exponent_reverse, EXPONENT_MAX_SIZE, &exp);
BN_bin2bn(input_reverse, length, &x);
BN_mod_exp(&y, &x, &exp, &mod, ctx);
out_length = BN_bn2bin(&y, out);
output_length = BN_bn2bin(&y, output);
crypto_reverse(output, output_length);
if (output_length < (int) key_length)
memset(output + output_length, 0, key_length - output_length);
BN_free(&y);
BN_clear_free(&x);
BN_free(&exp);
BN_free(&mod);
BN_CTX_free(ctx);
xfree(input_reverse);
}
void crypto_reverse(uint8* data, int length)
{
int i, j;
uint8 temp;
for (i = 0, j = length - 1; i < j; i++, j--)
{
temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
void crypto_nonce(uint8* nonce, int size)

View File

@ -35,6 +35,9 @@
#define D2I_X509_CONST
#endif
#define EXPONENT_MAX_SIZE 4
#define MODULUS_MAX_SIZE 256
#include <freerdp/freerdp.h>
#include <freerdp/utils/blob.h>
#include <freerdp/utils/memory.h>
@ -80,8 +83,8 @@ void crypto_cert_free(CryptoCert cert);
boolean crypto_cert_verify(CryptoCert server_cert, CryptoCert cacert);
boolean crypto_cert_get_public_key(CryptoCert cert, BLOB* public_key);
void crypto_rsa(int length, uint8* in, uint8* out, uint32 modulus_length, uint8* modulus, uint8* exponent);
void crypto_rsa_encrypt(uint8* input, int length, uint32 key_length, uint8* modulus, uint8* exponent, uint8* output);
void crypto_reverse(uint8* data, int length);
void crypto_nonce(uint8* nonce, int size);
#endif /* __CRYPTO_H */

View File

@ -166,6 +166,7 @@ void license_generate_keys(rdpLicense* license)
security_licensing_encryption_key(license->session_key_blob, license->client_random,
license->server_random, license->licensing_encryption_key); /* LicensingEncryptionKey */
#if 0
paddingLength = MODULUS_MAX_SIZE - license->certificate->cert_info.modulus.length;
memset(license->modulus, 0, paddingLength);
@ -177,13 +178,36 @@ void license_generate_keys(rdpLicense* license)
/* EncryptedPremasterSecret */
license->encrypted_pre_master_secret->type = BB_ANY_BLOB;
license->encrypted_pre_master_secret->length = MODULUS_MAX_SIZE + 8;
license->encrypted_pre_master_secret->data = (uint8*) xzalloc(MODULUS_MAX_SIZE + 8);
license->encrypted_premaster_secret->type = BB_ANY_BLOB;
license->encrypted_premaster_secret->length = 64;
license->encrypted_premaster_secret->data = (uint8*) xzalloc(64);
#endif
crypto_rsa(PREMASTER_SECRET_LENGTH, license->premaster_secret,
license->encrypted_pre_master_secret->data,
#if 0
crypto_rsa(MODULUS_MAX_SIZE, license->premaster_secret,
license->encrypted_premaster_secret->data,
MODULUS_MAX_SIZE, license->modulus, license->exponent);
#endif
#if 0
//ssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, uint8 * exponent)
/*
ssl_rsa_encrypt(pEncryptedPreMasterSecret, license_v3->ClientPreMasterSecret,
48, license_v3->server_public_key_len, license_v3->modulus,
license_v3->exponent);
*/
exponent = license->certificate->cert_info.exponent;
modulus = license->certificate->cert_info.modulus.data;
key_length = license->certificate->cert_info.modulus.length;
encrypted_premaster_secret = (uint8*) xmalloc(MODULUS_MAX_SIZE);
memset(encrypted_premaster_secret, 0, MODULUS_MAX_SIZE);
crypto_rsa_encrypt(encrypted_premaster_secret,
license->premaster_secret, 48, 64, modulus, exponent);
#endif
}
/**
@ -204,6 +228,55 @@ void license_generate_hwid(rdpLicense* license)
crypto_md5_final(md5, &license->hwid[HWID_PLATFORM_ID_LENGTH]);
}
void license_encrypt_premaster_secret(rdpLicense* license)
{
int key_length;
uint8* modulus;
uint8* exponent;
uint8* encrypted_premaster_secret;
exponent = license->certificate->cert_info.exponent;
modulus = license->certificate->cert_info.modulus.data;
key_length = license->certificate->cert_info.modulus.length;
encrypted_premaster_secret = (uint8*) xmalloc(MODULUS_MAX_SIZE);
memset(encrypted_premaster_secret, 0, MODULUS_MAX_SIZE);
crypto_rsa_encrypt(license->premaster_secret, PREMASTER_SECRET_LENGTH,
key_length, modulus, exponent, encrypted_premaster_secret);
license->encrypted_premaster_secret->type = BB_ANY_BLOB;
license->encrypted_premaster_secret->length = PREMASTER_SECRET_LENGTH;
license->encrypted_premaster_secret->data = encrypted_premaster_secret;
}
void license_decrypt_platform_challenge(rdpLicense* license)
{
CryptoRc4 rc4;
license->platform_challenge->data =
(uint8*) xmalloc(license->encrypted_platform_challenge->length);
license->platform_challenge->length =
license->encrypted_platform_challenge->length;
rc4 = crypto_rc4_init(license->licensing_encryption_key, LICENSING_ENCRYPTION_KEY_LENGTH);
crypto_rc4(rc4, license->encrypted_platform_challenge->length,
license->encrypted_platform_challenge->data,
license->platform_challenge->data);
#if 0
printf("encrypted_platform challenge:\n");
freerdp_hexdump(license->encrypted_platform_challenge->data,
license->encrypted_platform_challenge->length);
printf("platform challenge:\n");
freerdp_hexdump(license->platform_challenge->data, license->platform_challenge->length);
#endif
crypto_rc4_free(rc4);
}
/**
* Read Product Information (PRODUCT_INFO).\n
* @msdn{cc241915}
@ -308,6 +381,17 @@ void license_write_binary_blob(STREAM* s, LICENSE_BLOB* blob)
stream_write(s, blob->data, blob->length); /* blobData */
}
void license_write_padded_binary_blob(STREAM* s, LICENSE_BLOB* blob)
{
stream_write_uint16(s, blob->type); /* wBlobType (2 bytes) */
stream_write_uint16(s, blob->length + LICENSING_PADDING_SIZE); /* wBlobLen (2 bytes) */
if (blob->length > 0)
stream_write(s, blob->data, blob->length); /* blobData */
stream_write_zero(s, LICENSING_PADDING_SIZE);
}
/**
* Allocate New License Binary Blob (LICENSE_BINARY_BLOB).\n
* @msdn{cc240481}
@ -432,6 +516,7 @@ void license_read_license_request_packet(rdpLicense* license, STREAM* s)
license_generate_keys(license);
license_generate_hwid(license);
license_encrypt_premaster_secret(license);
}
/**
@ -458,20 +543,7 @@ void license_read_platform_challenge_packet(rdpLicense* license, STREAM* s)
/* MACData (16 bytes) */
stream_seek(s, 16);
printf("encrypted platform challenge\n");
freerdp_hexdump(license->encrypted_platform_challenge->data, license->encrypted_platform_challenge->length);
platform_challenge = (uint8*) xmalloc(license->encrypted_platform_challenge->length);
rc4 = crypto_rc4_init(license->licensing_encryption_key, LICENSING_ENCRYPTION_KEY_LENGTH);
crypto_rc4(rc4, license->encrypted_platform_challenge->length,
license->encrypted_platform_challenge->data, platform_challenge);
printf("decrypted platform challenge\n");
freerdp_hexdump(platform_challenge, license->encrypted_platform_challenge->length);
crypto_rc4_free(rc4);
license_decrypt_platform_challenge(license);
}
/**
@ -536,7 +608,7 @@ void license_write_new_license_request_packet(rdpLicense* license, STREAM* s)
stream_write_uint32(s, KEY_EXCHANGE_ALG_RSA); /* PreferredKeyExchangeAlg (4 bytes) */
license_write_platform_id(license, s); /* PlatformId (4 bytes) */
stream_write(s, license->client_random, 32); /* ClientRandom (32 bytes) */
license_write_binary_blob(s, license->encrypted_pre_master_secret); /* EncryptedPreMasterSecret */
license_write_padded_binary_blob(s, license->encrypted_premaster_secret); /* EncryptedPremasterSecret */
license_write_binary_blob(s, license->client_user_name); /* ClientUserName */
license_write_binary_blob(s, license->client_machine_name); /* ClientMachineName */
}
@ -644,10 +716,11 @@ rdpLicense* license_new(rdpRdp* rdp)
license->product_info = license_new_product_info();
license->key_exchange_list = license_new_binary_blob(BB_KEY_EXCHG_ALG_BLOB);
license->server_certificate = license_new_binary_blob(BB_CERTIFICATE_BLOB);
license->encrypted_pre_master_secret = license_new_binary_blob(BB_RANDOM_BLOB);
license->client_user_name = license_new_binary_blob(BB_CLIENT_USER_NAME_BLOB);
license->client_machine_name = license_new_binary_blob(BB_CLIENT_MACHINE_NAME_BLOB);
license->platform_challenge = license_new_binary_blob(BB_ANY_BLOB);
license->encrypted_platform_challenge = license_new_binary_blob(BB_ANY_BLOB);
license->encrypted_premaster_secret = license_new_binary_blob(BB_ANY_BLOB);
license->encrypted_hwid = license_new_binary_blob(BB_ENCRYPTED_DATA_BLOB);
license->scope_list = license_new_scope_list();
license_generate_randoms(license);
@ -669,10 +742,11 @@ void license_free(rdpLicense* license)
license_free_product_info(license->product_info);
license_free_binary_blob(license->key_exchange_list);
license_free_binary_blob(license->server_certificate);
license_free_binary_blob(license->encrypted_pre_master_secret);
license_free_binary_blob(license->client_user_name);
license_free_binary_blob(license->client_machine_name);
license_free_binary_blob(license->platform_challenge);
license_free_binary_blob(license->encrypted_platform_challenge);
license_free_binary_blob(license->encrypted_premaster_secret);
license_free_binary_blob(license->encrypted_hwid);
license_free_scope_list(license->scope_list);
xfree(license);

View File

@ -58,8 +58,6 @@ typedef struct rdp_license rdpLicense;
#define HWID_PLATFORM_ID_LENGTH 4
#define HWID_UNIQUE_DATA_LENGTH 16
#define HWID_LENGTH 20
#define MODULUS_MAX_SIZE 256
#define EXPONENT_MAX_SIZE 4
#define LICENSING_PADDING_SIZE 8
/* Licensing Preamble Flags */
@ -124,7 +122,8 @@ struct rdp_license
LICENSE_BLOB* server_certificate;
LICENSE_BLOB* client_user_name;
LICENSE_BLOB* client_machine_name;
LICENSE_BLOB* encrypted_pre_master_secret;
LICENSE_BLOB* platform_challenge;
LICENSE_BLOB* encrypted_premaster_secret;
LICENSE_BLOB* encrypted_platform_challenge;
LICENSE_BLOB* encrypted_hwid;
SCOPE_LIST* scope_list;
@ -137,6 +136,8 @@ STREAM* license_send_stream_init(rdpLicense* license);
void license_generate_randoms(rdpLicense* license);
void license_generate_keys(rdpLicense* license);
void license_generate_hwid(rdpLicense* license);
void license_encrypt_premaster_secret(rdpLicense* license);
void license_decrypt_platform_challenge(rdpLicense* license);
PRODUCT_INFO* license_new_product_info();
void license_free_product_info(PRODUCT_INFO* productInfo);