Bug#916912: [pre-approval] stretch-pu: package freerdp/1.1.0~git20140921.1.440916e+dfsg1-13+deb9u3
Dear release team,
please review...
On Thu, 20 Dec 2018 13:06:05 +0100 Mike Gabriel
<mike.gabriel@das-netzwerkteam.de> wrote:
> Dear Debian stretch Release Team,
>
> in Debian LTS, we are currently discussing a complex update of the
> freerdp (v1.1) package. The current status is this:
>
> * since March 2018 freerdp in stretch (and jessie) (Git
> snapshot of never released v1.1) is unusable against
> latest Windows servers.
> All Windows OS versions switched to RDP proto version 6
> plus CredSSP version 3) and the freerdp versions in Debian
> jessie/stretch do not support that.
> * for people using Debian stretch, the only viable work-around
> is using freerdp2 from stretch-backports.
> * people using Debian jessie LTS don't have any options (except
> from upgrading to stretch and using freerdp2 from stretch-bpo).
> * currently, we know of four unfixed CVE issues in freerdp (v1.1)
> (that are fixed in buster's freerdp2.
>
> With my Debian LTS contributor hat on, I have started working on the open
> freerdp CVE issues (which luckily appeared in a Ubuntu security update,
> so not much work on this side) _and_ ...
>
> ... I have started backporting the required patches (at least these:
> [1,2,3]) to get RDP proto version 6 working in Debian jessie's freerdp
> v1.1 version.
>
> This complete endeavour for LTS only makes sense if the stable release
> team is open to accepting such a complex change to Debian stretch, too.
>
> While working on these patches, I regularly get feedback from FreeRDP
> upstream developer Bernhard Miklautz.
>
> The Git version [4] of the proposed upload is not yet ready. After
> feedback from Bernhard, I will have to backport various WinPR API calls
> that are used around the RDP proto v6 implementation. So this whole thing
> is still work in progress.
>
> The reason for this mail is: if the stable release team declines this
> update, then we neither will bring it to Debian jessie LTS.
>
> Please give me a beacon single (mainly a "yes, go ahead", or a "no, no
> way!").
>
> Please let me know, if you need more info to consider.
>
> Cheers,
> Mike
>
> [1]
https://salsa.debian.org/debian-remote-team/freerdp-1.1-legacy/blob/debian/stretch/updates/debian/patches/0010_add-support-for-credssp-version-3.patch
> [2]
https://salsa.debian.org/debian-remote-team/freerdp-1.1-legacy/blob/debian/stretch/updates/debian/patches/0011_add-support-for-proto-version-6.patch
> [3]
https://salsa.debian.org/debian-remote-team/freerdp-1.1-legacy/blob/debian/stretch/updates/debian/patches/0012-fix-nla-don-t-use-server-version.patch
> [4]
https://salsa.debian.org/debian-remote-team/freerdp-1.1-legacy/tree/debian/stretch/updates
Over the X-mas holidays, Bernhard Miklautz and Martin Fleisz from
FreeRDP upstream worked hard on getting FreeRDP v1.1 (jessie + stretch)
working again with latest Microsoft Windows RDP Servers. They used the
above referenced patches as a starting point and came up with a working
solution. Special credits, in fact, go to Bernhard Miklautz.
Please review the attached .debdiff (for stretch) and give your go for
uploading to stretch.
After that, I will upload the same version (slighty backported to
jessie) to jessie-security.
I will also publish a blog post that will appear on Planet Debian that
links to built binaries that users may be table to test.
Thanks+Greets,
Mike
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/changelog freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/changelog
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/changelog 2017-08-12 21:26:43.000000000 +0200
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/changelog 2019-01-10 16:07:19.000000000 +0100
@@ -1,3 +1,28 @@
+freerdp (1.1.0~git20140921.1.440916e+dfsg1-13+deb9u3) stretch; urgency=medium
+
+ * debian/patches: Add security patches.
+ - CVE-2018-8786.patch: The count variable in update_read_bitmap() needs to
+ be UINT32 (not UINT16).
+ - CVE-2018-8787.patch: In gdi_Bitmap_Decompress, check for invalid bpp,
+ width and height before decompressing.
+ CVE-2018-8788.patch: In NSC encode/decode functions, catch data flawed in
+ various ways and bail out with failure.
+ CVE-2018-8789.patch: In ntlm_read_message_fields_buffer, check buffer
+ offset vs. Stream_Length and bail out if not appropriate.
+ - Thanks to Alex Murray for backporting them to FreeRDP 1.1.
+ * debian/patches:
+ + Add 0010_add-support-for-credssp-v3-and-rdpproto-v6.patch. Add CredSSP v3
+ and RDP proto v6 support. This allows users to connect to recently
+ (since March 2018) update Microsoft RDP servers again.
+ Thanks to Bernhard Miklautz and Martin Fleisz for helping out with
+ backporting this patch. Much appreciated!
+ * debian/control:
+ + B-D on libssh1.0-dev (instead of libssh-dev).
+ + Update Vcs-*: URLs.
+ * debian/lib{freerdp-core1.1,winpr-sspi0.1}.symbols: Update symbols.
+
+ -- Mike Gabriel <sunweaver@debian.org> Thu, 10 Jan 2019 16:07:19 +0100
+
freerdp (1.1.0~git20140921.1.440916e+dfsg1-13+deb9u2) stretch; urgency=medium
[ Bernhard Miklautz ]
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/control freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/control
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/control 2017-08-12 21:26:43.000000000 +0200
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/control 2019-01-10 16:07:19.000000000 +0100
@@ -35,8 +35,8 @@
uuid-dev,
Standards-Version: 3.9.8
Homepage: http://www.freerdp.com/
-Vcs-Browser: https://anonscm.debian.org/git/pkg-remote/freerdp.git
-Vcs-Git: https://anonscm.debian.org/git/pkg-remote/freerdp.git
+Vcs-Browser: https://salsa.debian.org/debian-remote-team/freerdp-1.1-legacy
+Vcs-Git: https://salsa.debian.org/debian-remote-team/freerdp-1.1-legacy.git
Package: freerdp-x11
Architecture: any
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/libfreerdp-core1.1.symbols freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/libfreerdp-core1.1.symbols
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/libfreerdp-core1.1.symbols 2017-08-12 21:26:43.000000000 +0200
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/libfreerdp-core1.1.symbols 2019-01-10 16:07:19.000000000 +0100
@@ -120,9 +120,11 @@
credssp_buffer_print@Base 1.1.0~beta1+git20130629
credssp_client_authenticate@Base 1.1.0~beta1+git20130629
credssp_decrypt_public_key_echo@Base 1.1.0~beta1+git20130629
+ credssp_decrypt_public_key_hash@Base 1.1.0~git20140921.1.440916e+dfsg1-13+deb9u3
credssp_decrypt_ts_credentials@Base 1.1.0~beta1+git20130629
credssp_encode_ts_credentials@Base 1.1.0~beta1+git20130629
credssp_encrypt_public_key_echo@Base 1.1.0~beta1+git20130629
+ credssp_encrypt_public_key_hash@Base 1.1.0~git20140921.1.440916e+dfsg1-13+deb9u3
credssp_encrypt_ts_credentials@Base 1.1.0~beta1+git20130629
credssp_free@Base 1.1.0~beta1+git20130629
credssp_new@Base 1.1.0~beta1+git20130629
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/libwinpr-sspi0.1.symbols freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/libwinpr-sspi0.1.symbols
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/libwinpr-sspi0.1.symbols 2017-08-12 21:26:43.000000000 +0200
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/libwinpr-sspi0.1.symbols 2019-01-10 16:07:19.000000000 +0100
@@ -24,6 +24,7 @@
FreeContextBuffer_EnumerateSecurityPackages@Base 1.1.0~beta1+git20130629
FreeContextBuffer_QuerySecurityPackageInfo@Base 1.1.0~beta1+git20130629
FreeCredentialsHandle@Base 1.1.0~beta1+git20130629
+ GetSecurityStatusString@Base 1.1.0~git20140921.1.440916e+dfsg1-13+deb9u3
ImpersonateSecurityContext@Base 1.1.0~beta1+git20130629
ImportSecurityContextA@Base 1.1.0~beta1+git20130629
ImportSecurityContextW@Base 1.1.0~beta1+git20130629
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/0001_fix-cmdline-parser.patch freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/0001_fix-cmdline-parser.patch
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/0001_fix-cmdline-parser.patch 2017-08-12 21:26:43.000000000 +0200
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/0001_fix-cmdline-parser.patch 2019-01-10 16:07:19.000000000 +0100
@@ -1,7 +1,7 @@
Description: Command line parser fixes.
Author: Bernhard Miklautz <bernhard.miklautz@shacknet.at>
Abstract:
- The command line parser had serveral problems when old style syntax
+ The command line parser had several problems when old style syntax
was used.
diff --git a/client/common/cmdline.c b/client/common/cmdline.c
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/0010_add-support-for-credssp-v3-and-rdpproto-v6.patch freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/0010_add-support-for-credssp-v3-and-rdpproto-v6.patch
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/0010_add-support-for-credssp-v3-and-rdpproto-v6.patch 1970-01-01 01:00:00.000000000 +0100
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/0010_add-support-for-credssp-v3-and-rdpproto-v6.patch 2019-01-10 16:07:19.000000000 +0100
@@ -0,0 +1,1302 @@
+From d7bdbf482370e57a481c8412e4997b98ecbf3e36 Mon Sep 17 00:00:00 2001
+From: Bernhard Miklautz <bernhard.miklautz@thincast.com>
+Date: Mon, 7 Jan 2019 23:45:12 +0100
+Subject: [PATCH] FINAL
+
+CredSSP v3 and RDP proto v6 support backported to FreeRDP v1.1
+
+Backported-by:
+ Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+ Bernhard Miklautz <bernhard.miklautz@thincast.com>
+ Martin Fleisz <martin.fleisz@thincast.com>
+
+---
+ include/freerdp/crypto/crypto.h | 1 +
+ libfreerdp/core/CMakeLists.txt | 2 +-
+ libfreerdp/core/nla.c | 430 +++++++++++++++++++++++++++++++++++-----
+ libfreerdp/core/nla.h | 9 +
+ libfreerdp/crypto/ber.c | 13 ++
+ winpr/include/winpr/endian.h | 8 +-
+ winpr/include/winpr/nt.h | 43 ++++
+ winpr/include/winpr/sspi.h | 2 +
+ winpr/libwinpr/sspi/NTLM/ntlm.c | 12 +-
+ winpr/libwinpr/sspi/sspi.c | 288 ++++++++++++++++++++++++++-
+ 10 files changed, 740 insertions(+), 68 deletions(-)
+ create mode 100644 winpr/include/winpr/nt.h
+
+diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h
+index b939e20..596ff62 100644
+--- a/include/freerdp/crypto/crypto.h
++++ b/include/freerdp/crypto/crypto.h
+@@ -74,6 +74,7 @@ struct crypto_cert_struct
+ X509 * px509;
+ };
+
++#define CRYPTO_SHA256_DIGEST_LENGTH SHA256_DIGEST_LENGTH
+ #define CRYPTO_SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
+ typedef struct crypto_sha1_struct* CryptoSha1;
+
+diff --git a/libfreerdp/core/CMakeLists.txt b/libfreerdp/core/CMakeLists.txt
+index 9cf9ed8..a1049de 100644
+--- a/libfreerdp/core/CMakeLists.txt
++++ b/libfreerdp/core/CMakeLists.txt
+@@ -136,7 +136,7 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
+ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
+ MONOLITHIC ${MONOLITHIC_BUILD}
+ MODULE winpr
+- MODULES winpr-registry winpr-utils winpr-interlocked winpr-dsparse winpr-sspi winpr-rpc winpr-crt)
++ MODULES winpr-registry winpr-utils winpr-interlocked winpr-dsparse winpr-sspi winpr-rpc winpr-crt winpr-error)
+
+ if(MONOLITHIC_BUILD)
+ set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
+diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c
+index 875c0ae..46f5b6b 100644
+--- a/libfreerdp/core/nla.c
++++ b/libfreerdp/core/nla.c
+@@ -3,6 +3,7 @@
+ * Network Level Authentication (NLA)
+ *
+ * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
++ * Copyright 2016 Martin Fleisz <martin.fleisz@thincast.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+@@ -22,6 +23,7 @@
+ #endif
+
+ #include <time.h>
++#include <inttypes.h>
+
+ #ifndef _WIN32
+ #include <unistd.h>
+@@ -35,15 +37,29 @@
+ #include <winpr/tchar.h>
+ #include <winpr/library.h>
+ #include <winpr/registry.h>
++#include <winpr/nt.h>
++#include <winpr/error.h>
++#include <openssl/sha.h>
++#include <openssl/hmac.h>
++#include <openssl/rand.h>
++#include <openssl/engine.h>
+
+ #include "nla.h"
+
++
++#ifdef UNICODE
++#define _tcsncmp wcsncmp
++#else
++#define _tcsncmp strncmp
++#endif /* UNICODE */
++
+ /**
+ * TSRequest ::= SEQUENCE {
+ * version [0] INTEGER,
+ * negoTokens [1] NegoData OPTIONAL,
+ * authInfo [2] OCTET STRING OPTIONAL,
+- * pubKeyAuth [3] OCTET STRING OPTIONAL
++ * pubKeyAuth [3] OCTET STRING OPTIONAL,
++ * errorCode [4] INTEGER OPTIONAL
+ * }
+ *
+ * NegoData ::= SEQUENCE OF NegoDataItem
+@@ -80,10 +96,6 @@
+ *
+ */
+
+-#ifdef WITH_DEBUG_NLA
+-#define WITH_DEBUG_CREDSSP
+-#endif
+-
+ #ifdef WITH_NATIVE_SSPI
+ #define NLA_PKG_NAME NTLMSP_NAME
+ #else
+@@ -97,13 +109,36 @@ int credssp_recv(rdpCredssp* credssp);
+ void credssp_buffer_print(rdpCredssp* credssp);
+ void credssp_buffer_free(rdpCredssp* credssp);
+ SECURITY_STATUS credssp_encrypt_public_key_echo(rdpCredssp* credssp);
++SECURITY_STATUS credssp_encrypt_public_key_hash(rdpCredssp* credssp);
+ SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp);
++SECURITY_STATUS credssp_decrypt_public_key_hash(rdpCredssp* credssp);
+ SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp);
+ SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp);
+
+ #define ber_sizeof_sequence_octet_string(length) ber_sizeof_contextual_tag(ber_sizeof_octet_string(length)) + ber_sizeof_octet_string(length)
+ #define ber_write_sequence_octet_string(stream, context, value, length) ber_write_contextual_tag(stream, context, ber_sizeof_octet_string(length), TRUE) + ber_write_octet_string(stream, value, length)
+
++/* CredSSP Client-To-Server Binding Hash\0 */
++static const BYTE ClientServerHashMagic[] =
++{
++ 0x43, 0x72, 0x65, 0x64, 0x53, 0x53, 0x50, 0x20,
++ 0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x2D, 0x54,
++ 0x6F, 0x2D, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
++ 0x20, 0x42, 0x69, 0x6E, 0x64, 0x69, 0x6E, 0x67,
++ 0x20, 0x48, 0x61, 0x73, 0x68, 0x00
++};
++
++/* CredSSP Server-To-Client Binding Hash\0 */
++static const BYTE ServerClientHashMagic[] =
++{
++ 0x43, 0x72, 0x65, 0x64, 0x53, 0x53, 0x50, 0x20,
++ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2D, 0x54,
++ 0x6F, 0x2D, 0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74,
++ 0x20, 0x42, 0x69, 0x6E, 0x64, 0x69, 0x6E, 0x67,
++ 0x20, 0x48, 0x61, 0x73, 0x68, 0x00
++};
++static const UINT32 NonceLength = 32;
++
+ /**
+ * Initialize NTLMSSP authentication module (client).
+ * @param credssp
+@@ -132,7 +167,7 @@ int credssp_ntlm_client_init(rdpCredssp* credssp)
+
+ sspi_SetAuthIdentity(&(credssp->identity), settings->Username, settings->Domain, settings->Password);
+
+-#ifdef WITH_DEBUG_NLA
++#ifdef WITH_DEBUG_CREDSSP
+ _tprintf(_T("User: %s Domain: %s Password: %s\n"),
+ (char*) credssp->identity.User, (char*) credssp->identity.Domain, (char*) credssp->identity.Password);
+ #endif
+@@ -189,7 +224,6 @@ int credssp_client_authenticate(rdpCredssp* credssp)
+ SecBufferDesc output_buffer_desc;
+ BOOL have_context;
+ BOOL have_input_buffer;
+- BOOL have_pub_key_auth;
+
+ sspi_GlobalInit();
+
+@@ -224,6 +258,7 @@ int credssp_client_authenticate(rdpCredssp* credssp)
+ }
+
+ cbMaxToken = pPackageInfo->cbMaxToken;
++ credssp->packageName = pPackageInfo->Name;
+
+ status = credssp->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME,
+ SECPKG_CRED_OUTBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
+@@ -236,7 +271,6 @@ int credssp_client_authenticate(rdpCredssp* credssp)
+
+ have_context = FALSE;
+ have_input_buffer = FALSE;
+- have_pub_key_auth = FALSE;
+ ZeroMemory(&input_buffer, sizeof(SecBuffer));
+ ZeroMemory(&output_buffer, sizeof(SecBuffer));
+ ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
+@@ -272,12 +306,19 @@ int credssp_client_authenticate(rdpCredssp* credssp)
+ input_buffer.pvBuffer = NULL;
+ }
+
+- if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_E_OK))
++ if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
+ {
+ if (credssp->table->CompleteAuthToken != NULL)
+ credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
+
+- have_pub_key_auth = TRUE;
++ if (status == SEC_I_COMPLETE_NEEDED)
++ status = SEC_E_OK;
++ else if (status == SEC_I_COMPLETE_AND_CONTINUE)
++ status = SEC_I_CONTINUE_NEEDED;
++ }
++
++ if (status == SEC_E_OK)
++ {
+
+ if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
+ {
+@@ -285,12 +326,15 @@ int credssp_client_authenticate(rdpCredssp* credssp)
+ return 0;
+ }
+
+- credssp_encrypt_public_key_echo(credssp);
++ if (credssp->peerVersion < 5)
++ status = credssp_encrypt_public_key_echo(credssp);
++ else
++ {
++ status = credssp_encrypt_public_key_hash(credssp);
++ }
+
+- if (status == SEC_I_COMPLETE_NEEDED)
+- status = SEC_E_OK;
+- else if (status == SEC_I_COMPLETE_AND_CONTINUE)
+- status = SEC_I_CONTINUE_NEEDED;
++ if (status != SEC_E_OK)
++ return -1;
+ }
+
+ /* send authentication token to server */
+@@ -340,7 +384,11 @@ int credssp_client_authenticate(rdpCredssp* credssp)
+
+ /* Verify Server Public Key Echo */
+
+- status = credssp_decrypt_public_key_echo(credssp);
++ if (credssp->peerVersion < 5)
++ status = credssp_decrypt_public_key_echo(credssp);
++ else
++ status = credssp_decrypt_public_key_hash(credssp);
++
+ credssp_buffer_free(credssp);
+
+ if (status != SEC_E_OK)
+@@ -350,7 +398,6 @@ int credssp_client_authenticate(rdpCredssp* credssp)
+ }
+
+ /* Send encrypted credentials */
+-
+ status = credssp_encrypt_ts_credentials(credssp);
+
+ if (status != SEC_E_OK)
+@@ -391,7 +438,6 @@ int credssp_server_authenticate(rdpCredssp* credssp)
+ SecBufferDesc output_buffer_desc;
+ BOOL have_context;
+ BOOL have_input_buffer;
+- BOOL have_pub_key_auth;
+
+ sspi_GlobalInit();
+
+@@ -440,6 +486,7 @@ int credssp_server_authenticate(rdpCredssp* credssp)
+ }
+
+ cbMaxToken = pPackageInfo->cbMaxToken;
++ credssp->packageName = pPackageInfo->Name;
+
+ status = credssp->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME,
+ SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &credentials, &expiration);
+@@ -452,7 +499,6 @@ int credssp_server_authenticate(rdpCredssp* credssp)
+
+ have_context = FALSE;
+ have_input_buffer = FALSE;
+- have_pub_key_auth = FALSE;
+ ZeroMemory(&input_buffer, sizeof(SecBuffer));
+ ZeroMemory(&output_buffer, sizeof(SecBuffer));
+ ZeroMemory(&input_buffer_desc, sizeof(SecBufferDesc));
+@@ -537,7 +583,6 @@ int credssp_server_authenticate(rdpCredssp* credssp)
+
+ if (status == SEC_E_OK)
+ {
+- have_pub_key_auth = TRUE;
+
+ if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
+ {
+@@ -545,7 +590,12 @@ int credssp_server_authenticate(rdpCredssp* credssp)
+ return 0;
+ }
+
+- if (credssp_decrypt_public_key_echo(credssp) != SEC_E_OK)
++ if (credssp->version < 5)
++ status = credssp_decrypt_public_key_echo(credssp);
++ else
++ status = credssp_decrypt_public_key_hash(credssp);
++
++ if (status != SEC_E_OK)
+ {
+ fprintf(stderr, "Error: could not verify client's public key echo\n");
+ return -1;
+@@ -555,13 +605,39 @@ int credssp_server_authenticate(rdpCredssp* credssp)
+ credssp->negoToken.pvBuffer = NULL;
+ credssp->negoToken.cbBuffer = 0;
+
+- credssp_encrypt_public_key_echo(credssp);
++ if (credssp->version < 5)
++ status = credssp_encrypt_public_key_echo(credssp);
++ else
++ status = credssp_encrypt_public_key_hash(credssp);
++
++ if (status != SEC_E_OK)
++ return -1;
+ }
+
+ if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
+ {
++ /* Special handling of these specific error codes as HRESULT_FROM_WIN32
++ unfortunately does not map directly to the corresponding NTSTATUS values
++ */
++ switch (GetLastError())
++ {
++ case ERROR_PASSWORD_MUST_CHANGE:
++ credssp->errorCode = STATUS_PASSWORD_MUST_CHANGE;
++ break;
++ case ERROR_PASSWORD_EXPIRED:
++ credssp->errorCode = STATUS_PASSWORD_EXPIRED;
++ break;
++ case ERROR_ACCOUNT_DISABLED:
++ credssp->errorCode = STATUS_ACCOUNT_DISABLED;
++ break;
++ default:
++ credssp->errorCode = HRESULT_FROM_WIN32(GetLastError());
++ break;
++ }
++
+ fprintf(stderr, "AcceptSecurityContext status: 0x%08X\n", status);
+- return -1;
++ credssp_send(credssp);
++ return -1; /* Access Denied */
+ }
+
+ /* send authentication token */
+@@ -602,10 +678,6 @@ int credssp_server_authenticate(rdpCredssp* credssp)
+ if (status != SEC_E_OK)
+ {
+ fprintf(stderr, "ImpersonateSecurityContext status: 0x%08X\n", status);
+- return 0;
+- }
+- else
+- {
+ status = credssp->table->RevertSecurityContext(&credssp->context);
+
+ if (status != SEC_E_OK)
+@@ -714,6 +786,66 @@ SECURITY_STATUS credssp_encrypt_public_key_echo(rdpCredssp* credssp)
+ return status;
+ }
+
++SECURITY_STATUS credssp_encrypt_public_key_hash(rdpCredssp* credssp)
++{
++ SecBuffer Buffers[2] = { { 0 } };
++ SecBufferDesc Message;
++ SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
++ EVP_MD_CTX* sha256 = NULL;
++ const EVP_MD* md = NULL;
++ const ULONG auth_data_length = (credssp->ContextSizes.cbSecurityTrailer + CRYPTO_SHA256_DIGEST_LENGTH);
++ const BYTE* hashMagic = credssp->server ? ServerClientHashMagic : ClientServerHashMagic;
++ const size_t hashSize = credssp->server ? sizeof(ServerClientHashMagic) : sizeof(ClientServerHashMagic);
++
++ sha256 = EVP_MD_CTX_create();
++ if (!sha256)
++ return status;
++ md = EVP_get_digestbyname("sha256");
++ if (!md)
++ goto out;
++
++ sspi_SecBufferAlloc(&credssp->pubKeyAuth, auth_data_length);
++ if (!credssp->pubKeyAuth.pvBuffer)
++ goto out;
++ if (!EVP_DigestInit_ex(sha256, md, NULL))
++ goto out;
++ /* generate SHA256 of following data: ClientServerHashMagic, Nonce, SubjectPublicKey */
++ if (!EVP_DigestUpdate(sha256, hashMagic, hashSize) ||
++ !EVP_DigestUpdate(sha256, credssp->ClientNonce.pvBuffer, credssp->ClientNonce.cbBuffer) ||
++ !EVP_DigestUpdate(sha256, credssp->PublicKey.pvBuffer, credssp->PublicKey.cbBuffer))
++ goto out;
++
++ Message.cBuffers = 2;
++ Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
++ Buffers[0].cbBuffer = credssp->ContextSizes.cbSecurityTrailer;
++ Buffers[0].pvBuffer = credssp->pubKeyAuth.pvBuffer;
++ Buffers[1].BufferType = SECBUFFER_DATA; /* SHA256 hash */
++ Buffers[1].cbBuffer = CRYPTO_SHA256_DIGEST_LENGTH;
++ Buffers[1].pvBuffer = ((BYTE *) credssp->pubKeyAuth.pvBuffer) + credssp->ContextSizes.cbSecurityTrailer;
++ if (!EVP_DigestFinal(sha256, Buffers[1].pvBuffer, NULL))
++ goto out;
++
++ /* encrypt message */
++ Message.pBuffers = (PSecBuffer) &Buffers;
++ Message.ulVersion = SECBUFFER_VERSION;
++ status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, credssp->send_seq_num++);
++ if (status != SEC_E_OK)
++ {
++ fprintf(stderr, "EncryptMessage status %s [0x%08"PRIX32"]\n",
++ GetSecurityStatusString(status), status);
++ }
++ if (Message.cBuffers == 2 && Buffers[0].cbBuffer < credssp->ContextSizes.cbSecurityTrailer)
++ {
++ /* IMPORTANT: EncryptMessage may not use all the signature space, so we need to shrink the excess between the buffers */
++ MoveMemory(((BYTE*)Buffers[0].pvBuffer) + Buffers[0].cbBuffer, Buffers[1].pvBuffer,
++ Buffers[1].cbBuffer);
++ credssp->pubKeyAuth.cbBuffer = Buffers[0].cbBuffer + Buffers[1].cbBuffer;
++ }
++out:
++ EVP_MD_CTX_destroy(sha256);
++ return status;
++}
++
+ SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp)
+ {
+ int length;
+@@ -728,7 +860,7 @@ SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp)
+
+ if (credssp->PublicKey.cbBuffer + credssp->ContextSizes.cbMaxSignature != credssp->pubKeyAuth.cbBuffer)
+ {
+- fprintf(stderr, "unexpected pubKeyAuth buffer size:%d\n", (int) credssp->pubKeyAuth.cbBuffer);
++ fprintf(stderr, "unexpected pubKeyAuth buffer size :%lu\n", credssp->pubKeyAuth.cbBuffer);
+ return SEC_E_INVALID_TOKEN;
+ }
+
+@@ -786,6 +918,95 @@ SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp)
+ return SEC_E_OK;
+ }
+
++SECURITY_STATUS credssp_decrypt_public_key_hash(rdpCredssp* credssp)
++{
++ unsigned long length;
++ BYTE* buffer = NULL;
++ ULONG pfQOP = 0;
++ int signature_length;
++ SecBuffer Buffers[2] = { { 0 } };
++ SecBufferDesc Message;
++ EVP_MD_CTX* sha256 = NULL;
++ const EVP_MD* md = NULL;
++ BYTE serverClientHash[CRYPTO_SHA256_DIGEST_LENGTH];
++ SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
++ const BYTE* hashMagic = credssp->server ? ClientServerHashMagic : ServerClientHashMagic;
++ const size_t hashSize = credssp->server ? sizeof(ServerClientHashMagic) : sizeof(ClientServerHashMagic);
++
++ signature_length = credssp->pubKeyAuth.cbBuffer - CRYPTO_SHA256_DIGEST_LENGTH;
++ if ((signature_length < 0) || (signature_length > (int)credssp->ContextSizes.cbSecurityTrailer))
++ {
++ fprintf(stderr, "unexpected pubKeyAuth buffer size: %lu\n", credssp->pubKeyAuth.cbBuffer);
++ goto fail;
++ }
++ if ((credssp->ContextSizes.cbSecurityTrailer + CRYPTO_SHA256_DIGEST_LENGTH) != credssp->pubKeyAuth.cbBuffer)
++ {
++ fprintf(stderr, "unexpected pubKeyAuth buffer size: %lu\n", credssp->pubKeyAuth.cbBuffer);
++ goto fail;
++ }
++ length = credssp->pubKeyAuth.cbBuffer;
++ buffer = (BYTE*)malloc(length);
++ if (!buffer)
++ {
++ status = SEC_E_INSUFFICIENT_MEMORY;
++ goto fail;
++ }
++ sha256 = EVP_MD_CTX_create();
++ if (!sha256)
++ {
++ status = SEC_E_INSUFFICIENT_MEMORY;
++ goto fail;
++ }
++
++ md = EVP_get_digestbyname("sha256");
++ if (!md)
++ {
++ status = SEC_E_INTERNAL_ERROR;
++ goto fail;
++ }
++
++ CopyMemory(buffer, credssp->pubKeyAuth.pvBuffer, length);
++ Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
++ Buffers[0].cbBuffer = signature_length;
++ Buffers[0].pvBuffer = buffer;
++ Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted Hash */
++ Buffers[1].cbBuffer = CRYPTO_SHA256_DIGEST_LENGTH;
++ Buffers[1].pvBuffer = buffer + signature_length;
++ Message.cBuffers = 2;
++ Message.ulVersion = SECBUFFER_VERSION;
++ Message.pBuffers = (PSecBuffer)&Buffers;
++
++ status = credssp->table->DecryptMessage(&credssp->context, &Message, credssp->recv_seq_num++, &pfQOP);
++ if (status != SEC_E_OK)
++ {
++ fprintf(stderr, "DecryptMessage failure %s [%08"PRIX32"]\n",
++ GetSecurityStatusString(status), status);
++ goto fail;
++ }
++ /* generate SHA256 of following data: ServerClientHashMagic, Nonce, SubjectPublicKey */
++ if (!EVP_DigestInit_ex(sha256, md, NULL) ||
++ !EVP_DigestUpdate(sha256, hashMagic, hashSize) ||
++ !EVP_DigestUpdate(sha256, credssp->ClientNonce.pvBuffer, credssp->ClientNonce.cbBuffer) ||
++ !EVP_DigestUpdate(sha256, credssp->PublicKey.pvBuffer, credssp->PublicKey.cbBuffer) ||
++ !EVP_DigestFinal(sha256, serverClientHash, NULL)
++ )
++ {
++ status = SEC_E_INTERNAL_ERROR;
++ goto fail;
++ }
++ /* verify hash */
++ if (memcmp(serverClientHash, Buffers[1].pvBuffer, CRYPTO_SHA256_DIGEST_LENGTH) != 0)
++ {
++ fprintf(stderr, "Could not verify server's hash\n");
++ status = SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */
++ goto fail;
++ }
++fail:
++ free(buffer);
++ EVP_MD_CTX_destroy(sha256);
++ return status;
++}
++
+ int credssp_sizeof_ts_password_creds(rdpCredssp* credssp)
+ {
+ int length = 0;
+@@ -941,19 +1162,18 @@ SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp)
+
+ credssp_encode_ts_credentials(credssp);
+
+- Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
+- Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
+
+- sspi_SecBufferAlloc(&credssp->authInfo, credssp->ContextSizes.cbMaxSignature + credssp->ts_credentials.cbBuffer);
++ sspi_SecBufferAlloc(&credssp->authInfo, credssp->ContextSizes.cbSecurityTrailer + credssp->ts_credentials.cbBuffer);
+
+- Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
++ Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
++ Buffers[0].cbBuffer = credssp->ContextSizes.cbSecurityTrailer;
+ Buffers[0].pvBuffer = credssp->authInfo.pvBuffer;
+ ZeroMemory(Buffers[0].pvBuffer, Buffers[0].cbBuffer);
+
++ Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
+ Buffers[1].cbBuffer = credssp->ts_credentials.cbBuffer;
+ Buffers[1].pvBuffer = &((BYTE*) credssp->authInfo.pvBuffer)[Buffers[0].cbBuffer];
+ CopyMemory(Buffers[1].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[1].cbBuffer);
+-
+ Message.cBuffers = 2;
+ Message.ulVersion = SECBUFFER_VERSION;
+ Message.pBuffers = (PSecBuffer) &Buffers;
+@@ -1040,6 +1260,13 @@ int credssp_sizeof_auth_info(int length)
+ return length;
+ }
+
++static size_t credssp_sizeof_client_nonce(size_t length)
++{
++ length = ber_sizeof_octet_string(length);
++ length += ber_sizeof_contextual_tag(length);
++ return length;
++}
++
+ int credssp_sizeof_ts_request(int length)
+ {
+ length += ber_sizeof_integer(2);
+@@ -1057,15 +1284,23 @@ void credssp_send(rdpCredssp* credssp)
+ wStream* s;
+ int length;
+ int ts_request_length;
+- int nego_tokens_length;
+- int pub_key_auth_length;
+- int auth_info_length;
+-
++ int nego_tokens_length = 0;
++ int pub_key_auth_length = 0;
++ int auth_info_length = 0;
++ int error_code_context_length = 0;
++ int error_code_length = 0;
++ int client_nonce_length = 0;
+ nego_tokens_length = (credssp->negoToken.cbBuffer > 0) ? credssp_sizeof_nego_tokens(credssp->negoToken.cbBuffer) : 0;
+ pub_key_auth_length = (credssp->pubKeyAuth.cbBuffer > 0) ? credssp_sizeof_pub_key_auth(credssp->pubKeyAuth.cbBuffer) : 0;
+ auth_info_length = (credssp->authInfo.cbBuffer > 0) ? credssp_sizeof_auth_info(credssp->authInfo.cbBuffer) : 0;
++ client_nonce_length = (credssp->ClientNonce.cbBuffer > 0) ? credssp_sizeof_client_nonce(credssp->ClientNonce.cbBuffer) : 0;
+
+- length = nego_tokens_length + pub_key_auth_length + auth_info_length;
++ if (credssp->peerVersion >= 3 && credssp->peerVersion != 5 && credssp->errorCode != 0)
++ {
++ error_code_length = ber_sizeof_integer(credssp->errorCode);
++ error_code_context_length = ber_sizeof_contextual_tag(error_code_length);
++ }
++ length = nego_tokens_length + pub_key_auth_length + auth_info_length + error_code_context_length + error_code_length + client_nonce_length;
+
+ ts_request_length = credssp_sizeof_ts_request(length);
+
+@@ -1076,17 +1311,21 @@ void credssp_send(rdpCredssp* credssp)
+
+ /* [0] version */
+ ber_write_contextual_tag(s, 0, 3, TRUE);
+- ber_write_integer(s, 2); /* INTEGER */
++ ber_write_integer(s, credssp->version); /* INTEGER */
+
+ /* [1] negoTokens (NegoData) */
+ if (nego_tokens_length > 0)
+ {
+- length = nego_tokens_length;
+
+- length -= ber_write_contextual_tag(s, 1, ber_sizeof_sequence(ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))), TRUE); /* NegoData */
+- length -= ber_write_sequence_tag(s, ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))); /* SEQUENCE OF NegoDataItem */
+- length -= ber_write_sequence_tag(s, ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer)); /* NegoDataItem */
+- length -= ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); /* OCTET STRING */
++ length = ber_write_contextual_tag(s, 1, ber_sizeof_sequence(ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))), TRUE); /* NegoData */
++ length += ber_write_sequence_tag(s, ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))); /* SEQUENCE OF NegoDataItem */
++ length += ber_write_sequence_tag(s, ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer)); /* NegoDataItem */
++ length += ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); /* OCTET STRING */
++ if (length != nego_tokens_length)
++ {
++ Stream_Free(s, TRUE);
++ return;
++ }
+
+ // assert length == 0
+ }
+@@ -1094,19 +1333,40 @@ void credssp_send(rdpCredssp* credssp)
+ /* [2] authInfo (OCTET STRING) */
+ if (auth_info_length > 0)
+ {
+- length = auth_info_length;
+- length -= ber_write_sequence_octet_string(s, 2, credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
+-
+- // assert length == 0
++ if (ber_write_sequence_octet_string(s, 2, credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer) != auth_info_length)
++ {
++ Stream_Free(s, TRUE);
++ return;
++ }
+ }
+
+ /* [3] pubKeyAuth (OCTET STRING) */
+ if (pub_key_auth_length > 0)
+ {
+- length = pub_key_auth_length;
+- length -= ber_write_sequence_octet_string(s, 3, credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer);
++ if (ber_write_sequence_octet_string(s, 3, credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer) != pub_key_auth_length)
++ {
++ Stream_Free(s, TRUE);
++ return;
++ }
+
+- // assert length == 0
++ }
++
++ /* [4] errorCode (INTEGER) */
++ if (error_code_length > 0)
++ {
++ ber_write_contextual_tag(s, 4, error_code_length, TRUE);
++ ber_write_integer(s, credssp->errorCode);
++ }
++
++ /* [5] clientNonce (OCTET STRING) */
++ if (client_nonce_length > 0)
++ {
++ if (ber_write_sequence_octet_string(s, 5, credssp->ClientNonce.pvBuffer,
++ credssp->ClientNonce.cbBuffer) != client_nonce_length)
++ {
++ Stream_Free(s, TRUE);
++ return;
++ }
+ }
+
+ Stream_SealLength(s);
+@@ -1145,7 +1405,26 @@ int credssp_recv(rdpCredssp* credssp)
+ if(!ber_read_sequence_tag(s, &length) ||
+ !ber_read_contextual_tag(s, 0, &length, TRUE) ||
+ !ber_read_integer(s, &version))
++ {
++ Stream_Free(s, TRUE);
++ return -1;
++ }
++ if (credssp->peerVersion == 0)
++ {
++#ifdef WITH_DEBUG_CREDSSP
++ fprintf(stderr, "CredSSP protocol support %"PRIu32", peer supports %"PRIu32"\n",
++ credssp->version, version);
++#endif
++ credssp->peerVersion = version;
++ }
++
++ /* if the peer suddenly changed its version - kick it */
++ if (credssp->peerVersion != version)
++ {
++ fprintf(stderr, "CredSSP peer changed protocol version from %"PRIu32" to %"PRIu32"\n",
++ credssp->peerVersion, version);
+ return -1;
++ }
+
+ /* [1] negoTokens (NegoData) */
+ if (ber_read_contextual_tag(s, 1, &length, TRUE) != FALSE)
+@@ -1155,7 +1434,10 @@ int credssp_recv(rdpCredssp* credssp)
+ !ber_read_contextual_tag(s, 0, &length, TRUE) || /* [0] negoToken */
+ !ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
+ Stream_GetRemainingLength(s) < length)
++ {
++ Stream_Free(s, TRUE);
+ return -1;
++ }
+ sspi_SecBufferAlloc(&credssp->negoToken, length);
+ Stream_Read(s, credssp->negoToken.pvBuffer, length);
+ credssp->negoToken.cbBuffer = length;
+@@ -1166,7 +1448,10 @@ int credssp_recv(rdpCredssp* credssp)
+ {
+ if(!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
+ Stream_GetRemainingLength(s) < length)
++ {
++ Stream_Free(s, TRUE);
+ return -1;
++ }
+ sspi_SecBufferAlloc(&credssp->authInfo, length);
+ Stream_Read(s, credssp->authInfo.pvBuffer, length);
+ credssp->authInfo.cbBuffer = length;
+@@ -1177,12 +1462,46 @@ int credssp_recv(rdpCredssp* credssp)
+ {
+ if(!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
+ Stream_GetRemainingLength(s) < length)
++ {
++ Stream_Free(s, TRUE);
+ return -1;
++ }
+ sspi_SecBufferAlloc(&credssp->pubKeyAuth, length);
+ Stream_Read(s, credssp->pubKeyAuth.pvBuffer, length);
+ credssp->pubKeyAuth.cbBuffer = length;
+ }
+
++ /* [4] errorCode (INTEGER) */
++ if (credssp->peerVersion >= 3)
++ {
++ if (ber_read_contextual_tag(s, 4, &length, TRUE) != FALSE)
++ {
++ if (!ber_read_integer(s, &credssp->errorCode))
++ {
++ Stream_Free(s, TRUE);
++ return -1;
++ }
++ }
++ }
++
++ if (credssp->peerVersion >= 5)
++ {
++ if (ber_read_contextual_tag(s, 5, &length, TRUE) != FALSE)
++ {
++ if (!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
++ Stream_GetRemainingLength(s) < length)
++ {
++ Stream_Free(s, TRUE);
++ return -1;
++ }
++
++ sspi_SecBufferAlloc(&credssp->ClientNonce, length);
++
++ Stream_Read(s, credssp->ClientNonce.pvBuffer, length);
++ credssp->ClientNonce.cbBuffer = length;
++ }
++ }
++
+ Stream_Free(s, TRUE);
+
+ return 0;
+@@ -1242,11 +1561,19 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings*
+ credssp->transport = transport;
+ credssp->send_seq_num = 0;
+ credssp->recv_seq_num = 0;
++ credssp->version = 6;
++
++ ZeroMemory(&credssp->ClientNonce, sizeof(SecBuffer));
+ ZeroMemory(&credssp->negoToken, sizeof(SecBuffer));
+ ZeroMemory(&credssp->pubKeyAuth, sizeof(SecBuffer));
+ ZeroMemory(&credssp->authInfo, sizeof(SecBuffer));
+ SecInvalidateHandle(&credssp->context);
+
++ sspi_SecBufferAlloc(&credssp->ClientNonce, NonceLength);
++
++ /* generate random 32-byte nonce */
++ RAND_bytes(credssp->ClientNonce.pvBuffer, NonceLength);
++
+ if (credssp->server)
+ {
+ status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"),
+@@ -1288,6 +1615,7 @@ void credssp_free(rdpCredssp* credssp)
+ if (credssp->table)
+ credssp->table->DeleteSecurityContext(&credssp->context);
+
++ sspi_SecBufferFree(&credssp->ClientNonce);
+ sspi_SecBufferFree(&credssp->PublicKey);
+ sspi_SecBufferFree(&credssp->ts_credentials);
+
+diff --git a/libfreerdp/core/nla.h b/libfreerdp/core/nla.h
+index 5a4baa2..fd61fec 100644
+--- a/libfreerdp/core/nla.h
++++ b/libfreerdp/core/nla.h
+@@ -45,9 +45,12 @@ struct rdp_credssp
+ LPTSTR SspiModule;
+ rdpSettings* settings;
+ rdpTransport* transport;
++ UINT32 version;
++ UINT32 errorCode;
+ SecBuffer negoToken;
+ SecBuffer pubKeyAuth;
+ SecBuffer authInfo;
++ SecBuffer ClientNonce;
+ SecBuffer PublicKey;
+ SecBuffer ts_credentials;
+ CryptoRc4 rc4_seal_state;
+@@ -55,6 +58,12 @@ struct rdp_credssp
+ SEC_WINNT_AUTH_IDENTITY identity;
+ PSecurityFunctionTable table;
+ SecPkgContext_Sizes ContextSizes;
++#if defined(UNICODE)
++ SEC_WCHAR* packageName;
++#else
++ SEC_CHAR* packageName;
++#endif
++ UINT32 peerVersion;
+ };
+
+ int credssp_authenticate(rdpCredssp* credssp);
+diff --git a/libfreerdp/crypto/ber.c b/libfreerdp/crypto/ber.c
+index 38d98f4..1ace4bf 100644
+--- a/libfreerdp/crypto/ber.c
++++ b/libfreerdp/crypto/ber.c
+@@ -448,6 +448,14 @@ int ber_write_integer(wStream* s, UINT32 value)
+ Stream_Write_UINT32_BE(s, value);
+ return 6;
+ }
++ else
++ {
++ /* treat as signed integer i.e. NT/HRESULT error codes */
++ ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
++ ber_write_length(s, 4);
++ Stream_Write_UINT32_BE(s, value);
++ return 6;
++ }
+
+ return 0;
+ }
+@@ -470,6 +478,11 @@ int ber_sizeof_integer(UINT32 value)
+ {
+ return 6;
+ }
++ else
++ {
++ /* treat as signed integer i.e. NT/HRESULT error codes */
++ return 6;
++ }
+
+ return 0;
+ }
+diff --git a/winpr/include/winpr/endian.h b/winpr/include/winpr/endian.h
+index 9d98340..3ae1de9 100644
+--- a/winpr/include/winpr/endian.h
++++ b/winpr/include/winpr/endian.h
+@@ -101,10 +101,10 @@ extern "C" {
+ *((UINT32*) _d) = _v; } while (0)
+
+ #define Data_Write_UINT32(_d, _v) do { \
+- *(_d) = (_v) & 0xFF; \
+- *(_d + 1) = ((_v) >> 8) & 0xFF; \
+- *(_d + 2) = ((_v) >> 16) & 0xFF; \
+- *(_d + 3) = ((_v) >> 24) & 0xFF; \
++ *((BYTE *) _d) = (_v) & 0xFF; \
++ *((BYTE *) _d + 1) = ((_v) >> 8) & 0xFF; \
++ *((BYTE *) _d + 2) = ((_v) >> 16) & 0xFF; \
++ *((BYTE *) _d + 3) = ((_v) >> 24) & 0xFF; \
+ } while (0)
+
+ #define Data_Write_UINT32_BE(_d, _v) do { \
+diff --git a/winpr/include/winpr/nt.h b/winpr/include/winpr/nt.h
+new file mode 100644
+index 0000000..4875aff
+--- /dev/null
++++ b/winpr/include/winpr/nt.h
+@@ -0,0 +1,43 @@
++
++/**
++ * WinPR: Windows Portable Runtime
++ * Windows Native System Services
++ *
++ * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef WINPR_NT_H
++#define WINPR_NT_H
++#ifndef _WIN32
++
++/* Defined in winnt.h, do not redefine */
++
++
++
++#define STATUS_LOGON_FAILURE ((NTSTATUS)0xC000006DL)
++#define STATUS_WRONG_PASSWORD ((NTSTATUS)0xC000006AL)
++#define STATUS_PASSWORD_EXPIRED ((NTSTATUS)0xC0000071L)
++#define STATUS_PASSWORD_MUST_CHANGE ((NTSTATUS)0xC0000224L)
++#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
++#define STATUS_DOWNGRADE_DETECTED ((NTSTATUS)0xC0000388L)
++#define STATUS_AUTHENTICATION_FIREWALL_FAILED ((NTSTATUS)0xC0000413L)
++#define STATUS_ACCOUNT_DISABLED ((NTSTATUS)0xC0000072L)
++#define STATUS_ACCOUNT_RESTRICTION ((NTSTATUS)0xC000006EL)
++#define STATUS_ACCOUNT_LOCKED_OUT ((NTSTATUS)0xC0000234L)
++#define STATUS_ACCOUNT_EXPIRED ((NTSTATUS)0xC0000193L)
++#define STATUS_LOGON_TYPE_NOT_GRANTED ((NTSTATUS)0xC000015BL)
++#endif
++
++#endif /* WINPR_NT_H */
+diff --git a/winpr/include/winpr/sspi.h b/winpr/include/winpr/sspi.h
+index 3f2d21b..1fe5a4a 100644
+--- a/winpr/include/winpr/sspi.h
++++ b/winpr/include/winpr/sspi.h
+@@ -103,6 +103,7 @@ typedef SecPkgInfoW* PSecPkgInfoW;
+
+ #define NTLMSP_NAME _T("NTLM")
+ #define NEGOSSP_NAME _T("Negotiate")
++#define KERBEROS_SSP_NAME _T("Kerberos")
+
+ #endif
+
+@@ -1015,6 +1016,7 @@ WINPR_API void sspi_SecBufferFree(PSecBuffer SecBuffer);
+
+ WINPR_API void sspi_SetAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, char* user, char* domain, char* password);
+ WINPR_API void sspi_CopyAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, SEC_WINNT_AUTH_IDENTITY* srcIdentity);
++WINPR_API const char* GetSecurityStatusString(SECURITY_STATUS status);
+
+ #ifdef __cplusplus
+ }
+diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c
+index d2137a8..2ad2acd 100644
+--- a/winpr/libwinpr/sspi/NTLM/ntlm.c
++++ b/winpr/libwinpr/sspi/NTLM/ntlm.c
+@@ -33,6 +33,7 @@
+ #include <winpr/print.h>
+ #include <winpr/sysinfo.h>
+ #include <winpr/registry.h>
++#include <winpr/endian.h>
+
+ #include "ntlm.h"
+ #include "../sspi.h"
+@@ -622,6 +623,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
+ int index;
+ int length;
+ void* data;
++ UINT32 value;
+ UINT32 SeqNo;
+ HMAC_CTX hmac;
+ BYTE digest[16];
+@@ -657,7 +659,9 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
+ /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
+ HMAC_CTX_init(&hmac);
+ HMAC_Init_ex(&hmac, context->SendSigningKey, 16, EVP_md5(), NULL);
+- HMAC_Update(&hmac, (void*) &(SeqNo), 4);
++
++ Data_Write_UINT32(&value, SeqNo);
++ HMAC_Update(&hmac, (void*) &value, 4);
+ HMAC_Update(&hmac, data, length);
+ HMAC_Final(&hmac, digest, NULL);
+ HMAC_CTX_cleanup(&hmac);
+@@ -687,11 +691,11 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
+ signature = (BYTE*) signature_buffer->pvBuffer;
+
+ /* Concatenate version, ciphertext and sequence number to build signature */
+- CopyMemory(signature, (void*) &version, 4);
++
++ Data_Write_UINT32(signature, version);
+ CopyMemory(&signature[4], (void*) checksum, 8);
+- CopyMemory(&signature[12], (void*) &(SeqNo), 4);
++ Data_Write_UINT32(&signature[12], SeqNo);
+ context->SendSeqNum++;
+-
+ #ifdef WITH_DEBUG_NTLM
+ fprintf(stderr, "Signature (length = %d)\n", (int) signature_buffer->cbBuffer);
+ winpr_HexDump(signature_buffer->pvBuffer, signature_buffer->cbBuffer);
+diff --git a/winpr/libwinpr/sspi/sspi.c b/winpr/libwinpr/sspi/sspi.c
+index 96c9599..bd46dc9 100644
+--- a/winpr/libwinpr/sspi/sspi.c
++++ b/winpr/libwinpr/sspi/sspi.c
+@@ -294,21 +294,30 @@ void sspi_SecureHandleFree(SecHandle* handle)
+
+ void sspi_SetAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, char* user, char* domain, char* password)
+ {
++ int status;
+ identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
++ free(identity->User);
++ identity->User = (UINT16*) NULL;
++ identity->UserLength = 0;
+
+ if (user)
+ {
+- identity->UserLength = ConvertToUnicode(CP_UTF8, 0, user, -1, &identity->User, 0) - 1;
+- }
+- else
+- {
+- identity->User = (UINT16*) NULL;
+- identity->UserLength = 0;
++ status = ConvertToUnicode(CP_UTF8, 0, user, -1, (LPWSTR*) & (identity->User), 0);
++
++ if (status <= 0)
++ return;
++
++ identity->UserLength = (ULONG)(status - 1);
+ }
+
+ if (domain)
+ {
+- identity->DomainLength = ConvertToUnicode(CP_UTF8, 0, domain, -1, &identity->Domain, 0) - 1;
++ status = ConvertToUnicode(CP_UTF8, 0, domain, -1, (LPWSTR*) & (identity->Domain), 0);
++
++ if (status <= 0)
++ return;
++
++ identity->DomainLength = (ULONG)(status - 1);
+ }
+ else
+ {
+@@ -318,7 +327,10 @@ void sspi_SetAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, char* user, char* d
+
+ if (password != NULL)
+ {
+- identity->PasswordLength = ConvertToUnicode(CP_UTF8, 0, password, -1, &identity->Password, 0) - 1;
++ status = ConvertToUnicode(CP_UTF8, 0, password, -1, (LPWSTR*) & (identity->Password), 0);
++
++ identity->PasswordLength = (ULONG)(status - 1);
++
+ }
+ else
+ {
+@@ -1159,4 +1171,264 @@ SecurityFunctionTableW SSPI_SecurityFunctionTableW =
+ SetContextAttributes, /* SetContextAttributes */
+ };
+
++const char* GetSecurityStatusString(SECURITY_STATUS status)
++{
++ switch (status)
++ {
++ case SEC_E_OK:
++ return "SEC_E_OK";
++
++ case SEC_E_INSUFFICIENT_MEMORY:
++ return "SEC_E_INSUFFICIENT_MEMORY";
++
++ case SEC_E_INVALID_HANDLE:
++ return "SEC_E_INVALID_HANDLE";
++
++ case SEC_E_UNSUPPORTED_FUNCTION:
++ return "SEC_E_UNSUPPORTED_FUNCTION";
++
++ case SEC_E_TARGET_UNKNOWN:
++ return "SEC_E_TARGET_UNKNOWN";
++
++ case SEC_E_INTERNAL_ERROR:
++ return "SEC_E_INTERNAL_ERROR";
++
++ case SEC_E_SECPKG_NOT_FOUND:
++ return "SEC_E_SECPKG_NOT_FOUND";
++
++ case SEC_E_NOT_OWNER:
++ return "SEC_E_NOT_OWNER";
++
++ case SEC_E_CANNOT_INSTALL:
++ return "SEC_E_CANNOT_INSTALL";
++
++ case SEC_E_INVALID_TOKEN:
++ return "SEC_E_INVALID_TOKEN";
++
++ case SEC_E_CANNOT_PACK:
++ return "SEC_E_CANNOT_PACK";
++
++ case SEC_E_QOP_NOT_SUPPORTED:
++ return "SEC_E_QOP_NOT_SUPPORTED";
++
++ case SEC_E_NO_IMPERSONATION:
++ return "SEC_E_NO_IMPERSONATION";
++
++ case SEC_E_LOGON_DENIED:
++ return "SEC_E_LOGON_DENIED";
++
++ case SEC_E_UNKNOWN_CREDENTIALS:
++ return "SEC_E_UNKNOWN_CREDENTIALS";
++
++ case SEC_E_NO_CREDENTIALS:
++ return "SEC_E_NO_CREDENTIALS";
++
++ case SEC_E_MESSAGE_ALTERED:
++ return "SEC_E_MESSAGE_ALTERED";
++
++ case SEC_E_OUT_OF_SEQUENCE:
++ return "SEC_E_OUT_OF_SEQUENCE";
++
++ case SEC_E_NO_AUTHENTICATING_AUTHORITY:
++ return "SEC_E_NO_AUTHENTICATING_AUTHORITY";
++
++ case SEC_E_BAD_PKGID:
++ return "SEC_E_BAD_PKGID";
++
++ case SEC_E_CONTEXT_EXPIRED:
++ return "SEC_E_CONTEXT_EXPIRED";
++
++ case SEC_E_INCOMPLETE_MESSAGE:
++ return "SEC_E_INCOMPLETE_MESSAGE";
++
++ case SEC_E_INCOMPLETE_CREDENTIALS:
++ return "SEC_E_INCOMPLETE_CREDENTIALS";
++
++ case SEC_E_BUFFER_TOO_SMALL:
++ return "SEC_E_BUFFER_TOO_SMALL";
++
++ case SEC_E_WRONG_PRINCIPAL:
++ return "SEC_E_WRONG_PRINCIPAL";
++
++ case SEC_E_TIME_SKEW:
++ return "SEC_E_TIME_SKEW";
++
++ case SEC_E_UNTRUSTED_ROOT:
++ return "SEC_E_UNTRUSTED_ROOT";
++
++ case SEC_E_ILLEGAL_MESSAGE:
++ return "SEC_E_ILLEGAL_MESSAGE";
++
++ case SEC_E_CERT_UNKNOWN:
++ return "SEC_E_CERT_UNKNOWN";
++
++ case SEC_E_CERT_EXPIRED:
++ return "SEC_E_CERT_EXPIRED";
++
++ case SEC_E_ENCRYPT_FAILURE:
++ return "SEC_E_ENCRYPT_FAILURE";
++
++ case SEC_E_DECRYPT_FAILURE:
++ return "SEC_E_DECRYPT_FAILURE";
++
++ case SEC_E_ALGORITHM_MISMATCH:
++ return "SEC_E_ALGORITHM_MISMATCH";
++
++ case SEC_E_SECURITY_QOS_FAILED:
++ return "SEC_E_SECURITY_QOS_FAILED";
++
++ case SEC_E_UNFINISHED_CONTEXT_DELETED:
++ return "SEC_E_UNFINISHED_CONTEXT_DELETED";
++
++ case SEC_E_NO_TGT_REPLY:
++ return "SEC_E_NO_TGT_REPLY";
++
++ case SEC_E_NO_IP_ADDRESSES:
++ return "SEC_E_NO_IP_ADDRESSES";
++
++ case SEC_E_WRONG_CREDENTIAL_HANDLE:
++ return "SEC_E_WRONG_CREDENTIAL_HANDLE";
++
++ case SEC_E_CRYPTO_SYSTEM_INVALID:
++ return "SEC_E_CRYPTO_SYSTEM_INVALID";
++
++ case SEC_E_MAX_REFERRALS_EXCEEDED:
++ return "SEC_E_MAX_REFERRALS_EXCEEDED";
++
++ case SEC_E_MUST_BE_KDC:
++ return "SEC_E_MUST_BE_KDC";
++
++ case SEC_E_STRONG_CRYPTO_NOT_SUPPORTED:
++ return "SEC_E_STRONG_CRYPTO_NOT_SUPPORTED";
++
++ case SEC_E_TOO_MANY_PRINCIPALS:
++ return "SEC_E_TOO_MANY_PRINCIPALS";
++
++ case SEC_E_NO_PA_DATA:
++ return "SEC_E_NO_PA_DATA";
++
++ case SEC_E_PKINIT_NAME_MISMATCH:
++ return "SEC_E_PKINIT_NAME_MISMATCH";
++
++ case SEC_E_SMARTCARD_LOGON_REQUIRED:
++ return "SEC_E_SMARTCARD_LOGON_REQUIRED";
++
++ case SEC_E_SHUTDOWN_IN_PROGRESS:
++ return "SEC_E_SHUTDOWN_IN_PROGRESS";
++
++ case SEC_E_KDC_INVALID_REQUEST:
++ return "SEC_E_KDC_INVALID_REQUEST";
++
++ case SEC_E_KDC_UNABLE_TO_REFER:
++ return "SEC_E_KDC_UNABLE_TO_REFER";
++
++ case SEC_E_KDC_UNKNOWN_ETYPE:
++ return "SEC_E_KDC_UNKNOWN_ETYPE";
++
++ case SEC_E_UNSUPPORTED_PREAUTH:
++ return "SEC_E_UNSUPPORTED_PREAUTH";
++
++ case SEC_E_DELEGATION_REQUIRED:
++ return "SEC_E_DELEGATION_REQUIRED";
++
++ case SEC_E_BAD_BINDINGS:
++ return "SEC_E_BAD_BINDINGS";
++
++ case SEC_E_MULTIPLE_ACCOUNTS:
++ return "SEC_E_MULTIPLE_ACCOUNTS";
++
++ case SEC_E_NO_KERB_KEY:
++ return "SEC_E_NO_KERB_KEY";
++
++ case SEC_E_CERT_WRONG_USAGE:
++ return "SEC_E_CERT_WRONG_USAGE";
++
++ case SEC_E_DOWNGRADE_DETECTED:
++ return "SEC_E_DOWNGRADE_DETECTED";
++
++ case SEC_E_SMARTCARD_CERT_REVOKED:
++ return "SEC_E_SMARTCARD_CERT_REVOKED";
++
++ case SEC_E_ISSUING_CA_UNTRUSTED:
++ return "SEC_E_ISSUING_CA_UNTRUSTED";
++
++ case SEC_E_REVOCATION_OFFLINE_C:
++ return "SEC_E_REVOCATION_OFFLINE_C";
++
++ case SEC_E_PKINIT_CLIENT_FAILURE:
++ return "SEC_E_PKINIT_CLIENT_FAILURE";
++
++ case SEC_E_SMARTCARD_CERT_EXPIRED:
++ return "SEC_E_SMARTCARD_CERT_EXPIRED";
++
++ case SEC_E_NO_S4U_PROT_SUPPORT:
++ return "SEC_E_NO_S4U_PROT_SUPPORT";
++
++ case SEC_E_CROSSREALM_DELEGATION_FAILURE:
++ return "SEC_E_CROSSREALM_DELEGATION_FAILURE";
++
++ case SEC_E_REVOCATION_OFFLINE_KDC:
++ return "SEC_E_REVOCATION_OFFLINE_KDC";
++
++ case SEC_E_ISSUING_CA_UNTRUSTED_KDC:
++ return "SEC_E_ISSUING_CA_UNTRUSTED_KDC";
++
++ case SEC_E_KDC_CERT_EXPIRED:
++ return "SEC_E_KDC_CERT_EXPIRED";
++
++ case SEC_E_KDC_CERT_REVOKED:
++ return "SEC_E_KDC_CERT_REVOKED";
++
++ case SEC_E_INVALID_PARAMETER:
++ return "SEC_E_INVALID_PARAMETER";
++
++ case SEC_E_DELEGATION_POLICY:
++ return "SEC_E_DELEGATION_POLICY";
++
++ case SEC_E_POLICY_NLTM_ONLY:
++ return "SEC_E_POLICY_NLTM_ONLY";
++
++ case SEC_E_NO_CONTEXT:
++ return "SEC_E_NO_CONTEXT";
++
++ case SEC_E_PKU2U_CERT_FAILURE:
++ return "SEC_E_PKU2U_CERT_FAILURE";
++
++ case SEC_E_MUTUAL_AUTH_FAILED:
++ return "SEC_E_MUTUAL_AUTH_FAILED";
++
++ case SEC_I_CONTINUE_NEEDED:
++ return "SEC_I_CONTINUE_NEEDED";
++
++ case SEC_I_COMPLETE_NEEDED:
++ return "SEC_I_COMPLETE_NEEDED";
++
++ case SEC_I_COMPLETE_AND_CONTINUE:
++ return "SEC_I_COMPLETE_AND_CONTINUE";
++
++ case SEC_I_LOCAL_LOGON:
++ return "SEC_I_LOCAL_LOGON";
++
++ case SEC_I_CONTEXT_EXPIRED:
++ return "SEC_I_CONTEXT_EXPIRED";
++
++ case SEC_I_INCOMPLETE_CREDENTIALS:
++ return "SEC_I_INCOMPLETE_CREDENTIALS";
++
++ case SEC_I_RENEGOTIATE:
++ return "SEC_I_RENEGOTIATE";
++
++ case SEC_I_NO_LSA_CONTEXT:
++ return "SEC_I_NO_LSA_CONTEXT";
++
++ case SEC_I_SIGNATURE_NEEDED:
++ return "SEC_I_SIGNATURE_NEEDED";
++
++ case SEC_I_NO_RENEGOTIATION:
++ return "SEC_I_NO_RENEGOTIATION";
++ }
++
++ return "SEC_E_UNKNOWN";
++}
++
+ #endif
+--
+2.11.0
+
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8786.patch freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8786.patch
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8786.patch 1970-01-01 01:00:00.000000000 +0100
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8786.patch 2019-01-10 16:07:19.000000000 +0100
@@ -0,0 +1,25 @@
+Backport of:
+
+From 445a5a42c500ceb80f8fa7f2c11f3682538033f3 Mon Sep 17 00:00:00 2001
+From: Armin Novak <armin.novak@thincast.com>
+Date: Mon, 22 Oct 2018 16:25:13 +0200
+Subject: [PATCH] Fixed CVE-2018-8786
+
+Thanks to Eyal Itkin from Check Point Software Technologies.
+---
+ libfreerdp/core/update.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+Index: freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/core/update.c
+===================================================================
+--- freerdp-1.1.0~git20140921.1.440916e+dfsg1.orig/libfreerdp/core/update.c
++++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/core/update.c
+@@ -119,7 +119,7 @@ BOOL update_read_bitmap(rdpUpdate* updat
+
+ if (bitmap_update->number > bitmap_update->count)
+ {
+- UINT16 count;
++ UINT32 count;
+
+ count = bitmap_update->number * 2;
+
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8787.patch freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8787.patch
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8787.patch 1970-01-01 01:00:00.000000000 +0100
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8787.patch 2019-01-10 16:07:19.000000000 +0100
@@ -0,0 +1,51 @@
+Backport of:
+
+From 09b9d4f1994a674c4ec85b4947aa656eda1aed8a Mon Sep 17 00:00:00 2001
+From: Armin Novak <armin.novak@thincast.com>
+Date: Mon, 22 Oct 2018 16:30:20 +0200
+Subject: [PATCH] Fixed CVE-2018-8787
+
+Thanks to Eyal Itkin from Check Point Software Technologies.
+---
+ libfreerdp/gdi/graphics.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+Index: freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/gdi/graphics.c
+===================================================================
+--- freerdp-1.1.0~git20140921.1.440916e+dfsg1.orig/libfreerdp/gdi/graphics.c
++++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/gdi/graphics.c
+@@ -23,6 +23,7 @@
+
+ #include <winpr/crt.h>
+
++#include <stdint.h>
+ #include <freerdp/gdi/dc.h>
+ #include <freerdp/gdi/brush.h>
+ #include <freerdp/gdi/shape.h>
+@@ -98,7 +99,7 @@ void gdi_Bitmap_Decompress(rdpContext* c
+ BYTE* data, int width, int height, int bpp, int length,
+ BOOL compressed, int codec_id)
+ {
+- UINT16 size;
++ UINT32 size;
+ RFX_MESSAGE* msg;
+ BYTE* src;
+ BYTE* dst;
+@@ -107,7 +108,16 @@ void gdi_Bitmap_Decompress(rdpContext* c
+ rdpGdi* gdi;
+ BOOL status;
+
+- size = width * height * ((bpp + 7) / 8);
++ size = width * height;
++
++ if (bpp <= 0 || width <= 0 || height <= 0 ||
++ width > (UINT32_MAX / height) ||
++ size > (UINT32_MAX / (bpp + 7) / 8))
++ {
++ printf("Invalid parameters, unable to decompress bitmap\n");
++ return;
++ }
++ size *= (bpp + 7) / 8;
+
+ if (bitmap->data == NULL)
+ bitmap->data = (BYTE*) malloc(size);
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8788.patch freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8788.patch
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8788.patch 1970-01-01 01:00:00.000000000 +0100
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8788.patch 2019-01-10 16:07:19.000000000 +0100
@@ -0,0 +1,352 @@
+Backport of:
+
+From d1112c279bd1a327e8e4d0b5f371458bf2579659 Mon Sep 17 00:00:00 2001
+From: Armin Novak <armin.novak@thincast.com>
+Date: Mon, 22 Oct 2018 16:52:21 +0200
+Subject: [PATCH] Fixed CVE-2018-8788
+
+Thanks to Eyal Itkin from Check Point Software Technologies.
+---
+ include/freerdp/codec/nsc.h | 4 +-
+ libfreerdp/codec/nsc.c | 94 +++++++++++++++++++++++++++++------
+ libfreerdp/codec/nsc_encode.c | 62 ++++++++++++++++-------
+ libfreerdp/codec/nsc_encode.h | 2 +-
+ libfreerdp/codec/nsc_sse2.c | 4 +-
+ 5 files changed, 130 insertions(+), 36 deletions(-)
+
+Index: freerdp-1.1.0~git20140921.1.440916e+dfsg1/include/freerdp/codec/nsc.h
+===================================================================
+--- freerdp-1.1.0~git20140921.1.440916e+dfsg1.orig/include/freerdp/codec/nsc.h
++++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/include/freerdp/codec/nsc.h
+@@ -59,8 +59,8 @@ struct _NSC_CONTEXT
+ /* color palette allocated by the application */
+ const BYTE* palette;
+
+- void (*decode)(NSC_CONTEXT* context);
+- void (*encode)(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride);
++ BOOL (*decode)(NSC_CONTEXT* context);
++ BOOL (*encode)(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride);
+
+ NSC_CONTEXT_PRIV* priv;
+ };
+Index: freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/codec/nsc.c
+===================================================================
+--- freerdp-1.1.0~git20140921.1.440916e+dfsg1.orig/libfreerdp/codec/nsc.c
++++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/codec/nsc.c
+@@ -43,7 +43,7 @@
+ #define NSC_INIT_SIMD(_nsc_context) do { } while (0)
+ #endif
+
+-static void nsc_decode(NSC_CONTEXT* context)
++static BOOL nsc_decode(NSC_CONTEXT* context)
+ {
+ UINT16 x;
+ UINT16 y;
+@@ -60,11 +60,18 @@ static void nsc_decode(NSC_CONTEXT* cont
+ INT16 g_val;
+ INT16 b_val;
+ BYTE* bmpdata;
++ size_t pos = 0;
++
++ if (!context)
++ return FALSE;
+
+ bmpdata = context->bmpdata;
+ rw = ROUND_UP_TO(context->width, 8);
+ shift = context->nsc_stream.ColorLossLevel - 1; /* colorloss recovery + YCoCg shift */
+
++ if (!bmpdata)
++ return FALSE;
++
+ for (y = 0; y < context->height; y++)
+ {
+ if (context->nsc_stream.ChromaSubSamplingLevel > 0)
+@@ -88,6 +95,11 @@ static void nsc_decode(NSC_CONTEXT* cont
+ r_val = y_val + co_val - cg_val;
+ g_val = y_val + cg_val;
+ b_val = y_val - co_val - cg_val;
++
++ if (pos + 4 > context->bmpdata_length)
++ return FALSE;
++
++ pos += 4;
+ *bmpdata++ = MINMAX(b_val, 0, 0xFF);
+ *bmpdata++ = MINMAX(g_val, 0, 0xFF);
+ *bmpdata++ = MINMAX(r_val, 0, 0xFF);
+@@ -98,9 +110,11 @@ static void nsc_decode(NSC_CONTEXT* cont
+ aplane++;
+ }
+ }
++
++ return TRUE;
+ }
+
+-static void nsc_rle_decode(BYTE* in, BYTE* out, UINT32 origsz)
++static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 origsz)
+ {
+ UINT32 len;
+ UINT32 left;
+@@ -113,6 +127,10 @@ static void nsc_rle_decode(BYTE* in, BYT
+
+ if (left == 5)
+ {
++ if (outSize < 1)
++ return FALSE;
++
++ outSize--;
+ *out++ = value;
+ left--;
+ }
+@@ -130,6 +148,10 @@ static void nsc_rle_decode(BYTE* in, BYT
+ len = *((UINT32*) in);
+ in += 4;
+ }
++ if (outSize < len)
++ return FALSE;
++
++ outSize -= len;
+ memset(out, value, len);
+ out += len;
+ left -= len;
+@@ -141,16 +163,24 @@ static void nsc_rle_decode(BYTE* in, BYT
+ }
+ }
+
+- *((UINT32*)out) = *((UINT32*)in);
++ if ((outSize < 4) || (left < 4))
++ return FALSE;
++
++ memcpy(out, in, 4);
++ return TRUE;
+ }
+
+-static void nsc_rle_decompress_data(NSC_CONTEXT* context)
++static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context)
+ {
+ UINT16 i;
+ BYTE* rle;
+ UINT32 origsize;
+ UINT32 planesize;
+
++
++ if (!context)
++ return FALSE;
++
+ rle = context->nsc_stream.Planes;
+
+ for (i = 0; i < 4; i++)
+@@ -159,14 +189,30 @@ static void nsc_rle_decompress_data(NSC_
+ planesize = context->nsc_stream.PlaneByteCount[i];
+
+ if (planesize == 0)
++ {
++ if (context->priv->plane_buf_length < origsize)
++ return FALSE;
++
+ memset(context->priv->plane_buf[i], 0xff, origsize);
++ }
+ else if (planesize < origsize)
+- nsc_rle_decode(rle, context->priv->plane_buf[i], origsize);
++ {
++ if (!nsc_rle_decode(rle, context->priv->plane_buf[i], context->priv->plane_buf_length,
++ origsize))
++ return FALSE;
++ }
+ else
++ {
++ if (context->priv->plane_buf_length < origsize)
++ return FALSE;
++
+ memcpy(context->priv->plane_buf[i], rle, origsize);
++ }
+
+ rle += planesize;
+ }
++
++ return TRUE;
+ }
+
+ static void nsc_stream_initialize(NSC_CONTEXT* context, wStream* s)
+@@ -337,12 +383,24 @@ void nsc_process_message(NSC_CONTEXT* co
+ Stream_Free(s, FALSE);
+
+ /* RLE decode */
+- PROFILER_ENTER(context->priv->prof_nsc_rle_decompress_data);
+- nsc_rle_decompress_data(context);
+- PROFILER_EXIT(context->priv->prof_nsc_rle_decompress_data);
++ {
++ BOOL rc;
++ PROFILER_ENTER(context->priv->prof_nsc_rle_decompress_data);
++ rc = nsc_rle_decompress_data(context);
++ PROFILER_EXIT(context->priv->prof_nsc_rle_decompress_data);
++
++ if (!rc)
++ return;
++ }
+
+ /* Colorloss recover, Chroma supersample and AYCoCg to ARGB Conversion in one step */
+- PROFILER_ENTER(context->priv->prof_nsc_decode);
+- context->decode(context);
+- PROFILER_EXIT(context->priv->prof_nsc_decode);
++ {
++ BOOL rc;
++ PROFILER_ENTER(context->priv->prof_nsc_decode);
++ rc = context->decode(context);
++ PROFILER_EXIT(context->priv->prof_nsc_decode);
++
++ if (!rc)
++ return;
++ }
+ }
+Index: freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/codec/nsc_encode.c
+===================================================================
+--- freerdp-1.1.0~git20140921.1.440916e+dfsg1.orig/libfreerdp/codec/nsc_encode.c
++++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/codec/nsc_encode.c
+@@ -67,7 +67,7 @@ static void nsc_context_initialize_encod
+ }
+ }
+
+-static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride)
++static BOOL nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride)
+ {
+ UINT16 x;
+ UINT16 y;
+@@ -85,10 +85,20 @@ static void nsc_encode_argb_to_aycocg(NS
+ UINT32 tempWidth;
+ UINT32 tempHeight;
+
++ if (!context || bmpdata || (rowstride == 0))
++ return FALSE;
++
+ tempWidth = ROUND_UP_TO(context->width, 8);
+ tempHeight = ROUND_UP_TO(context->height, 2);
+ rw = (context->nsc_stream.ChromaSubSamplingLevel > 0 ? tempWidth : context->width);
+ ccl = context->nsc_stream.ColorLossLevel;
++
++ if (context->priv->plane_buf_length < rw * rowstride)
++ return FALSE;
++
++ if (rw < rowstride * 2)
++ return FALSE;
++
+ yplane = context->priv->plane_buf[0];
+ coplane = context->priv->plane_buf[1];
+ cgplane = context->priv->plane_buf[2];
+@@ -196,32 +206,38 @@ static void nsc_encode_argb_to_aycocg(NS
+ memcpy(coplane + rw, coplane, rw);
+ memcpy(cgplane + rw, cgplane, rw);
+ }
++
++ return TRUE;
+ }
+
+-static void nsc_encode_subsampling(NSC_CONTEXT* context)
++static BOOL nsc_encode_subsampling(NSC_CONTEXT* context)
+ {
+ UINT16 x;
+ UINT16 y;
+- BYTE* co_dst;
+- BYTE* cg_dst;
+- INT8* co_src0;
+- INT8* co_src1;
+- INT8* cg_src0;
+- INT8* cg_src1;
+ UINT32 tempWidth;
+ UINT32 tempHeight;
+
++
++ if (!context)
++ return FALSE;
++
+ tempWidth = ROUND_UP_TO(context->width, 8);
+ tempHeight = ROUND_UP_TO(context->height, 2);
+
++ if (tempHeight == 0)
++ return FALSE;
++
++ if (tempWidth > context->priv->plane_buf_length / tempHeight)
++ return FALSE;
++
+ for (y = 0; y < tempHeight >> 1; y++)
+ {
+- co_dst = context->priv->plane_buf[1] + y * (tempWidth >> 1);
+- cg_dst = context->priv->plane_buf[2] + y * (tempWidth >> 1);
+- co_src0 = (INT8*) context->priv->plane_buf[1] + (y << 1) * tempWidth;
+- co_src1 = co_src0 + tempWidth;
+- cg_src0 = (INT8*) context->priv->plane_buf[2] + (y << 1) * tempWidth;
+- cg_src1 = cg_src0 + tempWidth;
++ BYTE* co_dst = context->priv->plane_buf[1] + y * (tempWidth >> 1);
++ BYTE* cg_dst = context->priv->plane_buf[2] + y * (tempWidth >> 1);
++ const INT8* co_src0 = (INT8*) context->priv->plane_buf[1] + (y << 1) * tempWidth;
++ const INT8* co_src1 = co_src0 + tempWidth;
++ const INT8* cg_src0 = (INT8*) context->priv->plane_buf[2] + (y << 1) * tempWidth;
++ const INT8* cg_src1 = cg_src0 + tempWidth;
+ for (x = 0; x < tempWidth >> 1; x++)
+ {
+ *co_dst++ = (BYTE) (((INT16) *co_src0 + (INT16) *(co_src0 + 1) +
+@@ -234,18 +250,28 @@ static void nsc_encode_subsampling(NSC_C
+ cg_src1 += 2;
+ }
+ }
++
++ return TRUE;
+ }
+
+-void nsc_encode(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride)
++BOOL nsc_encode(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride)
+ {
+- nsc_encode_argb_to_aycocg(context, bmpdata, rowstride);
++ if (!context || !bmpdata || (rowstride == 0))
++ return FALSE;
++
++ if (!nsc_encode_argb_to_aycocg(context, bmpdata, rowstride))
++ return FALSE;
++
+ if (context->nsc_stream.ChromaSubSamplingLevel > 0)
+ {
+- nsc_encode_subsampling(context);
++ if (!nsc_encode_subsampling(context))
++ return FALSE;
+ }
++
++ return TRUE;
+ }
+
+-static UINT32 nsc_rle_encode(BYTE* in, BYTE* out, UINT32 origsz)
++static UINT32 nsc_rle_encode(const BYTE* in, BYTE* out, UINT32 origsz)
+ {
+ UINT32 left;
+ UINT32 runlength = 1;
+Index: freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/codec/nsc_sse2.c
+===================================================================
+--- freerdp-1.1.0~git20140921.1.440916e+dfsg1.orig/libfreerdp/codec/nsc_sse2.c
++++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/codec/nsc_sse2.c
+@@ -333,13 +333,15 @@ static void nsc_encode_subsampling_sse2(
+ }
+ }
+
+-static void nsc_encode_sse2(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride)
++static BOOL nsc_encode_sse2(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride)
+ {
+ nsc_encode_argb_to_aycocg_sse2(context, bmpdata, rowstride);
+ if (context->nsc_stream.ChromaSubSamplingLevel > 0)
+ {
+ nsc_encode_subsampling_sse2(context);
+ }
++
++ return TRUE;
+ }
+
+ void nsc_init_sse2(NSC_CONTEXT* context)
+Index: freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/codec/nsc_encode.h
+===================================================================
+--- freerdp-1.1.0~git20140921.1.440916e+dfsg1.orig/libfreerdp/codec/nsc_encode.h
++++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/libfreerdp/codec/nsc_encode.h
+@@ -20,6 +20,6 @@
+ #ifndef __NSC_ENCODE_H
+ #define __NSC_ENCODE_H
+
+-void nsc_encode(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride);
++BOOL nsc_encode(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride);
+
+ #endif
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8789.patch freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8789.patch
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8789.patch 1970-01-01 01:00:00.000000000 +0100
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/CVE-2018-8789.patch 2019-01-10 16:07:19.000000000 +0100
@@ -0,0 +1,27 @@
+Backport of:
+
+From 2ee663f39dc8dac3d9988e847db19b2d7e3ac8c6 Mon Sep 17 00:00:00 2001
+From: Armin Novak <armin.novak@thincast.com>
+Date: Mon, 22 Oct 2018 16:00:03 +0200
+Subject: [PATCH] Fixed CVE-2018-8789
+
+Thanks to Eyal Itkin from Check Point Software Technologies.
+---
+ winpr/libwinpr/sspi/NTLM/ntlm_message.c | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+Index: freerdp-1.1.0~git20140921.1.440916e+dfsg1/winpr/libwinpr/sspi/NTLM/ntlm_message.c
+===================================================================
+--- freerdp-1.1.0~git20140921.1.440916e+dfsg1.orig/winpr/libwinpr/sspi/NTLM/ntlm_message.c
++++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/winpr/libwinpr/sspi/NTLM/ntlm_message.c
+@@ -146,6 +146,10 @@ void ntlm_read_message_fields_buffer(wSt
+ {
+ if (fields->Len > 0)
+ {
++ const UINT64 offset = (UINT64)fields->BufferOffset + (UINT64)fields->Len;
++
++ if (offset > Stream_Length(s))
++ return;
+ fields->Buffer = malloc(fields->Len);
+ Stream_SetPosition(s, fields->BufferOffset);
+ Stream_Read(s, fields->Buffer, fields->Len);
diff -Nru freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/series freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/series
--- freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/series 2017-08-12 21:26:43.000000000 +0200
+++ freerdp-1.1.0~git20140921.1.440916e+dfsg1/debian/patches/series 2019-01-10 16:07:19.000000000 +0100
@@ -21,3 +21,8 @@
1013_aligned_meminfo_alignment.patch
0008-Fix-multiple-security-issues.patch
0009-enable-TLS-12.patch
+CVE-2018-8786.patch
+CVE-2018-8787.patch
+CVE-2018-8788.patch
+CVE-2018-8789.patch
+0010_add-support-for-credssp-v3-and-rdpproto-v6.patch
Reply to: