Standard RDP Security Layer Levels/Method Overhaul

[MS-RDPBCGR] Section 5.3 describes the encryption level and method values for
standard RDP security.

Looking at the current usage of these values in the FreeRDP code gives me
reason to believe that there is a certain lack of understanding of how these
values should be handled.

The encryption level is only configured on the server side in the "Encryption
Level" setting found in the Remote Desktop Session Host Configuration RDP-Tcp
properties dialog and this value is never transferred from the client to the
server over the wire.
The possible options are "None", "Low", "Client Compatible", "High" and
"FIPS Compliant". The client receices this value in the Server Security Data
block (TS_UD_SC_SEC1), probably only for informational purposes and maybe to
give the client the possibility to verify if the server's decision for the
encryption method confirms to the server's encryption level.
The possible encryption methods are "NONE", "40BIT", "56BIT", "128BIT" and
"FIPS" and the RDP client advertises the ones it supports to the server in the
Client Security Data block (TS_UD_CS_SEC).
The server's configured encryption level value restricts the possible final
encryption method.
Something that I was not able to find in the documentation is the priority
level of the individual encryption methods based on which the server makes its
final method decision if there are several options.
My analysis with Windows Servers reveiled that the order is 128, 56, 40, FIPS.
The server only chooses FIPS if the level is "FIPS Comliant" or if it is the
only method advertised by the client.

Bottom line:
* FreeRDP's client side does not need to set settings->EncryptionLevel
(which was done quite frequently).
* FreeRDP's server side does not have to set the supported encryption methods
list in settings->EncryptionMethods

Changes in this commit:

Removed unnecessary/confusing changes of EncryptionLevel/Methods settings

Refactor settings->DisableEncryption
* This value actually means "Advanced RDP Encryption (NLA/TLS) is NOT used"
* The old name caused lots of confusion among developers
* Renamed it to "UseRdpSecurityLayer" (the compare logic stays untouched)

Any client's setting of settings->EncryptionMethods were annihilated
* All clients "want" to set all supported methods
* Some clients forgot 56bit because 56bit was not supported at the time the
code was written
* settings->EncryptionMethods was overwritten anyways in nego_connect()
* Removed all client side settings of settings->EncryptionMethods
The default is "None" (0)
* Changed nego_connect() to advertise all supported methods if
settings->EncryptionMethods is 0 (None)
* Added a commandline option /encryption-methods:comma separated list of the
values "40", "56", "128", "FIPS". E.g. /encryption-methods:56,128
* Print warning if server chooses non-advertised method

Verify received level and method in client's gcc_read_server_security_data
* Only accept valid/known encryption methods
* Verify encryption level/method combinations according to MS-RDPBCGR 5.3.2

Server implementations can now set settings->EncryptionLevel
* The default for settings->EncryptionLevel is 0 (None)
* nego_send_negotiation_response() changes it to ClientCompatible in that case
* default to ClientCompatible if the server implementation set an invalid level

Fix server's gcc_write_server_security_data
* Verify server encryption level value set by server implementations
* Choose rdp encryption method based on level and supported client methods
* Moved FIPS to the lowest priority (only used if other methods are possible)

Updated sample server
* Support RDP Security (RdpKeyFile was not set)
* Added commented sample code for setting the security level
This commit is contained in:
Norbert Federa 2014-12-12 02:17:12 +01:00
parent b579ad3cec
commit 939f1c639a
16 changed files with 275 additions and 76 deletions

View File

