From 8292b4558f0684065ce1f58db7783cc426099223 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 29 May 2017 10:50:22 +0200 Subject: [PATCH] Fix TALOS issues Fix the following issues identified by the CISCO TALOS project: * TALOS-2017-0336 CVE-2017-2834 * TALOS-2017-0337 CVE-2017-2834 * TALOS-2017-0338 CVE-2017-2836 * TALOS-2017-0339 CVE-2017-2837 * TALOS-2017-0340 CVE-2017-2838 * TALOS-2017-0341 CVE-2017-2839 --- libfreerdp/core/capabilities.c | 4 +- libfreerdp/core/certificate.c | 14 +++---- libfreerdp/core/certificate.h | 2 +- libfreerdp/core/connection.c | 6 +-- libfreerdp/core/gcc.c | 31 +++++++++++----- libfreerdp/core/info.c | 4 +- libfreerdp/core/license.c | 67 +++++++++++++++++++++++++++++++--- libfreerdp/core/license.h | 45 +---------------------- libfreerdp/core/mcs.c | 11 ++++-- libfreerdp/core/nego.c | 7 +++- libfreerdp/core/peer.c | 6 +-- libfreerdp/core/rdp.c | 43 ++++++++++++++++------ libfreerdp/core/rdp.h | 4 +- libfreerdp/core/security.c | 12 +++--- libfreerdp/core/security.h | 16 ++++---- libfreerdp/core/tpkt.c | 23 +++++++++--- libfreerdp/core/tpkt.h | 2 +- 17 files changed, 181 insertions(+), 116 deletions(-) diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index c083527ae..e026c007a 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -3769,12 +3769,12 @@ BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId) if (rdp->settings->UseRdpSecurityLayer) { - if (!rdp_read_security_header(s, &securityFlags)) + if (!rdp_read_security_header(s, &securityFlags, &length)) return FALSE; if (securityFlags & SEC_ENCRYPT) { - if (!rdp_decrypt(rdp, s, length - 4, securityFlags)) + if (!rdp_decrypt(rdp, s, length, securityFlags)) { WLog_ERR(TAG, "rdp_decrypt failed"); return FALSE; diff --git a/libfreerdp/core/certificate.c b/libfreerdp/core/certificate.c index 515a1024d..620bbc980 100644 --- a/libfreerdp/core/certificate.c +++ b/libfreerdp/core/certificate.c @@ -362,7 +362,6 @@ static BOOL certificate_process_server_public_key(rdpCertificate* certificate, w UINT32 keylen; UINT32 bitlen; UINT32 datalen; - UINT32 modlen; if (Stream_GetRemainingLength(s) < 20) return FALSE; @@ -379,12 +378,11 @@ static BOOL certificate_process_server_public_key(rdpCertificate* certificate, w Stream_Read_UINT32(s, bitlen); Stream_Read_UINT32(s, datalen); Stream_Read(s, certificate->cert_info.exponent, 4); - modlen = keylen - 8; - if (Stream_GetRemainingLength(s) < modlen + 8) // count padding + if ((keylen <= 8) || (Stream_GetRemainingLength(s) < keylen)) return FALSE; - certificate->cert_info.ModulusLength = modlen; + certificate->cert_info.ModulusLength = keylen - 8; certificate->cert_info.Modulus = malloc(certificate->cert_info.ModulusLength); if (!certificate->cert_info.Modulus) @@ -405,7 +403,7 @@ static BOOL certificate_process_server_public_signature(rdpCertificate* certific BYTE md5hash[WINPR_MD5_DIGEST_LENGTH]; if (!winpr_Digest(WINPR_MD_MD5, sigdata, sigdatalen, md5hash, sizeof(md5hash))) - return FALSE; + return FALSE; Stream_Read(s, encsig, siglen); /* Last 8 bytes shall be all zero. */ @@ -546,7 +544,7 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, wStream* s) { - int i; + UINT32 i; BOOL ret; UINT32 certLength; UINT32 numCertBlobs; @@ -562,7 +560,7 @@ BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, if (!certificate->x509_cert_chain) return FALSE; - for (i = 0; i < (int) numCertBlobs; i++) + for (i = 0; i < numCertBlobs; i++) { if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -621,7 +619,7 @@ BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, * @param length certificate length */ -BOOL certificate_read_server_certificate(rdpCertificate* certificate, BYTE* server_cert, int length) +BOOL certificate_read_server_certificate(rdpCertificate* certificate, BYTE* server_cert, size_t length) { BOOL ret; wStream* s; diff --git a/libfreerdp/core/certificate.h b/libfreerdp/core/certificate.h index 1dd31eb90..990fd29c4 100644 --- a/libfreerdp/core/certificate.h +++ b/libfreerdp/core/certificate.h @@ -58,7 +58,7 @@ FREERDP_LOCAL BOOL certificate_read_server_proprietary_certificate( FREERDP_LOCAL BOOL certificate_read_server_x509_certificate_chain( rdpCertificate* certificate, wStream* s); FREERDP_LOCAL BOOL certificate_read_server_certificate(rdpCertificate* - certificate, BYTE* server_cert, int length); + certificate, BYTE* server_cert, size_t length); FREERDP_LOCAL rdpCertificate* certificate_clone(rdpCertificate* certificate); diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index b3e1ecc27..df2da7838 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -542,7 +542,7 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) return FALSE; } - if (!rdp_read_security_header(s, &sec_flags)) + if (!rdp_read_security_header(s, &sec_flags, NULL)) { WLog_ERR(TAG, "invalid security header"); return FALSE; @@ -769,12 +769,12 @@ BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s) { UINT16 securityFlags = 0; - if (!rdp_read_security_header(s, &securityFlags)) + if (!rdp_read_security_header(s, &securityFlags, &length)) return FALSE; if (securityFlags & SEC_ENCRYPT) { - if (!rdp_decrypt(rdp, s, length - 4, securityFlags)) + if (!rdp_decrypt(rdp, s, length, securityFlags)) { WLog_ERR(TAG, "rdp_decrypt failed"); return FALSE; diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c index ef7302c9c..ae26115ab 100644 --- a/libfreerdp/core/gcc.c +++ b/libfreerdp/core/gcc.c @@ -33,6 +33,7 @@ #define TAG FREERDP_TAG("core.gcc") + /** * T.124 GCC is defined in: * @@ -1188,38 +1189,50 @@ BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs) Stream_Read_UINT32(s, settings->ServerRandomLength); /* serverRandomLen */ Stream_Read_UINT32(s, settings->ServerCertificateLength); /* serverCertLen */ - if (Stream_GetRemainingLength(s) < settings->ServerRandomLength + - settings->ServerCertificateLength) + if ((settings->ServerRandomLength == 0) || (settings->ServerCertificateLength == 0)) return FALSE; - if ((settings->ServerRandomLength <= 0) - || (settings->ServerCertificateLength <= 0)) + if (Stream_GetRemainingLength(s) < settings->ServerRandomLength) return FALSE; /* serverRandom */ settings->ServerRandom = (BYTE*) malloc(settings->ServerRandomLength); if (!settings->ServerRandom) - return FALSE; + goto fail; Stream_Read(s, settings->ServerRandom, settings->ServerRandomLength); + + if (Stream_GetRemainingLength(s) < settings->ServerCertificateLength) + goto fail; + /* serverCertificate */ settings->ServerCertificate = (BYTE*) malloc(settings->ServerCertificateLength); if (!settings->ServerCertificate) - return FALSE; + goto fail; Stream_Read(s, settings->ServerCertificate, settings->ServerCertificateLength); certificate_free(settings->RdpServerCertificate); settings->RdpServerCertificate = certificate_new(); if (!settings->RdpServerCertificate) - return FALSE; + goto fail; data = settings->ServerCertificate; length = settings->ServerCertificateLength; - return certificate_read_server_certificate(settings->RdpServerCertificate, data, - length); + if (!certificate_read_server_certificate(settings->RdpServerCertificate, data, + length)) + goto fail; + + return TRUE; + +fail: + free (settings->ServerRandom); + free (settings->ServerCertificate); + settings->ServerRandom = NULL; + settings->ServerCertificate = NULL; + return FALSE; } static const BYTE initial_signature[] = diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 697f247c9..1a0beee31 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -806,7 +806,7 @@ BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s) if (!rdp_read_header(rdp, s, &length, &channelId)) return FALSE; - if (!rdp_read_security_header(s, &securityFlags)) + if (!rdp_read_security_header(s, &securityFlags, &length)) return FALSE; if ((securityFlags & SEC_INFO_PKT) == 0) @@ -822,7 +822,7 @@ BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s) if (securityFlags & SEC_ENCRYPT) { - if (!rdp_decrypt(rdp, s, length - 4, securityFlags)) + if (!rdp_decrypt(rdp, s, length, securityFlags)) { WLog_ERR(TAG, "rdp_decrypt failed"); return FALSE; diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c index 8b19eae25..d89163969 100644 --- a/libfreerdp/core/license.c +++ b/libfreerdp/core/license.c @@ -36,6 +36,40 @@ /* #define LICENSE_NULL_CLIENT_RANDOM 1 */ /* #define LICENSE_NULL_PREMASTER_SECRET 1 */ +static wStream* license_send_stream_init(rdpLicense* license); + +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); +static BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo); + +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 SCOPE_LIST* license_new_scope_list(void); +static void license_free_scope_list(SCOPE_LIST* scopeList); +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_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_write_platform_challenge_response_packet( + rdpLicense* license, wStream* s, BYTE* mac_data); +static BOOL license_send_platform_challenge_response_packet(rdpLicense* license); + #ifdef WITH_DEBUG_LICENSE static const char* const LICENSE_MESSAGE_STRINGS[] = @@ -82,7 +116,7 @@ static const char* const state_transitions[] = "ST_RESEND_LAST_MESSAGE" }; -void license_print_product_info(LICENSE_PRODUCT_INFO* productInfo) +static void license_print_product_info(LICENSE_PRODUCT_INFO* productInfo) { char* CompanyName = NULL; char* ProductId = NULL; @@ -98,7 +132,7 @@ void license_print_product_info(LICENSE_PRODUCT_INFO* productInfo) free(ProductId); } -void license_print_scope_list(SCOPE_LIST* scopeList) +static void license_print_scope_list(SCOPE_LIST* scopeList) { int index; LICENSE_BLOB* scope; @@ -251,12 +285,12 @@ int license_recv(rdpLicense* license, wStream* s) return -1; } - if (!rdp_read_security_header(s, &securityFlags)) + if (!rdp_read_security_header(s, &securityFlags, &length)) return -1; if (securityFlags & SEC_ENCRYPT) { - if (!rdp_decrypt(license->rdp, s, length - 4, securityFlags)) + if (!rdp_decrypt(license->rdp, s, length, securityFlags)) { WLog_ERR(TAG, "rdp_decrypt failed"); return -1; @@ -463,7 +497,12 @@ BOOL license_decrypt_platform_challenge(rdpLicense* license) if ((rc4 = winpr_RC4_New(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH)) == NULL) + { + free(license->PlatformChallenge->data); + license->PlatformChallenge->data = NULL; + license->PlatformChallenge->length = 0; return FALSE; + } rc = winpr_RC4_Update(rc4, license->EncryptedPlatformChallenge->length, license->EncryptedPlatformChallenge->data, license->PlatformChallenge->data); @@ -487,15 +526,27 @@ BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo) Stream_Read_UINT32(s, productInfo->dwVersion); /* dwVersion (4 bytes) */ Stream_Read_UINT32(s, productInfo->cbCompanyName); /* cbCompanyName (4 bytes) */ - if (Stream_GetRemainingLength(s) < productInfo->cbCompanyName + 4) + /* Name must be >0, but there is no upper limit defined, use UINT32_MAX */ + if ((productInfo->cbCompanyName < 2) || (productInfo->cbCompanyName % 2 != 0)) return FALSE; + if (Stream_GetRemainingLength(s) < productInfo->cbCompanyName) + return FALSE; + + 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) + goto out_fail; + Stream_Read_UINT32(s, productInfo->cbProductId); /* cbProductId (4 bytes) */ + if ((productInfo->cbProductId < 2) || (productInfo->cbProductId % 2 != 0)) + goto out_fail; + if (Stream_GetRemainingLength(s) < productInfo->cbProductId) goto out_fail; @@ -507,7 +558,9 @@ BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo) out_fail: free(productInfo->pbCompanyName); + free(productInfo->pbProductId); productInfo->pbCompanyName = NULL; + productInfo->pbProductId = NULL; return FALSE; } @@ -806,7 +859,9 @@ BOOL license_read_platform_challenge_packet(rdpLicense* license, wStream* s) Stream_Read_UINT32(s, ConnectFlags); /* ConnectFlags, Reserved (4 bytes) */ /* EncryptedPlatformChallenge */ license->EncryptedPlatformChallenge->type = BB_ANY_BLOB; - license_read_binary_blob(s, license->EncryptedPlatformChallenge); + if (!license_read_binary_blob(s, license->EncryptedPlatformChallenge)) + return FALSE; + license->EncryptedPlatformChallenge->type = BB_ENCRYPTED_DATA_BLOB; if (Stream_GetRemainingLength(s) < 16) diff --git a/libfreerdp/core/license.h b/libfreerdp/core/license.h index 27369cf4f..760320687 100644 --- a/libfreerdp/core/license.h +++ b/libfreerdp/core/license.h @@ -17,8 +17,8 @@ * limitations under the License. */ -#ifndef __LICENSE_H -#define __LICENSE_H +#ifndef FREERDP_LICENSE_H +#define FREERDP_LICENSE_H typedef struct rdp_license rdpLicense; @@ -203,47 +203,6 @@ struct rdp_license FREERDP_LOCAL int license_recv(rdpLicense* license, wStream* s); FREERDP_LOCAL BOOL license_send(rdpLicense* license, wStream* s, BYTE type); -FREERDP_LOCAL wStream* license_send_stream_init(rdpLicense* license); - -FREERDP_LOCAL void license_generate_randoms(rdpLicense* license); -FREERDP_LOCAL BOOL license_generate_keys(rdpLicense* license); -FREERDP_LOCAL BOOL license_generate_hwid(rdpLicense* license); -FREERDP_LOCAL BOOL license_encrypt_premaster_secret(rdpLicense* license); -FREERDP_LOCAL BOOL license_decrypt_platform_challenge(rdpLicense* license); - -FREERDP_LOCAL LICENSE_PRODUCT_INFO* license_new_product_info(void); -FREERDP_LOCAL void license_free_product_info(LICENSE_PRODUCT_INFO* productInfo); -FREERDP_LOCAL BOOL license_read_product_info(wStream* s, - LICENSE_PRODUCT_INFO* productInfo); - -FREERDP_LOCAL LICENSE_BLOB* license_new_binary_blob(UINT16 type); -FREERDP_LOCAL void license_free_binary_blob(LICENSE_BLOB* blob); -FREERDP_LOCAL BOOL license_read_binary_blob(wStream* s, LICENSE_BLOB* blob); -FREERDP_LOCAL BOOL license_write_binary_blob(wStream* s, LICENSE_BLOB* blob); - -FREERDP_LOCAL SCOPE_LIST* license_new_scope_list(void); -FREERDP_LOCAL void license_free_scope_list(SCOPE_LIST* scopeList); -FREERDP_LOCAL BOOL license_read_scope_list(wStream* s, SCOPE_LIST* scopeList); - -FREERDP_LOCAL BOOL license_read_license_request_packet(rdpLicense* license, - wStream* s); -FREERDP_LOCAL BOOL license_read_platform_challenge_packet(rdpLicense* license, - wStream* s); -FREERDP_LOCAL void license_read_new_license_packet(rdpLicense* license, - wStream* s); -FREERDP_LOCAL void license_read_upgrade_license_packet(rdpLicense* license, - wStream* s); -FREERDP_LOCAL BOOL license_read_error_alert_packet(rdpLicense* license, - wStream* s); - -FREERDP_LOCAL BOOL license_write_new_license_request_packet(rdpLicense* license, - wStream* s); -FREERDP_LOCAL BOOL license_send_new_license_request_packet(rdpLicense* license); - -FREERDP_LOCAL BOOL license_write_platform_challenge_response_packet( - rdpLicense* license, wStream* s, BYTE* mac_data); -FREERDP_LOCAL BOOL license_send_platform_challenge_response_packet( - rdpLicense* license); FREERDP_LOCAL BOOL license_send_valid_client_error_packet(rdpLicense* license); diff --git a/libfreerdp/core/mcs.c b/libfreerdp/core/mcs.c index aedb9eae1..cadaa9fa7 100644 --- a/libfreerdp/core/mcs.c +++ b/libfreerdp/core/mcs.c @@ -232,7 +232,8 @@ BOOL mcs_read_domain_mcspdu_header(wStream* s, enum DomainMCSPDU* domainMCSPDU, if (!s || !domainMCSPDU || !length) return FALSE; - *length = tpkt_read_header(s); + if (!tpkt_read_header(s, length)) + return FALSE; if (!tpdu_read_data(s, &li)) return FALSE; @@ -509,11 +510,13 @@ BOOL mcs_recv_connect_initial(rdpMcs* mcs, wStream* s) UINT16 li; int length; BOOL upwardFlag; + UINT16 tlength; if (!mcs || !s) return FALSE; - tpkt_read_header(s); + if (!tpkt_read_header(s, &tlength)) + return FALSE; if (!tpdu_read_data(s, &li)) return FALSE; @@ -739,6 +742,7 @@ out: BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s) { int length; + UINT16 tlength; BYTE result; UINT16 li; UINT32 calledConnectId; @@ -746,7 +750,8 @@ BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s) if (!mcs || !s) return FALSE; - tpkt_read_header(s); + if (!tpkt_read_header(s, &tlength)) + return FALSE; if (!tpdu_read_data(s, &li)) return FALSE; diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index d4b023a1c..068a60323 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -575,7 +575,8 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra) UINT16 length; rdpNego* nego = (rdpNego*) extra; - length = tpkt_read_header(s); + if (!tpkt_read_header(s, &length)) + return -1; if (length == 0) return -1; @@ -739,8 +740,10 @@ BOOL nego_read_request(rdpNego* nego, wStream* s) { BYTE li; BYTE type; + UINT16 length; - tpkt_read_header(s); + if (!tpkt_read_header(s, &length)) + return FALSE; if (!tpdu_read_connection_request(s, &li)) return FALSE; diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index fb02f71e9..2d978da43 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -371,12 +371,12 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s) if (rdp->settings->UseRdpSecurityLayer) { - if (!rdp_read_security_header(s, &securityFlags)) + if (!rdp_read_security_header(s, &securityFlags, &length)) return -1; if (securityFlags & SEC_ENCRYPT) { - if (!rdp_decrypt(rdp, s, length - 4, securityFlags)) + if (!rdp_decrypt(rdp, s, length, securityFlags)) { WLog_ERR(TAG, "rdp_decrypt failed"); return -1; @@ -418,7 +418,7 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s) else if (rdp->mcs->messageChannelId && channelId == rdp->mcs->messageChannelId) { if (!rdp->settings->UseRdpSecurityLayer) - if (!rdp_read_security_header(s, &securityFlags)) + if (!rdp_read_security_header(s, &securityFlags, NULL)) return -1; return rdp_recv_message_channel_pdu(rdp, s, securityFlags); diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index f89d9c25e..a76b2c4ff 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -79,13 +79,17 @@ const char* DATA_PDU_TYPE_STRINGS[80] = * @param flags security flags */ -BOOL rdp_read_security_header(wStream* s, UINT16* flags) +BOOL rdp_read_security_header(wStream* s, UINT16* flags, UINT16* length) { /* Basic Security Header */ - if (Stream_GetRemainingLength(s) < 4) + if ((Stream_GetRemainingLength(s) < 4) || (length && (*length < 4))) return FALSE; Stream_Read_UINT16(s, *flags); /* flags */ Stream_Seek(s, 2); /* flagsHi (unused) */ + + if (length) + *length -= 4; + return TRUE; } @@ -301,7 +305,8 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) MCSPDU = (rdp->settings->ServerMode) ? DomainMCSPDU_SendDataRequest : DomainMCSPDU_SendDataIndication; - *length = tpkt_read_header(s); + if (!tpkt_read_header(s, length)) + return FALSE; if (!tpdu_read_header(s, &code, &li)) return FALSE; @@ -330,7 +335,10 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) MCSPDU = domainMCSPDU; - if ((size_t) (*length - 8) > Stream_GetRemainingLength(s)) + if (*length < 8) + return FALSE; + + if ((*length - 8) > Stream_GetRemainingLength(s)) return FALSE; if (MCSPDU == DomainMCSPDU_DisconnectProviderUltimatum) @@ -376,8 +384,12 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) if (Stream_GetRemainingLength(s) < 5) return FALSE; - per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */ - per_read_integer16(s, channelId, 0); /* channelId */ + if (!per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */ + return FALSE; + + if (!per_read_integer16(s, channelId, 0)) /* channelId */ + return FALSE; + Stream_Read_UINT8(s, byte); /* dataPriority + Segmentation (0x70) */ if (!per_read_length(s, length)) /* userData (OCTET_STRING) */ @@ -1030,17 +1042,21 @@ void rdp_read_flow_control_pdu(wStream* s, UINT16* type) * @param length int */ -BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags) +BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, INT32 length, UINT16 securityFlags) { BYTE cmac[8]; BYTE wmac[8]; BOOL status; + if (!rdp || !s || (length < 0)) + return FALSE; + if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) { UINT16 len; BYTE version, pad; BYTE* sig; + INT64 padLength; if (Stream_GetRemainingLength(s) < 12) return FALSE; @@ -1053,6 +1069,9 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags) Stream_Seek(s, 8); /* signature */ length -= 12; + padLength = length - pad; + if ((length <= 0) || (padLength <= 0)) + return FALSE; if (!security_fips_decrypt(Stream_Pointer(s), length, rdp)) { @@ -1070,11 +1089,13 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags) return TRUE; } - if (Stream_GetRemainingLength(s) < 8) + if (Stream_GetRemainingLength(s) < sizeof(wmac)) return FALSE; Stream_Read(s, wmac, sizeof(wmac)); length -= sizeof(wmac); + if (length <= 0) + return FALSE; if (!security_decrypt(Stream_Pointer(s), length, rdp)) return FALSE; @@ -1135,7 +1156,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) if (rdp->settings->UseRdpSecurityLayer) { - if (!rdp_read_security_header(s, &securityFlags)) + if (!rdp_read_security_header(s, &securityFlags, &length)) { WLog_ERR(TAG, "rdp_recv_tpkt_pdu: rdp_read_security_header() fail"); return -1; @@ -1143,7 +1164,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) if (securityFlags & (SEC_ENCRYPT | SEC_REDIRECTION_PKT)) { - if (!rdp_decrypt(rdp, s, length - 4, securityFlags)) + if (!rdp_decrypt(rdp, s, length, securityFlags)) { WLog_ERR(TAG, "rdp_decrypt failed"); return -1; @@ -1216,7 +1237,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) else if (rdp->mcs->messageChannelId && channelId == rdp->mcs->messageChannelId) { if (!rdp->settings->UseRdpSecurityLayer) - if (!rdp_read_security_header(s, &securityFlags)) + if (!rdp_read_security_header(s, &securityFlags, NULL)) return -1; return rdp_recv_message_channel_pdu(rdp, s, securityFlags); diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index 484e38217..cd68c9ffa 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -177,7 +177,7 @@ struct rdp_rdp BOOL AwaitCapabilities; }; -FREERDP_LOCAL BOOL rdp_read_security_header(wStream* s, UINT16* flags); +FREERDP_LOCAL BOOL rdp_read_security_header(wStream* s, UINT16* flags, UINT16* length); FREERDP_LOCAL void rdp_write_security_header(wStream* s, UINT16 flags); FREERDP_LOCAL BOOL rdp_read_share_control_header(wStream* s, UINT16* length, @@ -245,7 +245,7 @@ extern const char* DATA_PDU_TYPE_STRINGS[80]; #define DEBUG_RDP(...) do { } while (0) #endif -BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags); +BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, INT32 length, UINT16 securityFlags); BOOL rdp_set_error_info(rdpRdp* rdp, UINT32 errorInfo); BOOL rdp_send_error_info(rdpRdp* rdp); diff --git a/libfreerdp/core/security.c b/libfreerdp/core/security.c index 28a7e42be..807f58fc4 100644 --- a/libfreerdp/core/security.c +++ b/libfreerdp/core/security.c @@ -637,7 +637,7 @@ out: return result; } -BOOL security_encrypt(BYTE* data, int length, rdpRdp* rdp) +BOOL security_encrypt(BYTE* data, size_t length, rdpRdp* rdp) { if (rdp->encrypt_use_count >= 4096) { @@ -659,7 +659,7 @@ BOOL security_encrypt(BYTE* data, int length, rdpRdp* rdp) return TRUE; } -BOOL security_decrypt(BYTE* data, int length, rdpRdp* rdp) +BOOL security_decrypt(BYTE* data, size_t length, rdpRdp* rdp) { if (rdp->rc4_decrypt_key == NULL) return FALSE; @@ -683,7 +683,7 @@ BOOL security_decrypt(BYTE* data, int length, rdpRdp* rdp) return TRUE; } -BOOL security_hmac_signature(const BYTE* data, int length, BYTE* output, rdpRdp* rdp) +BOOL security_hmac_signature(const BYTE* data, size_t length, BYTE* output, rdpRdp* rdp) { BYTE buf[WINPR_SHA1_DIGEST_LENGTH]; BYTE use_count_le[4]; @@ -710,7 +710,7 @@ out: return result; } -BOOL security_fips_encrypt(BYTE* data, int length, rdpRdp* rdp) +BOOL security_fips_encrypt(BYTE* data, size_t length, rdpRdp* rdp) { size_t olen; @@ -720,7 +720,7 @@ BOOL security_fips_encrypt(BYTE* data, int length, rdpRdp* rdp) return TRUE; } -BOOL security_fips_decrypt(BYTE* data, int length, rdpRdp* rdp) +BOOL security_fips_decrypt(BYTE* data, size_t length, rdpRdp* rdp) { size_t olen; @@ -729,7 +729,7 @@ BOOL security_fips_decrypt(BYTE* data, int length, rdpRdp* rdp) return TRUE; } -BOOL security_fips_check_signature(const BYTE* data, int length, const BYTE* sig, rdpRdp* rdp) +BOOL security_fips_check_signature(const BYTE* data, size_t length, const BYTE* sig, rdpRdp* rdp) { BYTE buf[WINPR_SHA1_DIGEST_LENGTH]; BYTE use_count_le[4]; diff --git a/libfreerdp/core/security.h b/libfreerdp/core/security.h index 34bbbcd72..956463149 100644 --- a/libfreerdp/core/security.h +++ b/libfreerdp/core/security.h @@ -17,8 +17,8 @@ * limitations under the License. */ -#ifndef __SECURITY_H -#define __SECURITY_H +#ifndef FREERDP_SECURITY_H +#define FREERDP_SECURITY_H #include "rdp.h" #include @@ -45,13 +45,13 @@ FREERDP_LOCAL BOOL security_salted_mac_signature(rdpRdp* rdp, const BYTE* data, UINT32 length, BOOL encryption, BYTE* output); FREERDP_LOCAL BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp); -FREERDP_LOCAL BOOL security_encrypt(BYTE* data, int length, rdpRdp* rdp); -FREERDP_LOCAL BOOL security_decrypt(BYTE* data, int length, rdpRdp* rdp); -FREERDP_LOCAL BOOL security_hmac_signature(const BYTE* data, int length, +FREERDP_LOCAL BOOL security_encrypt(BYTE* data, size_t length, rdpRdp* rdp); +FREERDP_LOCAL BOOL security_decrypt(BYTE* data, size_t length, rdpRdp* rdp); +FREERDP_LOCAL BOOL security_hmac_signature(const BYTE* data, size_t length, BYTE* output, rdpRdp* rdp); -FREERDP_LOCAL BOOL security_fips_encrypt(BYTE* data, int length, rdpRdp* rdp); -FREERDP_LOCAL BOOL security_fips_decrypt(BYTE* data, int length, rdpRdp* rdp); -FREERDP_LOCAL BOOL security_fips_check_signature(const BYTE* data, int length, +FREERDP_LOCAL BOOL security_fips_encrypt(BYTE* data, size_t length, rdpRdp* rdp); +FREERDP_LOCAL BOOL security_fips_decrypt(BYTE* data, size_t length, rdpRdp* rdp); +FREERDP_LOCAL BOOL security_fips_check_signature(const BYTE* data, size_t length, const BYTE* sig, rdpRdp* rdp); #endif /* __SECURITY_H */ diff --git a/libfreerdp/core/tpkt.c b/libfreerdp/core/tpkt.c index 5689d62e4..eed79d731 100644 --- a/libfreerdp/core/tpkt.c +++ b/libfreerdp/core/tpkt.c @@ -78,28 +78,39 @@ BOOL tpkt_verify_header(wStream* s) /** * Read a TPKT header.\n * @param s - * @return length + * @param length + * @return success */ -UINT16 tpkt_read_header(wStream* s) +BOOL tpkt_read_header(wStream* s, UINT16* length) { BYTE version; - UINT16 length; + + if (Stream_GetRemainingLength(s) < 1) + return FALSE; Stream_Peek_UINT8(s, version); if (version == 3) { + UINT16 len; + if (Stream_GetRemainingLength(s) < 4) + return FALSE; + Stream_Seek(s, 2); - Stream_Read_UINT16_BE(s, length); + Stream_Read_UINT16_BE(s, len); + if (len < 4) + return FALSE; + + *length = len; } else { /* not a TPKT header */ - length = 0; + *length = 0; } - return length; + return TRUE; } /** diff --git a/libfreerdp/core/tpkt.h b/libfreerdp/core/tpkt.h index 55ce1dd18..9b18048e8 100644 --- a/libfreerdp/core/tpkt.h +++ b/libfreerdp/core/tpkt.h @@ -29,7 +29,7 @@ #define TPKT_HEADER_LENGTH 4 FREERDP_LOCAL BOOL tpkt_verify_header(wStream* s); -FREERDP_LOCAL UINT16 tpkt_read_header(wStream* s); +FREERDP_LOCAL BOOL tpkt_read_header(wStream* s, UINT16* length); FREERDP_LOCAL void tpkt_write_header(wStream* s, UINT16 length); #endif /* __TPKT_H */