From 7171a0b5c1cb39106bb50c2aff797ee3945352b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 11 Aug 2014 11:23:23 -0400 Subject: [PATCH] libfreerdp-core: fix reconnection using client random --- include/freerdp/settings.h | 15 ++++++++------ libfreerdp/common/settings.c | 14 +++++++++++++ libfreerdp/core/connection.c | 38 +++++++++++++++++++++--------------- libfreerdp/core/info.c | 20 ++++++++++++++++++- libfreerdp/core/settings.c | 15 +++++++++++++- 5 files changed, 78 insertions(+), 24 deletions(-) diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index ba05c81c0..5f48aeee7 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -536,6 +536,8 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_ServerRandomLength 197 #define FreeRDP_ServerCertificate 198 #define FreeRDP_ServerCertificateLength 199 +#define FreeRDP_ClientRandom 200 +#define FreeRDP_ClientRandomLength 201 #define FreeRDP_ChannelCount 256 #define FreeRDP_ChannelDefArraySize 257 #define FreeRDP_ChannelDefArray 258 @@ -851,11 +853,12 @@ struct rdp_settings ALIGN64 UINT32 ExtEncryptionMethods; /* 194 */ ALIGN64 UINT32 EncryptionLevel; /* 195 */ ALIGN64 BYTE* ServerRandom; /* 196 */ - ALIGN64 DWORD ServerRandomLength; /* 197 */ + ALIGN64 UINT32 ServerRandomLength; /* 197 */ ALIGN64 BYTE* ServerCertificate; /* 198 */ - ALIGN64 DWORD ServerCertificateLength; /* 199 */ + ALIGN64 UINT32 ServerCertificateLength; /* 199 */ ALIGN64 BYTE* ClientRandom; /* 200 */ - UINT64 padding0256[256 - 201]; /* 201 */ + ALIGN64 UINT32 ClientRandomLength; /* 201 */ + UINT64 padding0256[256 - 202]; /* 202 */ /* Client Network Data */ ALIGN64 UINT32 ChannelCount; /* 256 */ @@ -1014,7 +1017,7 @@ struct rdp_settings /* Credentials Cache */ ALIGN64 BYTE* Password51; /* 1280 */ - ALIGN64 DWORD Password51Length; /* 1281 */ + ALIGN64 UINT32 Password51Length; /* 1281 */ UINT64 padding1344[1344 - 1282]; /* 1282 */ /* Kerberos Authentication */ @@ -1120,8 +1123,8 @@ struct rdp_settings ALIGN64 char* RemoteApplicationFile; /* 2116 */ ALIGN64 char* RemoteApplicationGuid; /* 2117 */ ALIGN64 char* RemoteApplicationCmdLine; /* 2118 */ - ALIGN64 DWORD RemoteApplicationExpandCmdLine; /* 2119 */ - ALIGN64 DWORD RemoteApplicationExpandWorkingDir; /* 2120 */ + ALIGN64 UINT32 RemoteApplicationExpandCmdLine; /* 2119 */ + ALIGN64 UINT32 RemoteApplicationExpandWorkingDir; /* 2120 */ ALIGN64 BOOL DisableRemoteAppCapsCheck; /* 2121 */ ALIGN64 UINT32 RemoteAppNumIconCaches; /* 2122 */ ALIGN64 UINT32 RemoteAppNumIconCacheEntries; /* 2123 */ diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index 739e03f70..07956bee1 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -1626,6 +1626,12 @@ UINT32 freerdp_get_param_uint32(rdpSettings* settings, int id) case FreeRDP_EncryptionLevel: return settings->EncryptionLevel; + case FreeRDP_ServerRandomLength: + return settings->ServerRandomLength; + + case FreeRDP_ClientRandomLength: + return settings->ClientRandomLength; + case FreeRDP_ChannelCount: return settings->ChannelCount; @@ -1875,6 +1881,14 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param) settings->EncryptionLevel = param; break; + case FreeRDP_ServerRandomLength: + settings->ServerRandomLength = param; + break; + + case FreeRDP_ClientRandomLength: + settings->ClientRandomLength = param; + break; + case FreeRDP_ChannelCount: settings->ChannelCount = param; break; diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index b19d97148..52947636a 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -388,11 +388,14 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) wStream* s; UINT32 length; UINT32 key_len; - BYTE *crypt_client_random = NULL; - BOOL ret = FALSE; int status = 0; + BOOL ret = FALSE; + rdpSettings* settings; + BYTE* crypt_client_random = NULL; - if (!rdp->settings->DisableEncryption) + settings = rdp->settings; + + if (!settings->DisableEncryption) { /* no RDP encryption */ return TRUE; @@ -400,27 +403,30 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) /* encrypt client random */ - if (rdp->settings->ClientRandom) - free(rdp->settings->ClientRandom); + if (settings->ClientRandom) + free(settings->ClientRandom); - rdp->settings->ClientRandom = malloc(CLIENT_RANDOM_LENGTH); + settings->ClientRandomLength = CLIENT_RANDOM_LENGTH; + settings->ClientRandom = malloc(settings->ClientRandomLength); - if (!rdp->settings->ClientRandom) + 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; - 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; /* * client random must be (bitlen / 8) + 8 - see [MS-RDPBCGR] 5.3.4.1 * for details */ - crypt_client_random = calloc(1,key_len+8); + crypt_client_random = calloc(1, key_len + 8); + if (!crypt_client_random) return FALSE; - crypto_rsa_public_encrypt(rdp->settings->ClientRandom, CLIENT_RANDOM_LENGTH, key_len, mod, exp, crypt_client_random); + + 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; @@ -441,15 +447,15 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) goto end; /* now calculate encrypt / decrypt and update keys */ - if (!security_establish_keys(rdp->settings->ClientRandom, rdp)) + if (!security_establish_keys(settings->ClientRandom, rdp)) goto end; rdp->do_crypt = TRUE; - if (rdp->settings->SaltedChecksum) + if (settings->SaltedChecksum) rdp->do_secure_checksum = TRUE; - if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) + if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) { rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec); if (!rdp->fips_encrypt) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 300b854b8..771e86bc7 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -105,13 +105,31 @@ BOOL rdp_read_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) 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, autoReconnectCookie->securityVerifier, 16); /* SecurityVerifier */ + Stream_Write(s, cryptSecurityVerifier, 16); /* SecurityVerifier */ } /** diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index f112ad452..feb811967 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -522,6 +522,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->EncryptionLevel = settings->EncryptionLevel; /* 195 */ _settings->ServerRandomLength = settings->ServerRandomLength; /* 197 */ _settings->ServerCertificateLength = settings->ServerCertificateLength; /* 199 */ + _settings->ClientRandomLength = settings->ClientRandomLength; /* 201 */ _settings->ChannelCount = settings->ChannelCount; /* 256 */ _settings->ChannelDefArraySize = settings->ChannelDefArraySize; /* 257 */ _settings->ClusterInfoFlags = settings->ClusterInfoFlags; /* 320 */ @@ -725,6 +726,18 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) * Manual Code */ + if (_settings->ServerRandomLength) + { + _settings->ServerRandom = (BYTE*) malloc(_settings->ServerRandomLength); + CopyMemory(_settings->ServerRandom, settings->ServerRandom, _settings->ServerRandomLength); + } + + if (_settings->ClientRandomLength) + { + _settings->ClientRandom = (BYTE*) malloc(_settings->ClientRandomLength); + CopyMemory(_settings->ClientRandom, settings->ClientRandom, _settings->ClientRandomLength); + } + _settings->ChannelCount = settings->ChannelCount; _settings->ChannelDefArraySize = settings->ChannelDefArraySize; _settings->ChannelDefArray = (CHANNEL_DEF*) malloc(sizeof(CHANNEL_DEF) * settings->ChannelDefArraySize); @@ -836,7 +849,7 @@ void freerdp_settings_free(rdpSettings* settings) free(settings->ClientHostname); free(settings->ClientProductId); free(settings->ServerRandom); - if (settings->ClientRandom) free(settings->ClientRandom); + free(settings->ClientRandom); free(settings->ServerCertificate); free(settings->RdpKeyFile); certificate_free(settings->RdpServerCertificate);