@ -745,9 +745,7 @@ JNIEXPORT void JNICALL jni_freerdp_set_connection_info(JNIEnv *env, jclass cls,
settings->TlsSecurity = FALSE; settings->TlsSecurity = FALSE;
settings->NlaSecurity = FALSE; settings->NlaSecurity = FALSE;
settings->ExtSecurity = FALSE; settings->ExtSecurity = FALSE;
settings->DisableEncryption = TRUE; settings->UseRdpSecurityLayer = TRUE;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
break; break;
case 2: case 2:

View File

@ -3,6 +3,7 @@
* FreeRDP Client Command-Line Interface * FreeRDP Client Command-Line Interface
* *
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -167,6 +168,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
{ "heartbeat", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support heartbeat PDUs" }, { "heartbeat", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support heartbeat PDUs" },
{ "multitransport", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support multitransport protocol" }, { "multitransport", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support multitransport protocol" },
{ "assistance", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Remote assistance password" }, { "assistance", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Remote assistance password" },
{ "encryption-methods", COMMAND_LINE_VALUE_REQUIRED, "<40,56,128,FIPS>", NULL, NULL, -1, NULL, "RDP standard security encryption methods" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
}; };
@ -1733,9 +1735,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
settings->TlsSecurity = FALSE; settings->TlsSecurity = FALSE;
settings->NlaSecurity = FALSE; settings->NlaSecurity = FALSE;
settings->ExtSecurity = FALSE; settings->ExtSecurity = FALSE;
settings->DisableEncryption = TRUE; settings->UseRdpSecurityLayer = TRUE;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT| ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
} }
else if (strcmp("tls", arg->Value) == 0) /* TLS */ else if (strcmp("tls", arg->Value) == 0) /* TLS */
{ {
@ -1763,6 +1763,33 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
WLog_ERR(TAG, "unknown protocol security: %s", arg->Value); WLog_ERR(TAG, "unknown protocol security: %s", arg->Value);
} }
} }
CommandLineSwitchCase(arg, "encryption-methods")
{
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
{
UINT32 i;
char** p;
int count = 0;
p = freerdp_command_line_parse_comma_separated_values(arg->Value, &count);
for (i = 0; i < count; i++)
{
if (!strcmp(p[i], "40"))
settings->EncryptionMethods |= ENCRYPTION_METHOD_40BIT;
else if (!strcmp(p[i], "56"))
settings->EncryptionMethods |= ENCRYPTION_METHOD_56BIT;
else if (!strcmp(p[i], "128"))
settings->EncryptionMethods |= ENCRYPTION_METHOD_128BIT;
else if (!strcmp(p[i], "FIPS"))
settings->EncryptionMethods |= ENCRYPTION_METHOD_FIPS;
else
WLog_ERR(TAG, "unknown encryption method '%s'", p[i]);
}
free(p);
}
}
CommandLineSwitchCase(arg, "sec-rdp") CommandLineSwitchCase(arg, "sec-rdp")
{ {
settings->RdpSecurity = arg->Value ? TRUE : FALSE; settings->RdpSecurity = arg->Value ? TRUE : FALSE;
@ -1801,7 +1828,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
} }
CommandLineSwitchCase(arg, "encryption") CommandLineSwitchCase(arg, "encryption")
{ {
settings->DisableEncryption = arg->Value ? FALSE : TRUE; settings->UseRdpSecurityLayer = arg->Value ? FALSE : TRUE;
} }
CommandLineSwitchCase(arg, "grab-keyboard") CommandLineSwitchCase(arg, "grab-keyboard")
{ {

View File

@ -695,9 +695,7 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
settings->RdpSecurity = TRUE; settings->RdpSecurity = TRUE;
settings->TlsSecurity = FALSE; settings->TlsSecurity = FALSE;
settings->NlaSecurity = FALSE; settings->NlaSecurity = FALSE;
settings->DisableEncryption = FALSE; settings->UseRdpSecurityLayer = FALSE;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
} }
else if (strncmp("tls", arg->Value, 1) == 0) /* TLS */ else if (strncmp("tls", arg->Value, 1) == 0) /* TLS */
{ {

View File

@ -158,9 +158,7 @@ NSString* TSXSessionDidFailToConnectNotification = @"TSXSessionDidFailToConnect"
settings->TlsSecurity = FALSE; settings->TlsSecurity = FALSE;
settings->NlaSecurity = FALSE; settings->NlaSecurity = FALSE;
settings->ExtSecurity = FALSE; settings->ExtSecurity = FALSE;
settings->DisableEncryption = TRUE; settings->UseRdpSecurityLayer = TRUE;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
break; break;
default: default:

View File

@ -529,7 +529,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_SupportGraphicsPipeline 142 #define FreeRDP_SupportGraphicsPipeline 142
#define FreeRDP_SupportDynamicTimeZone 143 #define FreeRDP_SupportDynamicTimeZone 143
#define FreeRDP_SupportHeartbeatPdu 144 #define FreeRDP_SupportHeartbeatPdu 144
#define FreeRDP_DisableEncryption 192 #define FreeRDP_UseRdpSecurityLayer 192
#define FreeRDP_EncryptionMethods 193 #define FreeRDP_EncryptionMethods 193
#define FreeRDP_ExtEncryptionMethods 194 #define FreeRDP_ExtEncryptionMethods 194
#define FreeRDP_EncryptionLevel 195 #define FreeRDP_EncryptionLevel 195
@ -860,7 +860,7 @@ struct rdp_settings
UINT64 padding0192[192 - 145]; /* 145 */ UINT64 padding0192[192 - 145]; /* 145 */
/* Client/Server Security Data */ /* Client/Server Security Data */
ALIGN64 BOOL DisableEncryption; /* 192 */ ALIGN64 BOOL UseRdpSecurityLayer; /* 192 */
ALIGN64 UINT32 EncryptionMethods; /* 193 */ ALIGN64 UINT32 EncryptionMethods; /* 193 */
ALIGN64 UINT32 ExtEncryptionMethods; /* 194 */ ALIGN64 UINT32 ExtEncryptionMethods; /* 194 */
ALIGN64 UINT32 EncryptionLevel; /* 195 */ ALIGN64 UINT32 EncryptionLevel; /* 195 */

View File

@ -682,8 +682,8 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id)
case FreeRDP_SupportDynamicTimeZone: case FreeRDP_SupportDynamicTimeZone:
return settings->SupportDynamicTimeZone; return settings->SupportDynamicTimeZone;
case FreeRDP_DisableEncryption: case FreeRDP_UseRdpSecurityLayer:
return settings->DisableEncryption; return settings->UseRdpSecurityLayer;
case FreeRDP_ConsoleSession: case FreeRDP_ConsoleSession:
return settings->ConsoleSession; return settings->ConsoleSession;
@ -1075,8 +1075,8 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param)
settings->SupportDynamicTimeZone = param; settings->SupportDynamicTimeZone = param;
break; break;
case FreeRDP_DisableEncryption: case FreeRDP_UseRdpSecurityLayer:
settings->DisableEncryption = param; settings->UseRdpSecurityLayer = param;
break; break;
case FreeRDP_ConsoleSession: case FreeRDP_ConsoleSession:

View File

@ -3537,7 +3537,7 @@ BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId)
if (rdp->disconnect) if (rdp->disconnect)
return TRUE; return TRUE;
if (rdp->settings->DisableEncryption) if (rdp->settings->UseRdpSecurityLayer)
{ {
if (!rdp_read_security_header(s, &securityFlags)) if (!rdp_read_security_header(s, &securityFlags))
return FALSE; return FALSE;

View File

@ -398,7 +398,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
settings = rdp->settings; settings = rdp->settings;
if (!settings->DisableEncryption) if (!settings->UseRdpSecurityLayer)
{ {
/* no RDP encryption */ /* no RDP encryption */
return TRUE; return TRUE;
@ -515,7 +515,7 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
BYTE* priv_exp; BYTE* priv_exp;
BOOL ret = FALSE; BOOL ret = FALSE;
if (!rdp->settings->DisableEncryption) if (!rdp->settings->UseRdpSecurityLayer)
{ {
/* No RDP Security. */ /* No RDP Security. */
return TRUE; return TRUE;

View File

@ -3,6 +3,7 @@
* T.124 Generic Conference Control (GCC) * T.124 Generic Conference Control (GCC)
* *
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,7 +29,7 @@
#include "gcc.h" #include "gcc.h"
#include "certificate.h" #include "certificate.h"
#define TAG FREERDP_TAG("core") #define TAG FREERDP_TAG("core.gcc")
/** /**
* T.124 GCC is defined in: * T.124 GCC is defined in:
@ -948,7 +949,7 @@ BOOL gcc_read_client_security_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
if (blockLength < 8) if (blockLength < 8)
return FALSE; return FALSE;
if (settings->DisableEncryption) if (settings->UseRdpSecurityLayer)
{ {
Stream_Read_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */ Stream_Read_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
if (settings->EncryptionMethods == 0) if (settings->EncryptionMethods == 0)
@ -976,7 +977,7 @@ void gcc_write_client_security_data(wStream* s, rdpMcs* mcs)
gcc_write_user_data_header(s, CS_SECURITY, 12); gcc_write_user_data_header(s, CS_SECURITY, 12);
if (settings->DisableEncryption) if (settings->UseRdpSecurityLayer)
{ {
Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */ Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
Stream_Write_UINT32(s, 0); /* extEncryptionMethods */ Stream_Write_UINT32(s, 0); /* extEncryptionMethods */
@ -994,19 +995,87 @@ BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs)
BYTE* data; BYTE* data;
UINT32 length; UINT32 length;
rdpSettings* settings = mcs->settings; rdpSettings* settings = mcs->settings;
BOOL validCryptoConfig = FALSE;
UINT32 serverEncryptionMethod;
if (Stream_GetRemainingLength(s) < 8) if (Stream_GetRemainingLength(s) < 8)
return FALSE; return FALSE;
Stream_Read_UINT32(s, settings->EncryptionMethods); /* encryptionMethod */ Stream_Read_UINT32(s, serverEncryptionMethod); /* encryptionMethod */
Stream_Read_UINT32(s, settings->EncryptionLevel); /* encryptionLevel */ Stream_Read_UINT32(s, settings->EncryptionLevel); /* encryptionLevel */
if (settings->EncryptionMethods == 0 && settings->EncryptionLevel == 0) /* Only accept valid/known encryption methods */
switch (serverEncryptionMethod)
{ {
/* serverRandom and serverRandom must not be present */ case ENCRYPTION_METHOD_NONE:
settings->DisableEncryption = FALSE; WLog_DBG(TAG, "Server rdp encryption method: NONE");
settings->EncryptionMethods = ENCRYPTION_METHOD_NONE; break;
settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; case ENCRYPTION_METHOD_40BIT:
WLog_DBG(TAG, "Server rdp encryption method: 40BIT");
break;
case ENCRYPTION_METHOD_56BIT:
WLog_DBG(TAG, "Server rdp encryption method: 56BIT");
break;
case ENCRYPTION_METHOD_128BIT:
WLog_DBG(TAG, "Server rdp encryption method: 128BIT");
break;
case ENCRYPTION_METHOD_FIPS:
WLog_DBG(TAG, "Server rdp encryption method: FIPS");
break;
default:
WLog_ERR(TAG, "Received unknown encryption method %08X", serverEncryptionMethod);
return FALSE;
}
if (settings->UseRdpSecurityLayer && !(settings->EncryptionMethods & serverEncryptionMethod))
{
WLog_WARN(TAG, "Server uses non-advertised encryption method 0x%08X", serverEncryptionMethod);
/* FIXME: Should we return FALSE; in this case ?? */
}
settings->EncryptionMethods = serverEncryptionMethod;
/* Verify encryption level/method combinations according to MS-RDPBCGR Section 5.3.2 */
switch (settings->EncryptionLevel)
{
case ENCRYPTION_LEVEL_NONE:
if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
{
validCryptoConfig = TRUE;
}
break;
case ENCRYPTION_LEVEL_FIPS:
if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
{
validCryptoConfig = TRUE;
}
break;
case ENCRYPTION_LEVEL_LOW:
case ENCRYPTION_LEVEL_HIGH:
case ENCRYPTION_LEVEL_CLIENT_COMPATIBLE:
if (settings->EncryptionMethods == ENCRYPTION_METHOD_40BIT ||
settings->EncryptionMethods == ENCRYPTION_METHOD_56BIT ||
settings->EncryptionMethods == ENCRYPTION_METHOD_128BIT ||
settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
{
validCryptoConfig = TRUE;
}
break;
default:
WLog_ERR(TAG, "Received unknown encryption level %08X", settings->EncryptionLevel);
}
if (!validCryptoConfig)
{
WLog_ERR(TAG, "Received invalid cryptographic configuration (level=0x%08X method=0x%08X)",
settings->EncryptionLevel, settings->EncryptionMethods);
return FALSE;
}
if (settings->EncryptionLevel == ENCRYPTION_LEVEL_NONE)
{
/* serverRandomLen and serverCertLen must not be present */
settings->UseRdpSecurityLayer = FALSE;
return TRUE; return TRUE;
} }
@ -1102,30 +1171,111 @@ void gcc_write_server_security_data(wStream* s, rdpMcs* mcs)
UINT32 headerLen, serverRandomLen, serverCertLen, wPublicKeyBlobLen; UINT32 headerLen, serverRandomLen, serverCertLen, wPublicKeyBlobLen;
rdpSettings* settings = mcs->settings; rdpSettings* settings = mcs->settings;
if (!settings->DisableEncryption) /**
* Re: settings->EncryptionLevel:
* This is configured/set by the server implementation and serves the same
* purpose as the "Encryption Level" setting in the RDP-Tcp configuration
* dialog of Microsoft's Remote Desktop Session Host Configuration.
* Re: settings->EncryptionMethods:
* at this point this setting contains the client's supported encryption
* methods we've received in gcc_read_client_security_data()
*/
if (!settings->UseRdpSecurityLayer)
{ {
settings->EncryptionMethods = ENCRYPTION_METHOD_NONE; /* TLS/NLA is used: disable rdp style encryption */
settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE;
} }
else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_FIPS) != 0)
/* verify server encryption level value */
switch (settings->EncryptionLevel)
{ {
settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS; case ENCRYPTION_LEVEL_NONE:
} WLog_INFO(TAG, "Active rdp encryption level: NONE");
else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_128BIT) != 0) break;
{ case ENCRYPTION_LEVEL_FIPS:
settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT; WLog_INFO(TAG, "Active rdp encryption level: FIPS Compliant");
} break;
else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_56BIT) != 0) case ENCRYPTION_LEVEL_HIGH:
{ WLog_INFO(TAG, "Active rdp encryption level: HIGH");
settings->EncryptionMethods = ENCRYPTION_METHOD_56BIT; break;
} case ENCRYPTION_LEVEL_LOW:
else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_40BIT) != 0) WLog_INFO(TAG, "Active rdp encryption level: LOW");
{ break;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT; case ENCRYPTION_LEVEL_CLIENT_COMPATIBLE:
WLog_INFO(TAG, "Active rdp encryption level: CLIENT-COMPATIBLE");
break;
default:
WLog_ERR(TAG, "Invalid server encryption level 0x%08X", settings->EncryptionLevel);
WLog_ERR(TAG, "Switching to encryption level CLIENT-COMPATIBLE");
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
} }
if (settings->EncryptionMethods != ENCRYPTION_METHOD_NONE) /* choose rdp encryption method based on server level and client methods */
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; switch (settings->EncryptionLevel)
{
case ENCRYPTION_LEVEL_NONE:
/* The only valid method is NONE in this case */
settings->EncryptionMethods = ENCRYPTION_METHOD_NONE;
break;
case ENCRYPTION_LEVEL_FIPS:
/* The only valid method is FIPS in this case */
if (!(settings->EncryptionMethods & ENCRYPTION_METHOD_FIPS))
{
WLog_WARN(TAG, "client does not support FIPS as required by server configuration");
}
settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS;
break;
case ENCRYPTION_LEVEL_HIGH:
/* Maximum key strength supported by the server must be used (128 bit)*/
if (!(settings->EncryptionMethods & ENCRYPTION_METHOD_128BIT))
{
WLog_WARN(TAG, "client does not support 128 bit encryption method as required by server configuration");
}
settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT;
break;
case ENCRYPTION_LEVEL_LOW:
case ENCRYPTION_LEVEL_CLIENT_COMPATIBLE:
/* Maximum key strength supported by the client must be used */
if (settings->EncryptionMethods & ENCRYPTION_METHOD_128BIT)
settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT;
else if (settings->EncryptionMethods & ENCRYPTION_METHOD_56BIT)
settings->EncryptionMethods = ENCRYPTION_METHOD_56BIT;
else if (settings->EncryptionMethods & ENCRYPTION_METHOD_40BIT)
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT;
else if (settings->EncryptionMethods & ENCRYPTION_METHOD_FIPS)
settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS;
else
{
WLog_WARN(TAG, "client has not announced any supported encryption methods");
settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT;
}
break;
default:
WLog_ERR(TAG, "internal error: unknown encryption level");
}
/* log selected encryption method */
switch (settings->EncryptionMethods)
{
case ENCRYPTION_METHOD_NONE:
WLog_INFO(TAG, "Selected rdp encryption method: NONE");
break;
case ENCRYPTION_METHOD_40BIT:
WLog_INFO(TAG, "Selected rdp encryption method: 40BIT");
break;
case ENCRYPTION_METHOD_56BIT:
WLog_INFO(TAG, "Selected rdp encryption method: 56BIT");
break;
case ENCRYPTION_METHOD_128BIT:
WLog_INFO(TAG, "Selected rdp encryption method: 128BIT");
break;
case ENCRYPTION_METHOD_FIPS:
WLog_INFO(TAG, "Selected rdp encryption method: FIPS");
break;
default:
WLog_ERR(TAG, "internal error: unknown encryption method");
}
headerLen = 12; headerLen = 12;
keyLen = 0; keyLen = 0;
@ -1133,8 +1283,7 @@ void gcc_write_server_security_data(wStream* s, rdpMcs* mcs)
serverRandomLen = 0; serverRandomLen = 0;
serverCertLen = 0; serverCertLen = 0;
if (settings->EncryptionMethods != ENCRYPTION_METHOD_NONE || if (settings->EncryptionMethods != ENCRYPTION_METHOD_NONE)
settings->EncryptionLevel != ENCRYPTION_LEVEL_NONE)
{ {
serverRandomLen = 32; serverRandomLen = 32;
@ -1170,8 +1319,7 @@ void gcc_write_server_security_data(wStream* s, rdpMcs* mcs)
Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethod */ Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethod */
Stream_Write_UINT32(s, settings->EncryptionLevel); /* encryptionLevel */ Stream_Write_UINT32(s, settings->EncryptionLevel); /* encryptionLevel */
if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE && if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
settings->EncryptionLevel == ENCRYPTION_LEVEL_NONE)
{ {
return; return;
} }
@ -1243,7 +1391,7 @@ BOOL gcc_read_client_network_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
if (blockLength < 4 + mcs->channelCount * 12) if (blockLength < 4 + mcs->channelCount * 12)
return FALSE; return FALSE;
if (mcs->channelCount > 16) if (mcs->channelCount > 16)
return FALSE; return FALSE;

View File

@ -590,7 +590,7 @@ BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s)
if ((securityFlags & SEC_INFO_PKT) == 0) if ((securityFlags & SEC_INFO_PKT) == 0)
return FALSE; return FALSE;
if (rdp->settings->DisableEncryption) if (rdp->settings->UseRdpSecurityLayer)
{ {
if (securityFlags & SEC_REDIRECTION_PKT) if (securityFlags & SEC_REDIRECTION_PKT)
{ {

View File

@ -3,6 +3,7 @@
* RDP Protocol Security Negotiation * RDP Protocol Security Negotiation
* *
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -164,9 +165,16 @@ BOOL nego_connect(rdpNego* nego)
if (nego->selected_protocol == PROTOCOL_RDP) if (nego->selected_protocol == PROTOCOL_RDP)
{ {
settings->DisableEncryption = TRUE; settings->UseRdpSecurityLayer = TRUE;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; if (!settings->EncryptionMethods)
{
/**
* Advertise all supported encryption methods if the client
* implementation did not set any security methods
*/
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
}
} }
/* finally connect security layer (if not already done) */ /* finally connect security layer (if not already done) */
@ -964,14 +972,30 @@ BOOL nego_send_negotiation_response(rdpNego* nego)
settings->TlsSecurity = FALSE; settings->TlsSecurity = FALSE;
settings->NlaSecurity = FALSE; settings->NlaSecurity = FALSE;
settings->RdpSecurity = TRUE; settings->RdpSecurity = TRUE;
settings->UseRdpSecurityLayer = TRUE;
if (!settings->LocalConnection) if (settings->EncryptionLevel == ENCRYPTION_LEVEL_NONE)
{ {
settings->DisableEncryption = TRUE; /**
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; * If the server implementation did not explicitely set a
* encryption level we default to client compatible
*/
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
} }
if (settings->LocalConnection)
{
/**
* Note: This hack was firstly introduced in commit 95f5e115 to
* disable the unnecessary encryption with peers connecting to
* 127.0.0.1 or local unix sockets.
* This also affects connections via port tunnels! (e.g. ssh -L)
*/
WLog_INFO(TAG, "Turning off encryption for local peer with standard rdp security");
settings->UseRdpSecurityLayer = FALSE;
settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE;
}
if (!settings->RdpServerRsaKey && !settings->RdpKeyFile) if (!settings->RdpServerRsaKey && !settings->RdpKeyFile)
{ {
WLog_ERR(TAG, "Missing server certificate"); WLog_ERR(TAG, "Missing server certificate");
@ -983,8 +1007,7 @@ BOOL nego_send_negotiation_response(rdpNego* nego)
settings->TlsSecurity = TRUE; settings->TlsSecurity = TRUE;
settings->NlaSecurity = FALSE; settings->NlaSecurity = FALSE;
settings->RdpSecurity = FALSE; settings->RdpSecurity = FALSE;
settings->DisableEncryption = FALSE; settings->UseRdpSecurityLayer = FALSE;
settings->EncryptionMethods = ENCRYPTION_METHOD_NONE;
settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE;
} }
else if (settings->SelectedProtocol == PROTOCOL_NLA) else if (settings->SelectedProtocol == PROTOCOL_NLA)
@ -992,8 +1015,7 @@ BOOL nego_send_negotiation_response(rdpNego* nego)
settings->TlsSecurity = TRUE; settings->TlsSecurity = TRUE;
settings->NlaSecurity = TRUE; settings->NlaSecurity = TRUE;
settings->RdpSecurity = FALSE; settings->RdpSecurity = FALSE;
settings->DisableEncryption = FALSE; settings->UseRdpSecurityLayer = FALSE;
settings->EncryptionMethods = ENCRYPTION_METHOD_NONE;
settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE;
} }
} }

