Subject: Re: bug#27939: FreeRDP CVE-2017-2834 CVE-2017-2835 CVE-2017-2836 CVE-2017-2837 CVE-2017-2838 CVE-2017-2839

From: Thomas Danckaert <[email-masked]>
Date: Wed, 09 Aug 2017 19:05:19 +0200 (CEST)

From: Leo Famulari <[email-masked]>
Subject: Re: bug#27939: FreeRDP CVE-2017-2834 CVE-2017-2835 
CVE-2017-2836 CVE-2017-2837 CVE-2017-2838 CVE-2017-2839
Date: Fri, 4 Aug 2017 10:56:15 -0400

> On Fri, Aug 04, 2017 at 10:34:55AM +0200, Thomas Danckaert wrote:
>> Unfortunately, vinagre doesn't build against freerdp 2. I'll try 
>> to fix
>> that, or otherwise try to backport the patches to freerdp 1.x.
>
> I think it should not be too hard to backport the patches if that's 
> what
> we need to do, but I don't have the time this week.

I tried applying the patch for 
https://github.com/FreeRDP/FreeRDP/commit/03ab68318966c3a22935a02838daaea7b7fbe96c 
to [email-masked]+android9, fixed the conflicts, and came up 
with the attached patch.  I can confirm freerdp1.2beta with this 
patch compiles and runs, but cannot guarantee this fixes all those 
issues, because I'm totally unfamiliar with the code (and with rdp) 
... is this enough to create a freerdp-1.2 package?

The alternative is to downgrade to [email-masked], or to disable rdp 
from vinagre.  When I first submitted these packages, I ran into 
trouble trying to build [email-masked], but I don't remember exactly 
what the problem was :).

Thomas
diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c
index 91bc8a931..6c1a004dc 100644
--- a/libfreerdp/core/capabilities.c
+++ b/libfreerdp/core/capabilities.c
@@ -3464,12 +3464,12 @@ BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId)
 
 	if (rdp->settings->DisableEncryption)
 	{
-		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))
 			{
 				DEBUG_WARN( "rdp_decrypt failed\n");
 				return FALSE;
diff --git a/libfreerdp/core/certificate.c b/libfreerdp/core/certificate.c
index 8829c0cd9..ff825d4af 100644
--- a/libfreerdp/core/certificate.c
+++ b/libfreerdp/core/certificate.c
@@ -357,7 +357,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;
@@ -374,12 +373,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)
@@ -543,7 +541,7 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate
 
 BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, wStream* s)
 {
-	int i;
+	UINT32 i;
 	UINT32 certLength;
 	UINT32 numCertBlobs;
 	BOOL ret;
@@ -558,7 +556,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;
@@ -615,7 +613,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)
 {
 	wStream* s;
 	UINT32 dwVersion;
diff --git a/libfreerdp/core/certificate.h b/libfreerdp/core/certificate.h
index 2d726cf8a..1e5fbfe99 100644
--- a/libfreerdp/core/certificate.h
+++ b/libfreerdp/core/certificate.h
@@ -50,7 +50,7 @@ void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain);
 
 BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate, wStream* s);
 BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, wStream* s);
-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);
 
 rdpCertificate* certificate_new(void);
 void certificate_free(rdpCertificate* certificate);
diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c
index 52947636a..a79940b04 100644
--- a/libfreerdp/core/connection.c
+++ b/libfreerdp/core/connection.c
@@ -522,11 +522,8 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
 		return FALSE;
 	}
 
-	if (!rdp_read_security_header(s, &sec_flags))
-	{
-		DEBUG_WARN( "%s: invalid security header\n", __FUNCTION__);
+	if (!rdp_read_security_header(s, &sec_flags, NULL))
 		return FALSE;
-	}
 
 	if ((sec_flags & SEC_EXCHANGE_PKT) == 0)
 	{
@@ -770,7 +767,12 @@ BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream *s)
 		{
 			if (channelId == rdp->mcs->messageChannelId)
 			{
-				if (rdp_recv_message_channel_pdu(rdp, s) == 0)
+                          UINT16 securityFlags = 0;
+
+                          if (!rdp_read_security_header(s, &securityFlags, &length))
+					return FALSE;
+
+                          if (rdp_recv_message_channel_pdu(rdp, s, securityFlags) == 0)
 					return TRUE;
 			}
 		}
diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c
index ac75bc4ba..25b46e977 100644
--- a/libfreerdp/core/gcc.c
+++ b/libfreerdp/core/gcc.c
@@ -979,10 +979,10 @@ 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 */
@@ -991,22 +991,34 @@ BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs)
 		return FALSE;
 	Stream_Read(s, settings->ServerRandom, settings->ServerRandomLength);
 
-
 	/* serverCertificate */
+	if(Stream_GetRemainingLength(s) < settings->ServerCertificateLength)
+		goto out_fail1;
 	settings->ServerCertificate = (BYTE*) malloc(settings->ServerCertificateLength);
 	if (!settings->ServerCertificate)
-		return FALSE;
-	Stream_Read(s, settings->ServerCertificate, settings->ServerCertificateLength);
+		goto out_fail1;
 
+	Stream_Read(s, settings->ServerCertificate, settings->ServerCertificateLength);
 	certificate_free(settings->RdpServerCertificate);
 	settings->RdpServerCertificate = certificate_new();
 	if (!settings->RdpServerCertificate)
-		return FALSE;
+		goto out_fail2;
 
 	data = settings->ServerCertificate;
 	length = settings->ServerCertificateLength;
 
-	return certificate_read_server_certificate(settings->RdpServerCertificate, data, length);
+	if (certificate_read_server_certificate(settings->RdpServerCertificate, data, length) < 1)
+		goto out_fail2;
+
+	return TRUE;
+
+	out_fail2:
+		free(settings->ServerCertificate);
+		settings->ServerCertificate = NULL;
+	out_fail1:
+		free(settings->ServerRandom);
+		settings->ServerRandom = NULL;
+		return FALSE;
 }
 
 static const BYTE initial_signature[] =
diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c
index 217b3ff21..e48092729 100644
--- a/libfreerdp/core/info.c
+++ b/libfreerdp/core/info.c
@@ -582,7 +582,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)
@@ -598,7 +598,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))
 			{
 				DEBUG_WARN( "rdp_decrypt failed\n");
 				return FALSE;
diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c
index aa2c17f1d..d10ed72dc 100644
--- a/libfreerdp/core/license.c
+++ b/libfreerdp/core/license.c
@@ -232,12 +232,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))
 		{
 			DEBUG_WARN("%s: rdp_decrypt failed\n", __FUNCTION__);
 			return -1;
@@ -458,23 +458,41 @@ 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->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)
-	{
-		free(productInfo->pbCompanyName);
-		productInfo->pbCompanyName = NULL;
-		return FALSE;
-	}
+		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);
+		productInfo->pbCompanyName = NULL;
+		return FALSE;
+
 }
 
 /**
@@ -764,7 +782,10 @@ 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/mcs.c b/libfreerdp/core/mcs.c
index 326622116..fef3f3532 100644
--- a/libfreerdp/core/mcs.c
+++ b/libfreerdp/core/mcs.c
@@ -217,7 +217,8 @@ BOOL mcs_read_domain_mcspdu_header(wStream* s, enum DomainMCSPDU* domainMCSPDU,
 	BYTE choice;
 	enum DomainMCSPDU MCSPDU;
 
-	*length = tpkt_read_header(s);
+	if (!tpkt_read_header(s, length))
+		return FALSE;
 
 	if (!tpdu_read_data(s, &li))
 		return FALSE;
@@ -467,8 +468,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;
@@ -644,8 +650,13 @@ BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s)
 	BYTE result;
 	UINT16 li;
 	UINT32 calledConnectId;
+	UINT16 tlength;
 
-	tpkt_read_header(s);
+	if (!mcs || !s)
+		return FALSE;
+
+	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 d5c98ef29..5b675469a 100644
--- a/libfreerdp/core/nego.c
+++ b/libfreerdp/core/nego.c
@@ -537,9 +537,7 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra)
 	UINT16 length;
 	rdpNego* nego = (rdpNego*) extra;
 
-	length = tpkt_read_header(s);
-
-	if (length == 0)
+	if (!tpkt_read_header(s, &length) || length == 0)
 		return -1;
 
 	if (!tpdu_read_connection_confirm(s, &li))
@@ -613,8 +611,10 @@ BOOL nego_read_request(rdpNego* nego, wStream* s)
 	BYTE li;
 	BYTE c;
 	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 e2f3f48f2..449e01daa 100644
--- a/libfreerdp/core/peer.c
+++ b/libfreerdp/core/peer.c
@@ -189,12 +189,12 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s)
  
 	if (rdp->settings->DisableEncryption)
 	{
-		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))
 			{
 				DEBUG_WARN( "rdp_decrypt failed\n");
 				return -1;
diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c
index 5360d53d6..4113347b2 100644
--- a/libfreerdp/core/rdp.c
+++ b/libfreerdp/core/rdp.c
@@ -77,13 +77,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;
 }
 
@@ -284,7 +288,10 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId)
 			return FALSE;
 	}
 
-	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)
@@ -334,8 +341,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) */
@@ -362,7 +373,7 @@ void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channelId)
 
 	MCSPDU = (rdp->settings->ServerMode) ? DomainMCSPDU_SendDataIndication : DomainMCSPDU_SendDataRequest;
 
-	if ((rdp->sec_flags & SEC_ENCRYPT) && (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS))
+ 	if ((rdp->sec_flags & SEC_ENCRYPT) && (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS))
 	{
 		int pad;
 
@@ -840,13 +851,8 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s)
 	return 0;
 }
 
-int rdp_recv_message_channel_pdu(rdpRdp* rdp, wStream* s)
+int rdp_recv_message_channel_pdu(rdpRdp* rdp, wStream* s, UINT16 securityFlags)
 {
-	UINT16 securityFlags;
-
-	if (!rdp_read_security_header(s, &securityFlags))
-		return -1;
-
 	if (securityFlags & SEC_AUTODETECT_REQ)
 	{
 		/* Server Auto-Detect Request PDU */
@@ -898,16 +904,20 @@ int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s)
  * @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];
 
+	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;
@@ -920,6 +930,10 @@ 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))
 		{
@@ -937,11 +951,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;
@@ -994,12 +1010,12 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s)
  
 	if (rdp->settings->DisableEncryption)
 	{
-		if (!rdp_read_security_header(s, &securityFlags))
+		if (!rdp_read_security_header(s, &securityFlags, &length))
 			return -1;
 
 		if (securityFlags & (SEC_ENCRYPT | SEC_REDIRECTION_PKT))
 		{
-			if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
+			if (!rdp_decrypt(rdp, s, length, securityFlags))
 			{
 				DEBUG_WARN( "rdp_decrypt failed\n");
 				return -1;
@@ -1060,7 +1076,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s)
 	}
 	else if (rdp->mcs->messageChannelId && channelId == rdp->mcs->messageChannelId)
 	{
-		return rdp_recv_message_channel_pdu(rdp, s);
+          return rdp_recv_message_channel_pdu(rdp, s, securityFlags);
 	}
 	else
 	{
diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h
index f830e737b..9a2268d3f 100644
--- a/libfreerdp/core/rdp.h
+++ b/libfreerdp/core/rdp.h
@@ -170,7 +170,7 @@ struct rdp_rdp
 	rdpSettings* settingsCopy;
 };
 
-BOOL rdp_read_security_header(wStream* s, UINT16* flags);
+BOOL rdp_read_security_header(wStream* s, UINT16* flags, UINT16* length);
 void rdp_write_security_header(wStream* s, UINT16 flags);
 
 BOOL rdp_read_share_control_header(wStream* s, UINT16* length, UINT16* type, UINT16* channel_id);
@@ -200,7 +200,7 @@ int rdp_send_channel_data(rdpRdp* rdp, UINT16 channelId, BYTE* data, int size);
 
 wStream* rdp_message_channel_pdu_init(rdpRdp* rdp);
 BOOL rdp_send_message_channel_pdu(rdpRdp* rdp, wStream* s, UINT16 sec_flags);
-int rdp_recv_message_channel_pdu(rdpRdp* rdp, wStream* s);
+int rdp_recv_message_channel_pdu(rdpRdp* rdp, wStream* s, UINT16 sec_flags);
 
 int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s);
 
@@ -217,7 +217,7 @@ void rdp_free(rdpRdp* rdp);
 #define DEBUG_RDP(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
 #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);
 
