示例#1
0
void rdp_write_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings)
{
	CryptoHmac hmac;
	BYTE nullRandom[32];
	BYTE cryptSecurityVerifier[16];
	ARC_CS_PRIVATE_PACKET* autoReconnectCookie;
	autoReconnectCookie = settings->ClientAutoReconnectCookie;

	/* SecurityVerifier = HMAC(AutoReconnectRandom, ClientRandom) */

	hmac = crypto_hmac_new();
	ZeroMemory(nullRandom, sizeof(nullRandom));

	crypto_hmac_md5_init(hmac, autoReconnectCookie->securityVerifier, 16);

	if (settings->ClientRandomLength > 0)
		crypto_hmac_update(hmac, settings->ClientRandom, settings->ClientRandomLength);
	else
		crypto_hmac_update(hmac, nullRandom, sizeof(nullRandom));

	crypto_hmac_final(hmac, cryptSecurityVerifier, 16);
	crypto_hmac_free(hmac);

	Stream_Write_UINT32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */
	Stream_Write_UINT32(s, autoReconnectCookie->version); /* version (4 bytes) */
	Stream_Write_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */
	Stream_Write(s, cryptSecurityVerifier, 16); /* SecurityVerifier */
}
示例#2
0
文件: info.c 项目: C4rt/FreeRDP
BOOL rdp_compute_client_auto_reconnect_cookie(rdpRdp* rdp)
{
	CryptoHmac hmac;
	BYTE ClientRandom[32];
	BYTE AutoReconnectRandom[32];
	ARC_SC_PRIVATE_PACKET* serverCookie;
	ARC_CS_PRIVATE_PACKET* clientCookie;
	rdpSettings* settings = rdp->settings;

	serverCookie = settings->ServerAutoReconnectCookie;
	clientCookie = settings->ClientAutoReconnectCookie;

	clientCookie->cbLen = 28;
	clientCookie->version = serverCookie->version;
	clientCookie->logonId = serverCookie->logonId;
	ZeroMemory(clientCookie->securityVerifier, 16);

	ZeroMemory(AutoReconnectRandom, sizeof(AutoReconnectRandom));
	CopyMemory(AutoReconnectRandom, serverCookie->arcRandomBits, 16);

	ZeroMemory(ClientRandom, sizeof(ClientRandom));

	if (settings->SelectedProtocol == PROTOCOL_RDP)
		CopyMemory(ClientRandom, settings->ClientRandom, settings->ClientRandomLength);

	hmac = crypto_hmac_new();

	if (!hmac)
		return FALSE;

	/* SecurityVerifier = HMAC_MD5(AutoReconnectRandom, ClientRandom) */

	if (!crypto_hmac_md5_init(hmac, AutoReconnectRandom, 16))
		return FALSE;
	crypto_hmac_update(hmac, ClientRandom, 32);
	crypto_hmac_final(hmac, clientCookie->securityVerifier, 16);
	crypto_hmac_free(hmac);

	return TRUE;
}
示例#3
0
BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
{
	BYTE client_random[64]; /* Should be only 32 after successful decryption, but on failure might take up to 64 bytes. */
	BYTE crypt_client_random[256 + 8];
	UINT32 rand_len, key_len;
	UINT16 channel_id, length, sec_flags;
	BYTE* mod;
	BYTE* priv_exp;

	if (!rdp->settings->DisableEncryption)
	{
		/* No RDP Security. */
		return TRUE;
	}

	if (!rdp_read_header(rdp, s, &length, &channel_id))
	{
		fprintf(stderr, "rdp_server_establish_keys: invalid RDP header\n");
		return FALSE;
	}

	if (!rdp_read_security_header(s, &sec_flags))
		return FALSE;

	if ((sec_flags & SEC_EXCHANGE_PKT) == 0)
	{
		fprintf(stderr, "rdp_server_establish_keys: missing SEC_EXCHANGE_PKT in security header\n");
		return FALSE;
	}

	if (Stream_GetRemainingLength(s) < 4)
		return FALSE;

	Stream_Read_UINT32(s, rand_len);

	if (Stream_GetRemainingLength(s) < rand_len + 8)  /* include 8 bytes of padding */
		return FALSE;

	key_len = rdp->settings->RdpServerRsaKey->ModulusLength;

	if (rand_len != key_len + 8)
	{
		fprintf(stderr, "rdp_server_establish_keys: invalid encrypted client random length\n");
		return FALSE;
	}

	ZeroMemory(crypt_client_random, sizeof(crypt_client_random));
	Stream_Read(s, crypt_client_random, rand_len);
	/* 8 zero bytes of padding */
	Stream_Seek(s, 8);
	mod = rdp->settings->RdpServerRsaKey->Modulus;
	priv_exp = rdp->settings->RdpServerRsaKey->PrivateExponent;
	crypto_rsa_private_decrypt(crypt_client_random, rand_len - 8, key_len, mod, priv_exp, client_random);

	/* now calculate encrypt / decrypt and update keys */
	if (!security_establish_keys(client_random, rdp))
	{
		return FALSE;
	}

	rdp->do_crypt = TRUE;

	if (rdp->settings->SaltedChecksum)
		rdp->do_secure_checksum = TRUE;

	if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
	{
		rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec);
		rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec);

		rdp->fips_hmac = crypto_hmac_new();
		return TRUE;
	}

	rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len);
	rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);

	return TRUE;
}
示例#4
0
static BOOL rdp_client_establish_keys(rdpRdp* rdp)
{
	BYTE* mod;
	BYTE* exp;
	wStream* s;
	UINT32 length;
	UINT32 key_len;
	BYTE crypt_client_random[256 + 8];

	if (!rdp->settings->DisableEncryption)
	{
		/* no RDP encryption */
		return TRUE;
	}

	/* encrypt client random */

	if (rdp->settings->ClientRandom)
		free(rdp->settings->ClientRandom);

	rdp->settings->ClientRandom = malloc(CLIENT_RANDOM_LENGTH);

	if (!rdp->settings->ClientRandom)
		return FALSE;

	ZeroMemory(crypt_client_random, sizeof(crypt_client_random));

	crypto_nonce(rdp->settings->ClientRandom, CLIENT_RANDOM_LENGTH);
	key_len = rdp->settings->RdpServerCertificate->cert_info.ModulusLength;
	mod = rdp->settings->RdpServerCertificate->cert_info.Modulus;
	exp = rdp->settings->RdpServerCertificate->cert_info.exponent;
	crypto_rsa_public_encrypt(rdp->settings->ClientRandom, CLIENT_RANDOM_LENGTH, key_len, mod, exp, crypt_client_random);

	/* send crypt client random to server */
	length = RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + 4 + key_len + 8;
	s = Stream_New(NULL, length);

	rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
	rdp_write_security_header(s, SEC_EXCHANGE_PKT);
	length = key_len + 8;

	Stream_Write_UINT32(s, length);
	Stream_Write(s, crypt_client_random, length);
	Stream_SealLength(s);

	if (transport_write(rdp->mcs->transport, s) < 0)
	{
		return FALSE;
	}

	Stream_Free(s, TRUE);

	/* now calculate encrypt / decrypt and update keys */
	if (!security_establish_keys(rdp->settings->ClientRandom, rdp))
	{
		return FALSE;
	}

	rdp->do_crypt = TRUE;

	if (rdp->settings->SaltedChecksum)
		rdp->do_secure_checksum = TRUE;

	if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
	{
		rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec);
		rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec);

		rdp->fips_hmac = crypto_hmac_new();
		return TRUE;
	}

	rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len);
	rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);

	return TRUE;
}
示例#5
0
static boolean rdp_server_establish_keys(rdpRdp* rdp, STREAM* s)
{
	uint8 client_random[64]; /* Should be only 32 after successfull decryption, but on failure might take up to 64 bytes. */
	uint8 crypt_client_random[256 + 8];
	uint32 rand_len, key_len;
	uint16 channel_id, length, sec_flags;
	uint8* mod;
	uint8* priv_exp;

	if (rdp->settings->encryption == false)
	{
		/* No RDP Security. */
		return true;
	}

	if (!rdp_read_header(rdp, s, &length, &channel_id))
	{
		printf("rdp_server_establish_keys: invalid RDP header\n");
		return false;
	}
	rdp_read_security_header(s, &sec_flags);
	if ((sec_flags & SEC_EXCHANGE_PKT) == 0)
	{
		printf("rdp_server_establish_keys: missing SEC_EXCHANGE_PKT in security header\n");
		return false;
	}
	stream_read_uint32(s, rand_len);
	key_len = rdp->settings->server_key->modulus.length;
	if (rand_len != key_len + 8)
	{
		printf("rdp_server_establish_keys: invalid encrypted client random length\n");
		return false;
	}
	memset(crypt_client_random, 0, sizeof(crypt_client_random));
	stream_read(s, crypt_client_random, rand_len);
	/* 8 zero bytes of padding */
	stream_seek(s, 8);
	mod = rdp->settings->server_key->modulus.data;
	priv_exp = rdp->settings->server_key->private_exponent.data;
	crypto_rsa_private_decrypt(crypt_client_random, rand_len - 8, key_len, mod, priv_exp, client_random);

	/* now calculate encrypt / decrypt and update keys */
	if (!security_establish_keys(client_random, rdp))
	{
		return false;
	}

	rdp->do_crypt = true;
	if (rdp->settings->salted_checksum)
		rdp->do_secure_checksum = true;

	if (rdp->settings->encryption_method == ENCRYPTION_METHOD_FIPS)
	{
		uint8 fips_ivec[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
		rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec);
		rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec);

		rdp->fips_hmac = crypto_hmac_new();
		return true;
	}

	rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len);
	rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);

	return true;
}
示例#6
0
static boolean rdp_client_establish_keys(rdpRdp* rdp)
{
	uint8 client_random[CLIENT_RANDOM_LENGTH];
	uint8 crypt_client_random[256 + 8];
	uint32 key_len;
	uint8* mod;
	uint8* exp;
	uint32 length;
	STREAM* s;

	if (rdp->settings->encryption == false)
	{
		/* no RDP encryption */
		return true;
	}

	/* encrypt client random */
	memset(crypt_client_random, 0, sizeof(crypt_client_random));
	crypto_nonce(client_random, sizeof(client_random));
	key_len = rdp->settings->server_cert->cert_info.modulus.length;
	mod = rdp->settings->server_cert->cert_info.modulus.data;
	exp = rdp->settings->server_cert->cert_info.exponent;
	crypto_rsa_public_encrypt(client_random, sizeof(client_random), key_len, mod, exp, crypt_client_random);

	/* send crypt client random to server */
	length = RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + 4 + key_len + 8;
	s = transport_send_stream_init(rdp->mcs->transport, length);
	rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
	rdp_write_security_header(s, SEC_EXCHANGE_PKT);
	length = key_len + 8;
	stream_write_uint32(s, length);
	stream_write(s, crypt_client_random, length);
	if (transport_write(rdp->mcs->transport, s) < 0)
	{
		return false;
	}

	/* now calculate encrypt / decrypt and update keys */
	if (!security_establish_keys(client_random, rdp))
	{
		return false;
	}

	rdp->do_crypt = true;
	if (rdp->settings->salted_checksum)
		rdp->do_secure_checksum = true;

	if (rdp->settings->encryption_method == ENCRYPTION_METHOD_FIPS)
	{
		uint8 fips_ivec[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
		rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec);
		rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec);

		rdp->fips_hmac = crypto_hmac_new();
		return true;
	}

	rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len);
	rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);

	return true;
}
示例#7
0
static boolean rdp_establish_keys(rdpRdp* rdp)
{
	uint8 client_random[32];
	uint8 crypt_client_random[256 + 8];
	uint32 key_len;
	uint8* mod;
	uint8* exp;
	uint32 length;
	STREAM* s;

	if (rdp->settings->encryption == False)
	{
		/* no RDP encryption */
		return True;
	}

	/* encrypt client random */
	memset(crypt_client_random, 0, sizeof(crypt_client_random));
	memset(client_random, 0x5e, 32);
	crypto_nonce(client_random, 32);
	key_len = rdp->settings->server_cert->cert_info.modulus.length;
	mod = rdp->settings->server_cert->cert_info.modulus.data;
	exp = rdp->settings->server_cert->cert_info.exponent;
	crypto_rsa_encrypt(client_random, 32, key_len, mod, exp, crypt_client_random);

	/* send crypt client random to server */
	length = 7 + 8 + 4 + 4 + key_len + 8;
	s = transport_send_stream_init(rdp->mcs->transport, length);
	tpkt_write_header(s, length);
	tpdu_write_header(s, 2, 0xf0);
	per_write_choice(s, DomainMCSPDU_SendDataRequest << 2);
	per_write_integer16(s, rdp->mcs->user_id, MCS_BASE_CHANNEL_ID);
	per_write_integer16(s, MCS_GLOBAL_CHANNEL_ID, 0);
	stream_write_uint8(s, 0x70);
	length = (4 + 4 + key_len + 8) | 0x8000;
	stream_write_uint16_be(s, length);
	stream_write_uint32(s, 1); /* SEC_CLIENT_RANDOM */
	length = key_len + 8;
	stream_write_uint32(s, length);
	memcpy(s->p, crypt_client_random, length);
	stream_seek(s, length);
	if (transport_write(rdp->mcs->transport, s) < 0)
	{
		return False;
	}

	/* now calculate encrypt / decrypt and update keys */
	if (!security_establish_keys(client_random, rdp))
	{
		return False;
	}

	rdp->do_crypt = True;

	if (rdp->settings->encryption_method == ENCRYPTION_METHOD_FIPS)
	{
		uint8 fips_ivec[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
		rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec);
		rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec);

		rdp->fips_hmac = crypto_hmac_new();
		return True;
	}

	rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len);
	rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);

	return True;
}
示例#8
0
BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
{
	BYTE* client_random = NULL;
	BYTE* crypt_client_random = NULL;
	UINT32 rand_len, key_len;
	UINT16 channel_id, length, sec_flags;
	BYTE* mod;
	BYTE* priv_exp;
	BOOL ret = FALSE;

	if (!rdp->settings->DisableEncryption)
	{
		/* No RDP Security. */
		return TRUE;
	}

	if (!rdp_read_header(rdp, s, &length, &channel_id))
	{
		WLog_ERR(TAG, "invalid RDP header");
		return FALSE;
	}

	if (!rdp_read_security_header(s, &sec_flags))
	{
		WLog_ERR(TAG, "invalid security header");
		return FALSE;
	}

	if ((sec_flags & SEC_EXCHANGE_PKT) == 0)
	{
		WLog_ERR(TAG, "missing SEC_EXCHANGE_PKT in security header");
		return FALSE;
	}

	rdp->do_crypt_license = (sec_flags & SEC_LICENSE_ENCRYPT_SC) != 0 ? TRUE : FALSE;

	if (Stream_GetRemainingLength(s) < 4)
		return FALSE;

	Stream_Read_UINT32(s, rand_len);

	/* rand_len already includes 8 bytes of padding */
	if (Stream_GetRemainingLength(s) < rand_len)
		return FALSE;

	key_len = rdp->settings->RdpServerRsaKey->ModulusLength;
	client_random = malloc(key_len);
	if (!client_random)
		return FALSE;

	if (rand_len != key_len + 8)
	{
		WLog_ERR(TAG, "invalid encrypted client random length");
		goto end2;
	}

	crypt_client_random = calloc(1, rand_len);
	if (!crypt_client_random)
		goto end2;
	Stream_Read(s, crypt_client_random, rand_len);

	mod = rdp->settings->RdpServerRsaKey->Modulus;
	priv_exp = rdp->settings->RdpServerRsaKey->PrivateExponent;
	crypto_rsa_private_decrypt(crypt_client_random, rand_len - 8, key_len, mod, priv_exp, client_random);

	/* now calculate encrypt / decrypt and update keys */
	if (!security_establish_keys(client_random, rdp))
	{
		goto end;
	}

	rdp->do_crypt = TRUE;

	if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
	{
		rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec);
		if (!rdp->fips_encrypt)
		{
			WLog_ERR(TAG, "unable to allocate des3 encrypt key");
			goto end;
		}

		rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec);
		if (!rdp->fips_decrypt)
		{
			WLog_ERR(TAG, "unable to allocate des3 decrypt key");
			goto end;
		}

		rdp->fips_hmac = crypto_hmac_new();
		if (!rdp->fips_hmac)
		{
			WLog_ERR(TAG, "unable to allocate fips hmac");
			goto end;
		}
		ret = TRUE;
		goto end;
	}

	rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len);
	if (!rdp->rc4_decrypt_key)
	{
		WLog_ERR(TAG, "unable to allocate rc4 decrypt key");
		goto end;
	}

	rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);
	if (!rdp->rc4_encrypt_key)
	{
		WLog_ERR(TAG, "unable to allocate rc4 encrypt key");
		goto end;
	}
	ret = TRUE;
