Dear release team,

please review...

On Thu, 20 Dec 2018 13:06:05 +0100 Mike Gabriel <[email protected]> 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 <[email protected]>  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 <[email protected]>
 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 <[email protected]>
+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 <[email protected]>
+  Bernhard Miklautz <[email protected]>
+  Martin Fleisz <[email protected]>
+
+---
+ 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 <[email protected]>
++ * Copyright 2016 Martin Fleisz <[email protected]>
+  *
+  * 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 <[email protected]>
++ *
++ * 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 <[email protected]>
+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 <[email protected]>
+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 <[email protected]>
+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 <[email protected]>
+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 via email to