diff --git a/libfreerdp/core/security.c b/libfreerdp/core/security.c
index 4bd8427c9..e99814d0a 100644
--- a/libfreerdp/core/security.c
+++ b/libfreerdp/core/security.c
@@ -564,7 +564,7 @@ BOOL security_key_update(BYTE* key, BYTE* update_key, int key_len, rdpRdp* rdp)
 	return TRUE;
 }
 
-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)
 	{
@@ -584,7 +584,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;
@@ -607,7 +607,7 @@ BOOL security_decrypt(BYTE* data, int length, rdpRdp* rdp)
 	return TRUE;
 }
 
-void security_hmac_signature(const BYTE* data, int length, BYTE* output, rdpRdp* rdp)
+void security_hmac_signature(const BYTE* data, size_t length, BYTE* output, rdpRdp* rdp)
 {
 	BYTE buf[20];
 	BYTE use_count_le[4];
@@ -622,20 +622,20 @@ void security_hmac_signature(const BYTE* data, int length, BYTE* output, rdpRdp*
 	memmove(output, buf, 8);
 }
 
-BOOL security_fips_encrypt(BYTE* data, int length, rdpRdp* rdp)
+BOOL security_fips_encrypt(BYTE* data, size_t length, rdpRdp* rdp)
 {
 	crypto_des3_encrypt(rdp->fips_encrypt, length, data, data);
 	rdp->encrypt_use_count++;
 	return TRUE;
 }
 
-BOOL security_fips_decrypt(BYTE* data, int length, rdpRdp* rdp)
+BOOL security_fips_decrypt(BYTE* data, size_t length, rdpRdp* rdp)
 {
 	crypto_des3_decrypt(rdp->fips_decrypt, length, data, data);
 	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[20];
 	BYTE use_count_le[4];
diff --git a/libfreerdp/core/security.h b/libfreerdp/core/security.h
index ffcebdfdd..c6b603866 100644
--- a/libfreerdp/core/security.h
+++ b/libfreerdp/core/security.h
@@ -37,12 +37,12 @@ void security_mac_signature(rdpRdp *rdp, const BYTE* data, UINT32 length, BYTE*
 void security_salted_mac_signature(rdpRdp *rdp, const BYTE* data, UINT32 length, BOOL encryption, BYTE* output);
 BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp);
 
-BOOL security_encrypt(BYTE* data, int length, rdpRdp* rdp);
-BOOL security_decrypt(BYTE* data, int length, rdpRdp* rdp);
+BOOL security_encrypt(BYTE* data, size_t length, rdpRdp* rdp);
+BOOL security_decrypt(BYTE* data, size_t length, rdpRdp* rdp);
 
-void security_hmac_signature(const BYTE* data, int length, BYTE* output, rdpRdp* rdp);
-BOOL security_fips_encrypt(BYTE* data, int length, rdpRdp* rdp);
-BOOL security_fips_decrypt(BYTE* data, int length, rdpRdp* rdp);
-BOOL security_fips_check_signature(const BYTE* data, int length, const BYTE* sig, rdpRdp* rdp);
+void security_hmac_signature(const BYTE* data, size_t length, BYTE* output, rdpRdp* rdp);
+BOOL security_fips_encrypt(BYTE* data, size_t length, rdpRdp* rdp);
+BOOL security_fips_decrypt(BYTE* data, size_t length, rdpRdp* rdp);
+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..900e288fd 100644
--- a/libfreerdp/core/tpkt.c
+++ b/libfreerdp/core/tpkt.c
@@ -81,25 +81,37 @@ BOOL tpkt_verify_header(wStream* s)
  * @return length
  */
 
-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 af984c11c..9b5174906 100644
--- a/libfreerdp/core/tpkt.h
+++ b/libfreerdp/core/tpkt.h
@@ -28,7 +28,7 @@
 #define TPKT_HEADER_LENGTH	4
 
 BOOL tpkt_verify_header(wStream* s);
-UINT16 tpkt_read_header(wStream* s);
+BOOL tpkt_read_header(wStream* s, UINT16* length);
 void tpkt_write_header(wStream* s, UINT16 length);
 
 #endif /* __TPKT_H */