end:
	if (crypt_client_random)
		free(crypt_client_random);
end2:
	if (client_random)
		free(client_random);

	return ret;
}
示例#9
0
static BOOL rdp_client_establish_keys(rdpRdp* rdp)
{
	BYTE* mod;
	BYTE* exp;
	wStream* s;
	UINT32 length;
	UINT32 key_len;
	int status = 0;
	BOOL ret = FALSE;
	rdpSettings* settings;
	BYTE* crypt_client_random = NULL;

	settings = rdp->settings;

	if (!settings->DisableEncryption)
	{
		/* no RDP encryption */
		return TRUE;
	}

	/* encrypt client random */

	if (settings->ClientRandom)
		free(settings->ClientRandom);

	settings->ClientRandomLength = CLIENT_RANDOM_LENGTH;
	settings->ClientRandom = malloc(settings->ClientRandomLength);

	if (!settings->ClientRandom)
		return FALSE;

	crypto_nonce(settings->ClientRandom, settings->ClientRandomLength);
	key_len = settings->RdpServerCertificate->cert_info.ModulusLength;
	mod = settings->RdpServerCertificate->cert_info.Modulus;
	exp = settings->RdpServerCertificate->cert_info.exponent;

	/*
	 * client random must be (bitlen / 8) + 8 - see [MS-RDPBCGR] 5.3.4.1
	 * for details
	 */
	crypt_client_random = calloc(1, key_len + 8);

	if (!crypt_client_random)
		return FALSE;

	crypto_rsa_public_encrypt(settings->ClientRandom, settings->ClientRandomLength, key_len, mod, exp, crypt_client_random);

	/* send crypt client random to server */
	length = RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + 4 + key_len + 8;
	s = Stream_New(NULL, length);

	rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
	rdp_write_security_header(s, SEC_EXCHANGE_PKT | SEC_LICENSE_ENCRYPT_SC);
	length = key_len + 8;

	Stream_Write_UINT32(s, length);
	Stream_Write(s, crypt_client_random, length);
	Stream_SealLength(s);

	status = transport_write(rdp->mcs->transport, s);
	Stream_Free(s, TRUE);

	if (status < 0)
		goto end;

	rdp->do_crypt_license = TRUE;

	/* now calculate encrypt / decrypt and update keys */
	if (!security_establish_keys(settings->ClientRandom, rdp))
		goto end;

	rdp->do_crypt = TRUE;

	if (settings->SaltedChecksum)
		rdp->do_secure_checksum = TRUE;

	if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
	{
		rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec);
		if (!rdp->fips_encrypt)
		{
			WLog_ERR(TAG, "unable to allocate des3 encrypt key");
			goto end;
		}
		rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec);
		if (!rdp->fips_decrypt)
		{
			WLog_ERR(TAG, "unable to allocate des3 decrypt key");
			goto end;
		}

		rdp->fips_hmac = crypto_hmac_new();
		if (!rdp->fips_hmac)
		{
			WLog_ERR(TAG, "unable to allocate fips hmac");
			goto end;
		}
		ret = TRUE;
		goto end;
	}

	rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len);
	if (!rdp->rc4_decrypt_key)
	{
		WLog_ERR(TAG, "unable to allocate rc4 decrypt key");
		goto end;
	}

	rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);
	if (!rdp->rc4_encrypt_key)
	{
		WLog_ERR(TAG, "unable to allocate rc4 encrypt key");
		goto end;
	}
	ret = TRUE;
end:
	if (crypt_client_random)
		free(crypt_client_random);
	return ret;
}
示例#10
0
void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings)
{
	int clientAddressFamily;
	WCHAR* clientAddress = NULL;
	int cbClientAddress;
	WCHAR* clientDir = NULL;
	int cbClientDir;
	int cbAutoReconnectLen;

	clientAddressFamily = settings->IPv6Enabled ? ADDRESS_FAMILY_INET6 : ADDRESS_FAMILY_INET;

	cbClientAddress = ConvertToUnicode(CP_UTF8, 0, settings->ClientAddress, -1, &clientAddress, 0) * 2;

	cbClientDir = ConvertToUnicode(CP_UTF8, 0, settings->ClientDir, -1, &clientDir, 0) * 2;

	cbAutoReconnectLen = (int) settings->ServerAutoReconnectCookie->cbLen;

	Stream_Write_UINT16(s, clientAddressFamily); /* clientAddressFamily */

	Stream_Write_UINT16(s, cbClientAddress + 2); /* cbClientAddress */

	if (cbClientAddress > 0)
		Stream_Write(s, clientAddress, cbClientAddress); /* clientAddress */
	Stream_Write_UINT16(s, 0);

	Stream_Write_UINT16(s, cbClientDir + 2); /* cbClientDir */

	if (cbClientDir > 0)
		Stream_Write(s, clientDir, cbClientDir); /* clientDir */
	Stream_Write_UINT16(s, 0);

	rdp_write_client_time_zone(s, settings); /* clientTimeZone */

	Stream_Write_UINT32(s, 0); /* clientSessionId, should be set to 0 */

	freerdp_performance_flags_make(settings);
	Stream_Write_UINT32(s, settings->PerformanceFlags); /* performanceFlags */

	Stream_Write_UINT16(s, cbAutoReconnectLen); /* cbAutoReconnectLen */

	if (cbAutoReconnectLen > 0)
	{
		CryptoHmac hmac;
		ARC_SC_PRIVATE_PACKET* serverCookie;
		ARC_CS_PRIVATE_PACKET* clientCookie;
		WLog_DBG(TAG, "Sending auto reconnect");
		serverCookie = settings->ServerAutoReconnectCookie;
		clientCookie = settings->ClientAutoReconnectCookie;

		clientCookie->cbLen = serverCookie->cbLen;
		clientCookie->version = serverCookie->version;
		clientCookie->logonId = serverCookie->logonId;

		hmac = crypto_hmac_new();
		if (!hmac)
		{
			WLog_ERR(TAG,  "unable to allocate hmac");
			goto out_free;
		}

		crypto_hmac_md5_init(hmac, serverCookie->arcRandomBits, 16);

		if (settings->SelectedProtocol == PROTOCOL_RDP)
		{
			crypto_hmac_update(hmac, (BYTE*) (settings->ClientRandom), 32);
		}
		else
		{
			/* Anthony Tong's version had 16 zeroes here; I'm not sure why.
			 * I do know that 16 did not reconnect correctly vs Win2008RDVH,
			 * and 32 did.
			 */
			const BYTE zeros[32] = { 0,0,0,0,  0,0,0,0,  0,0,0,0,  0,0,0,0,
				0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
			crypto_hmac_update(hmac, zeros, 32);
		}
		crypto_hmac_final(hmac, clientCookie->securityVerifier, 16);

		rdp_write_client_auto_reconnect_cookie(s, settings); /* autoReconnectCookie */
		/* mark as used */
		settings->ServerAutoReconnectCookie->cbLen = 0;
		crypto_hmac_free(hmac);
	}

	/* reserved1 (2 bytes) */
	/* reserved2 (2 bytes) */
out_free:
	free(clientAddress);
	free(clientDir);
}