View File

@ -348,7 +348,7 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s)
if (rdp->disconnect) if (rdp->disconnect)
return 0; return 0;
if (rdp->settings->DisableEncryption) if (rdp->settings->UseRdpSecurityLayer)
{ {
if (!rdp_read_security_header(s, &securityFlags)) if (!rdp_read_security_header(s, &securityFlags))
return -1; return -1;
@ -485,7 +485,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra)
break; break;
case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT:
if (rdp->settings->DisableEncryption) if (rdp->settings->UseRdpSecurityLayer)
{ {
if (!rdp_server_establish_keys(rdp, s)) if (!rdp_server_establish_keys(rdp, s))
return -1; return -1;

View File

@ -1040,7 +1040,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s)
rdp->autodetect->bandwidthMeasureByteCount += length; rdp->autodetect->bandwidthMeasureByteCount += length;
} }
if (rdp->settings->DisableEncryption) if (rdp->settings->UseRdpSecurityLayer)
{ {
if (!rdp_read_security_header(s, &securityFlags)) if (!rdp_read_security_header(s, &securityFlags))
return -1; return -1;

View File

@ -422,7 +422,6 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp)
CryptoSha1 sha1; CryptoSha1 sha1;
BYTE client_encrypt_key_t[CRYPTO_SHA1_DIGEST_LENGTH + 1]; BYTE client_encrypt_key_t[CRYPTO_SHA1_DIGEST_LENGTH + 1];
BYTE client_decrypt_key_t[CRYPTO_SHA1_DIGEST_LENGTH + 1]; BYTE client_decrypt_key_t[CRYPTO_SHA1_DIGEST_LENGTH + 1];
WLog_INFO(TAG, "FIPS Compliant encryption level.");
sha1 = crypto_sha1_init(); sha1 = crypto_sha1_init();
if (!sha1) if (!sha1)
{ {

View File

@ -232,7 +232,7 @@ rdpSettings* freerdp_settings_new(DWORD flags)
settings->KeyboardSubType = 0; settings->KeyboardSubType = 0;
settings->KeyboardFunctionKey = 12; settings->KeyboardFunctionKey = 12;
settings->KeyboardLayout = 0; settings->KeyboardLayout = 0;
settings->DisableEncryption = FALSE; settings->UseRdpSecurityLayer = FALSE;
settings->SaltedChecksum = TRUE; settings->SaltedChecksum = TRUE;
settings->ServerPort = 3389; settings->ServerPort = 3389;
settings->GatewayPort = 443; settings->GatewayPort = 443;

View File

@ -4,6 +4,7 @@
* *
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2011 Vic Lee * Copyright 2011 Vic Lee
* Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -347,19 +348,19 @@ static BOOL test_sleep_tsdiff(UINT32 *old_sec, UINT32 *old_usec, UINT32 new_sec,
*old_sec = new_sec; *old_sec = new_sec;
*old_usec = new_usec; *old_usec = new_usec;
while (usec < 0) while (usec < 0)
{ {
usec += 1000000; usec += 1000000;
sec--; sec--;
} }
if (sec > 0) if (sec > 0)
Sleep(sec * 1000); Sleep(sec * 1000);
if (usec > 0) if (usec > 0)
USleep(usec); USleep(usec);
return TRUE; return TRUE;
} }
@ -669,7 +670,15 @@ static void* test_peer_mainloop(void* arg)
/* Initialize the real server settings here */ /* Initialize the real server settings here */
client->settings->CertificateFile = _strdup("server.crt"); client->settings->CertificateFile = _strdup("server.crt");
client->settings->PrivateKeyFile = _strdup("server.key"); client->settings->PrivateKeyFile = _strdup("server.key");
client->settings->RdpKeyFile = _strdup("server.key");
client->settings->RdpSecurity = TRUE;
client->settings->TlsSecurity = TRUE;
client->settings->NlaSecurity = FALSE; client->settings->NlaSecurity = FALSE;
client->settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
/* client->settings->EncryptionLevel = ENCRYPTION_LEVEL_HIGH; */
/* client->settings->EncryptionLevel = ENCRYPTION_LEVEL_LOW; */
/* client->settings->EncryptionLevel = ENCRYPTION_LEVEL_FIPS; */
client->settings->RemoteFxCodec = TRUE; client->settings->RemoteFxCodec = TRUE;
client->settings->ColorDepth = 32; client->settings->ColorDepth = 32;
client->settings->SuppressOutput = TRUE; client->settings->SuppressOutput = TRUE;
@ -844,7 +853,7 @@ int main(int argc, char* argv[])
if (argc > 1) if (argc > 1)
test_pcap_file = argv[1]; test_pcap_file = argv[1];
if (argc > 2 && !strcmp(argv[2], "--fast")) if (argc > 2 && !strcmp(argv[2], "--fast"))
test_dump_rfx_realtime = FALSE; test_dump_rfx_realtime = FALSE;