FreeRDP/libfreerdp/core/gcc.c

2433 lines
71 KiB
C
Raw Normal View History

/**
2012-10-09 07:02:04 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
* T.124 Generic Conference Control (GCC)
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
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
2014-12-12 04:17:12 +03:00
* Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
* Copyright 2014 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
2023-02-09 10:48:11 +03:00
* Copyright 2023 Armin Novak <anovak@thincast.com>
* Copyright 2023 Thincast Technologies GmbH
*
* 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.
*/
2022-02-16 13:20:38 +03:00
#include <freerdp/config.h>
#include "settings.h"
2012-12-14 22:11:07 +04:00
#include <winpr/crt.h>
2016-02-24 18:46:25 +03:00
#include <winpr/crypto.h>
#include <winpr/assert.h>
#include <freerdp/log.h>
#include <freerdp/utils/string.h>
2023-02-03 13:53:49 +03:00
#include <freerdp/crypto/certificate.h>
#include "utils.h"
#include "gcc.h"
2023-02-03 13:53:49 +03:00
#include "nego.h"
#include "../crypto/certificate.h"
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
2014-12-12 04:17:12 +03:00
#define TAG FREERDP_TAG("core.gcc")
typedef enum
{
HIGH_COLOR_4BPP = 0x04,
HIGH_COLOR_8BPP = 0x08,
HIGH_COLOR_15BPP = 0x0F,
HIGH_COLOR_16BPP = 0x10,
HIGH_COLOR_24BPP = 0x18,
} HIGH_COLOR_DEPTH;
static const char* HighColorToString(HIGH_COLOR_DEPTH color)
{
switch (color)
{
case HIGH_COLOR_4BPP:
return "HIGH_COLOR_4BPP";
case HIGH_COLOR_8BPP:
return "HIGH_COLOR_8BPP";
case HIGH_COLOR_15BPP:
return "HIGH_COLOR_15BPP";
case HIGH_COLOR_16BPP:
return "HIGH_COLOR_16BPP";
case HIGH_COLOR_24BPP:
return "HIGH_COLOR_24BPP";
default:
return "HIGH_COLOR_UNKNOWN";
}
}
static HIGH_COLOR_DEPTH ColorDepthToHighColor(UINT32 bpp)
{
switch (bpp)
{
case 4:
return HIGH_COLOR_4BPP;
case 8:
return HIGH_COLOR_8BPP;
case 15:
return HIGH_COLOR_15BPP;
case 16:
return HIGH_COLOR_16BPP;
default:
return HIGH_COLOR_24BPP;
}
}
static char* gcc_block_type_string(UINT16 type, char* buffer, size_t size);
static BOOL gcc_read_client_cluster_data(wStream* s, rdpMcs* mcs);
static BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs);
2021-01-25 12:06:01 +03:00
static BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, UINT16 length);
static BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, UINT16 length);
2019-11-20 13:30:14 +03:00
static BOOL gcc_read_user_data_header(wStream* s, UINT16* type, UINT16* length);
2020-11-18 09:51:45 +03:00
static BOOL gcc_write_user_data_header(wStream* s, UINT16 type, UINT16 length);
2019-11-20 13:30:14 +03:00
static BOOL gcc_write_client_core_data(wStream* s, const rdpMcs* mcs);
2019-11-20 13:30:14 +03:00
static BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs);
static BOOL gcc_write_server_core_data(wStream* s, rdpMcs* mcs);
static BOOL gcc_read_client_security_data(wStream* s, rdpMcs* mcs);
2020-11-18 09:51:45 +03:00
static BOOL gcc_write_client_security_data(wStream* s, const rdpMcs* mcs);
2019-11-20 13:30:14 +03:00
static BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs);
static BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs);
static BOOL gcc_read_client_network_data(wStream* s, rdpMcs* mcs);
2020-11-18 09:51:45 +03:00
static BOOL gcc_write_client_network_data(wStream* s, const rdpMcs* mcs);
2019-11-20 13:30:14 +03:00
static BOOL gcc_read_server_network_data(wStream* s, rdpMcs* mcs);
2020-11-18 09:51:45 +03:00
static BOOL gcc_write_server_network_data(wStream* s, const rdpMcs* mcs);
static BOOL gcc_write_client_cluster_data(wStream* s, const rdpMcs* mcs);
static BOOL gcc_read_client_monitor_data(wStream* s, rdpMcs* mcs);
2020-11-18 09:51:45 +03:00
static BOOL gcc_write_client_monitor_data(wStream* s, const rdpMcs* mcs);
static BOOL gcc_read_client_monitor_extended_data(wStream* s, rdpMcs* mcs);
2020-11-18 09:51:45 +03:00
static BOOL gcc_write_client_monitor_extended_data(wStream* s, const rdpMcs* mcs);
static BOOL gcc_read_client_message_channel_data(wStream* s, rdpMcs* mcs);
2020-11-18 09:51:45 +03:00
static BOOL gcc_write_client_message_channel_data(wStream* s, const rdpMcs* mcs);
2019-11-20 13:30:14 +03:00
static BOOL gcc_read_server_message_channel_data(wStream* s, rdpMcs* mcs);
2020-11-18 09:51:45 +03:00
static BOOL gcc_write_server_message_channel_data(wStream* s, const rdpMcs* mcs);
static BOOL gcc_read_client_multitransport_channel_data(wStream* s, rdpMcs* mcs);
2020-11-18 09:51:45 +03:00
static BOOL gcc_write_client_multitransport_channel_data(wStream* s, const rdpMcs* mcs);
2019-11-20 13:30:14 +03:00
static BOOL gcc_read_server_multitransport_channel_data(wStream* s, rdpMcs* mcs);
2020-11-18 09:51:45 +03:00
static BOOL gcc_write_server_multitransport_channel_data(wStream* s, const rdpMcs* mcs);
2019-11-20 13:30:14 +03:00
static rdpSettings* mcs_get_settings(rdpMcs* mcs)
{
WINPR_ASSERT(mcs);
rdpContext* context = transport_get_context(mcs->transport);
WINPR_ASSERT(context);
return context->settings;
}
static const rdpSettings* mcs_get_const_settings(const rdpMcs* mcs)
{
WINPR_ASSERT(mcs);
const rdpContext* context = transport_get_context(mcs->transport);
WINPR_ASSERT(context);
return context->settings;
}
static char* rdp_early_server_caps_string(UINT32 flags, char* buffer, size_t size)
{
char msg[32] = { 0 };
const UINT32 mask = RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1 | RNS_UD_SC_DYNAMIC_DST_SUPPORTED |
RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2 | RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED;
const UINT32 unknown = flags & (~mask);
if (flags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1)
winpr_str_append("RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1", buffer, size, "|");
if (flags & RNS_UD_SC_DYNAMIC_DST_SUPPORTED)
winpr_str_append("RNS_UD_SC_DYNAMIC_DST_SUPPORTED", buffer, size, "|");
if (flags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2)
winpr_str_append("RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2", buffer, size, "|");
if (flags & RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED)
winpr_str_append("RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED", buffer, size, "|");
if (unknown != 0)
{
(void)_snprintf(msg, sizeof(msg), "RNS_UD_SC_UNKNOWN[0x%08" PRIx32 "]", unknown);
winpr_str_append(msg, buffer, size, "|");
}
(void)_snprintf(msg, sizeof(msg), "[0x%08" PRIx32 "]", flags);
winpr_str_append(msg, buffer, size, "|");
return buffer;
}
static const char* rdp_early_client_caps_string(UINT32 flags, char* buffer, size_t size)
{
char msg[32] = { 0 };
const UINT32 mask = RNS_UD_CS_SUPPORT_ERRINFO_PDU | RNS_UD_CS_WANT_32BPP_SESSION |
RNS_UD_CS_SUPPORT_STATUSINFO_PDU | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS |
RNS_UD_CS_RELATIVE_MOUSE_INPUT | RNS_UD_CS_VALID_CONNECTION_TYPE |
RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU |
RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT |
RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL | RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE |
RNS_UD_CS_SUPPORT_HEARTBEAT_PDU | RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN;
const UINT32 unknown = flags & (~mask);
if (flags & RNS_UD_CS_SUPPORT_ERRINFO_PDU)
winpr_str_append("RNS_UD_CS_SUPPORT_ERRINFO_PDU", buffer, size, "|");
if (flags & RNS_UD_CS_WANT_32BPP_SESSION)
winpr_str_append("RNS_UD_CS_WANT_32BPP_SESSION", buffer, size, "|");
if (flags & RNS_UD_CS_SUPPORT_STATUSINFO_PDU)
winpr_str_append("RNS_UD_CS_SUPPORT_STATUSINFO_PDU", buffer, size, "|");
if (flags & RNS_UD_CS_STRONG_ASYMMETRIC_KEYS)
winpr_str_append("RNS_UD_CS_STRONG_ASYMMETRIC_KEYS", buffer, size, "|");
if (flags & RNS_UD_CS_RELATIVE_MOUSE_INPUT)
winpr_str_append("RNS_UD_CS_RELATIVE_MOUSE_INPUT", buffer, size, "|");
if (flags & RNS_UD_CS_VALID_CONNECTION_TYPE)
winpr_str_append("RNS_UD_CS_VALID_CONNECTION_TYPE", buffer, size, "|");
if (flags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU)
winpr_str_append("RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU", buffer, size, "|");
if (flags & RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT)
winpr_str_append("RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT", buffer, size, "|");
if (flags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL)
winpr_str_append("RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL", buffer, size, "|");
if (flags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE)
winpr_str_append("RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE", buffer, size, "|");
if (flags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU)
winpr_str_append("RNS_UD_CS_SUPPORT_HEARTBEAT_PDU", buffer, size, "|");
if (flags & RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN)
winpr_str_append("RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN", buffer, size, "|");
if (unknown != 0)
{
(void)_snprintf(msg, sizeof(msg), "RNS_UD_CS_UNKNOWN[0x%08" PRIx32 "]", unknown);
winpr_str_append(msg, buffer, size, "|");
}
(void)_snprintf(msg, sizeof(msg), "[0x%08" PRIx32 "]", flags);
winpr_str_append(msg, buffer, size, "|");
return buffer;
}
2018-11-14 12:14:48 +03:00
static DWORD rdp_version_common(DWORD serverVersion, DWORD clientVersion)
{
DWORD version = MIN(serverVersion, clientVersion);
switch (version)
{
case RDP_VERSION_4:
case RDP_VERSION_5_PLUS:
case RDP_VERSION_10_0:
case RDP_VERSION_10_1:
case RDP_VERSION_10_2:
case RDP_VERSION_10_3:
case RDP_VERSION_10_4:
case RDP_VERSION_10_5:
case RDP_VERSION_10_6:
case RDP_VERSION_10_7:
case RDP_VERSION_10_8:
case RDP_VERSION_10_9:
case RDP_VERSION_10_10:
case RDP_VERSION_10_11:
2023-10-12 14:07:11 +03:00
case RDP_VERSION_10_12:
2018-11-14 12:14:48 +03:00
return version;
default:
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "Invalid client [%" PRId32 "] and server [%" PRId32 "] versions",
2018-11-14 12:14:48 +03:00
serverVersion, clientVersion);
return version;
}
}
/**
* T.124 GCC is defined in:
*
* http://www.itu.int/rec/T-REC-T.124-199802-S/en
* ITU-T T.124 (02/98): Generic Conference Control
*/
/**
* ConnectData ::= SEQUENCE
* {
* t124Identifier Key,
* connectPDU OCTET_STRING
* }
*
* Key ::= CHOICE
* {
* object OBJECT_IDENTIFIER,
* h221NonStandard H221NonStandardIdentifier
* }
*
* ConnectGCCPDU ::= CHOICE
* {
* conferenceCreateRequest ConferenceCreateRequest,
* conferenceCreateResponse ConferenceCreateResponse,
* conferenceQueryRequest ConferenceQueryRequest,
* conferenceQueryResponse ConferenceQueryResponse,
* conferenceJoinRequest ConferenceJoinRequest,
* conferenceJoinResponse ConferenceJoinResponse,
* conferenceInviteRequest ConferenceInviteRequest,
* conferenceInviteResponse ConferenceInviteResponse,
* ...
* }
*
* ConferenceCreateRequest ::= SEQUENCE
* {
* conferenceName ConferenceName,
* convenerPassword Password OPTIONAL,
* password Password OPTIONAL,
* lockedConference BOOLEAN,
* listedConference BOOLEAN,
* conductibleConference BOOLEAN,
* terminationMethod TerminationMethod,
* conductorPrivileges SET OF Privilege OPTIONAL,
* conductedPrivileges SET OF Privilege OPTIONAL,
* nonConductedPrivileges SET OF Privilege OPTIONAL,
* conferenceDescription TextString OPTIONAL,
* callerIdentifier TextString OPTIONAL,
* userData UserData OPTIONAL,
* ...,
* conferencePriority ConferencePriority OPTIONAL,
* conferenceMode ConferenceMode OPTIONAL
* }
*
* ConferenceCreateResponse ::= SEQUENCE
* {
* nodeID UserID,
* tag INTEGER,
* result ENUMERATED
* {
* success (0),
* userRejected (1),
* resourcesNotAvailable (2),
* rejectedForSymmetryBreaking (3),
* lockedConferenceNotSupported (4)
* },
* userData UserData OPTIONAL,
* ...
* }
*
* ConferenceName ::= SEQUENCE
* {
* numeric SimpleNumericString
* text SimpleTextString OPTIONAL,
* ...
* }
*
* SimpleNumericString ::= NumericString (SIZE (1..255)) (FROM ("0123456789"))
*
* UserData ::= SET OF SEQUENCE
* {
* key Key,
* value OCTET_STRING OPTIONAL
* }
*
* H221NonStandardIdentifier ::= OCTET STRING (SIZE (4..255))
*
* UserID ::= DynamicChannelID
*
* ChannelID ::= INTEGER (1..65535)
* StaticChannelID ::= INTEGER (1..1000)
* DynamicChannelID ::= INTEGER (1001..65535)
*
*/
/*
* OID = 0.0.20.124.0.1
* { itu-t(0) recommendation(0) t(20) t124(124) version(0) 1 }
* v.1 of ITU-T Recommendation T.124 (Feb 1998): "Generic Conference Control"
*/
static const BYTE t124_02_98_oid[6] = { 0, 0, 20, 124, 0, 1 };
static const BYTE h221_cs_key[4] = "Duca";
static const BYTE h221_sc_key[4] = "McDn";
/**
2022-12-09 16:35:03 +03:00
* Read a GCC Conference Create Request.
* msdn{cc240836}
*
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
BOOL gcc_read_conference_create_request(wStream* s, rdpMcs* mcs)
{
UINT16 length = 0;
BYTE choice = 0;
BYTE number = 0;
BYTE selection = 0;
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
/* ConnectData */
if (!per_read_choice(s, &choice))
return FALSE;
2016-09-20 09:58:04 +03:00
if (!per_read_object_identifier(s, t124_02_98_oid))
return FALSE;
/* ConnectData::connectPDU (OCTET_STRING) */
if (!per_read_length(s, &length))
return FALSE;
/* ConnectGCCPDU */
if (!per_read_choice(s, &choice))
return FALSE;
2016-09-20 09:58:04 +03:00
if (!per_read_selection(s, &selection))
return FALSE;
/* ConferenceCreateRequest::conferenceName */
if (!per_read_numeric_string(s, 1)) /* ConferenceName::numeric */
return FALSE;
2016-09-20 09:58:04 +03:00
if (!per_read_padding(s, 1)) /* padding */
return FALSE;
/* UserData (SET OF SEQUENCE) */
2019-11-06 17:24:51 +03:00
if (!per_read_number_of_sets(s, &number) || number != 1) /* one set of UserData */
return FALSE;
2016-09-20 09:58:04 +03:00
2019-11-06 17:24:51 +03:00
if (!per_read_choice(s, &choice) ||
choice != 0xC0) /* UserData::value present + select h221NonStandard (1) */
return FALSE;
/* h221NonStandard */
2016-09-20 09:58:04 +03:00
if (!per_read_octet_string(s, h221_cs_key, 4,
4)) /* h221NonStandard, client-to-server H.221 key, "Duca" */
return FALSE;
/* userData::value (OCTET_STRING) */
if (!per_read_length(s, &length))
return FALSE;
2016-09-20 09:58:04 +03:00
if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
return FALSE;
2016-09-20 09:58:04 +03:00
if (!gcc_read_client_data_blocks(s, mcs, length))
return FALSE;
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Write a GCC Conference Create Request.
* msdn{cc240836}
*
* @param s stream
2022-12-09 16:35:03 +03:00
* @param userData client data blocks
*
* @return \b TRUE for success, \b FALSE otherwise
*/
2020-11-18 09:51:45 +03:00
BOOL gcc_write_conference_create_request(wStream* s, wStream* userData)
{
WINPR_ASSERT(s);
WINPR_ASSERT(userData);
/* ConnectData */
2020-11-18 09:51:45 +03:00
if (!per_write_choice(s, 0)) /* From Key select object (0) of type OBJECT_IDENTIFIER */
return FALSE;
if (!per_write_object_identifier(s, t124_02_98_oid)) /* ITU-T T.124 (02/98) OBJECT_IDENTIFIER */
return FALSE;
/* ConnectData::connectPDU (OCTET_STRING) */
2020-11-18 09:51:45 +03:00
if (!per_write_length(s, Stream_GetPosition(userData) + 14)) /* connectPDU length */
return FALSE;
/* ConnectGCCPDU */
2020-11-18 09:51:45 +03:00
if (!per_write_choice(s, 0)) /* From ConnectGCCPDU select conferenceCreateRequest (0) of type
2019-11-06 17:24:51 +03:00
ConferenceCreateRequest */
2020-11-18 09:51:45 +03:00
return FALSE;
if (!per_write_selection(s, 0x08)) /* select optional userData from ConferenceCreateRequest */
return FALSE;
/* ConferenceCreateRequest::conferenceName */
2020-11-18 09:51:45 +03:00
if (!per_write_numeric_string(s, (BYTE*)"1", 1, 1)) /* ConferenceName::numeric */
return FALSE;
if (!per_write_padding(s, 1)) /* padding */
return FALSE;
/* UserData (SET OF SEQUENCE) */
2020-11-18 09:51:45 +03:00
if (!per_write_number_of_sets(s, 1)) /* one set of UserData */
return FALSE;
if (!per_write_choice(s, 0xC0)) /* UserData::value present + select h221NonStandard (1) */
return FALSE;
/* h221NonStandard */
2020-11-18 09:51:45 +03:00
if (!per_write_octet_string(s, h221_cs_key, 4,
4)) /* h221NonStandard, client-to-server H.221 key, "Duca" */
return FALSE;
/* userData::value (OCTET_STRING) */
2020-11-18 09:51:45 +03:00
return per_write_octet_string(s, Stream_Buffer(userData), Stream_GetPosition(userData),
0); /* array of client data blocks */
}
BOOL gcc_read_conference_create_response(wStream* s, rdpMcs* mcs)
{
UINT16 length = 0;
UINT32 tag = 0;
UINT16 nodeID = 0;
BYTE result = 0;
BYTE choice = 0;
BYTE number = 0;
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
/* ConnectData */
2019-11-06 17:24:51 +03:00
if (!per_read_choice(s, &choice) || !per_read_object_identifier(s, t124_02_98_oid))
return FALSE;
/* ConnectData::connectPDU (OCTET_STRING) */
if (!per_read_length(s, &length))
return FALSE;
/* ConnectGCCPDU */
if (!per_read_choice(s, &choice))
return FALSE;
/* ConferenceCreateResponse::nodeID (UserID) */
if (!per_read_integer16(s, &nodeID, 1001))
return FALSE;
/* ConferenceCreateResponse::tag (INTEGER) */
if (!per_read_integer(s, &tag))
return FALSE;
/* ConferenceCreateResponse::result (ENUMERATED) */
if (!per_read_enumerated(s, &result, MCS_Result_enum_length))
return FALSE;
/* number of UserData sets */
if (!per_read_number_of_sets(s, &number))
return FALSE;
/* UserData::value present + select h221NonStandard (1) */
if (!per_read_choice(s, &choice))
return FALSE;
/* h221NonStandard */
2016-09-20 09:58:04 +03:00
if (!per_read_octet_string(s, h221_sc_key, 4,
4)) /* h221NonStandard, server-to-client H.221 key, "McDn" */
return FALSE;
/* userData (OCTET_STRING) */
if (!per_read_length(s, &length))
return FALSE;
if (!gcc_read_server_data_blocks(s, mcs, length))
2011-09-05 22:02:52 +04:00
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "gcc_read_conference_create_response: gcc_read_server_data_blocks failed");
return FALSE;
2011-09-05 22:02:52 +04:00
}
return TRUE;
}
2020-11-18 09:51:45 +03:00
BOOL gcc_write_conference_create_response(wStream* s, wStream* userData)
2011-08-19 19:56:47 +04:00
{
WINPR_ASSERT(s);
WINPR_ASSERT(userData);
2011-08-19 19:56:47 +04:00
/* ConnectData */
2020-11-18 09:51:45 +03:00
if (!per_write_choice(s, 0))
return FALSE;
if (!per_write_object_identifier(s, t124_02_98_oid))
return FALSE;
2011-08-19 19:56:47 +04:00
/* ConnectData::connectPDU (OCTET_STRING) */
/* This length MUST be ignored by the client according to [MS-RDPBCGR] */
2020-11-18 09:51:45 +03:00
if (!per_write_length(s, 0x2A))
return FALSE;
2011-08-19 19:56:47 +04:00
/* ConnectGCCPDU */
2020-11-18 09:51:45 +03:00
if (!per_write_choice(s, 0x14))
return FALSE;
2011-08-19 19:56:47 +04:00
/* ConferenceCreateResponse::nodeID (UserID) */
2020-11-18 09:51:45 +03:00
if (!per_write_integer16(s, 0x79F3, 1001))
return FALSE;
2011-08-19 19:56:47 +04:00
/* ConferenceCreateResponse::tag (INTEGER) */
2020-11-18 09:51:45 +03:00
if (!per_write_integer(s, 1))
return FALSE;
2011-08-19 19:56:47 +04:00
/* ConferenceCreateResponse::result (ENUMERATED) */
2020-11-18 09:51:45 +03:00
if (!per_write_enumerated(s, 0, MCS_Result_enum_length))
return FALSE;
2011-08-19 19:56:47 +04:00
/* number of UserData sets */
2020-11-18 09:51:45 +03:00
if (!per_write_number_of_sets(s, 1))
return FALSE;
2011-08-19 19:56:47 +04:00
/* UserData::value present + select h221NonStandard (1) */
2020-11-18 09:51:45 +03:00
if (!per_write_choice(s, 0xC0))
return FALSE;
2011-08-19 19:56:47 +04:00
/* h221NonStandard */
2020-11-18 09:51:45 +03:00
if (!per_write_octet_string(s, h221_sc_key, 4,
4)) /* h221NonStandard, server-to-client H.221 key, "McDn" */
return FALSE;
2011-08-19 19:56:47 +04:00
/* userData (OCTET_STRING) */
2020-11-18 09:51:45 +03:00
return per_write_octet_string(s, Stream_Buffer(userData), Stream_GetPosition(userData),
0); /* array of server data blocks */
2011-08-19 19:56:47 +04:00
}
static BOOL gcc_read_client_unused1_data(wStream* s)
{
return Stream_SafeSeek(s, 2);
}
2021-01-25 12:06:01 +03:00
BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, UINT16 length)
{
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
BOOL gotMultitransport = FALSE;
while (length > 0)
{
wStream sbuffer = { 0 };
UINT16 type = 0;
UINT16 blockLength = 0;
if (!gcc_read_user_data_header(s, &type, &blockLength))
return FALSE;
if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(blockLength - 4)))
return FALSE;
wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLength - 4);
WINPR_ASSERT(sub);
Stream_Seek(s, blockLength - 4);
switch (type)
{
case CS_CORE:
if (!gcc_read_client_core_data(sub, mcs))
return FALSE;
2016-09-20 09:58:04 +03:00
break;
case CS_SECURITY:
if (!gcc_read_client_security_data(sub, mcs))
return FALSE;
2016-09-20 09:58:04 +03:00
break;
case CS_NET:
if (!gcc_read_client_network_data(sub, mcs))
return FALSE;
2016-09-20 09:58:04 +03:00
break;
case CS_CLUSTER:
if (!gcc_read_client_cluster_data(sub, mcs))
return FALSE;
2016-09-20 09:58:04 +03:00
break;
case CS_MONITOR:
if (!gcc_read_client_monitor_data(sub, mcs))
return FALSE;
2016-09-20 09:58:04 +03:00
break;
case CS_MCS_MSGCHANNEL:
if (!gcc_read_client_message_channel_data(sub, mcs))
return FALSE;
2016-09-20 09:58:04 +03:00
break;
case CS_MONITOR_EX:
if (!gcc_read_client_monitor_extended_data(sub, mcs))
return FALSE;
2016-09-20 09:58:04 +03:00
break;
case CS_UNUSED1:
if (!gcc_read_client_unused1_data(sub))
return FALSE;
break;
case 0xC009:
case CS_MULTITRANSPORT:
gotMultitransport = TRUE;
if (!gcc_read_client_multitransport_channel_data(sub, mcs))
return FALSE;
2016-09-20 09:58:04 +03:00
break;
default:
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "Unknown GCC client data block: 0x%04" PRIX16 "", type);
winpr_HexDump(TAG, WLOG_TRACE, Stream_Pointer(sub), Stream_GetRemainingLength(sub));
break;
}
const size_t rem = Stream_GetRemainingLength(sub);
if (rem > 0)
{
char buffer[128] = { 0 };
const size_t total = Stream_Length(sub);
2016-09-20 09:58:04 +03:00
WLog_ERR(TAG,
"Error parsing GCC client data block %s: Actual Offset: %" PRIuz
" Expected Offset: %" PRIuz,
gcc_block_type_string(type, buffer, sizeof(buffer)), total - rem, total);
}
if (blockLength > length)
{
char buffer[128] = { 0 };
WLog_ERR(TAG,
"Error parsing GCC client data block %s: got blockLength 0x%04" PRIx16
", but only 0x%04" PRIx16 "remaining",
gcc_block_type_string(type, buffer, sizeof(buffer)), blockLength, length);
length = 0;
}
else
length -= blockLength;
}
if (!gotMultitransport)
{
rdpSettings* settings = mcs_get_settings(mcs);
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMultitransport, FALSE))
return FALSE;
if (!freerdp_settings_set_uint32(settings, FreeRDP_MultitransportFlags, 0))
return FALSE;
}
return TRUE;
}
BOOL gcc_write_client_data_blocks(wStream* s, const rdpMcs* mcs)
{
const rdpSettings* settings = mcs_get_const_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
2020-11-18 09:51:45 +03:00
if (!gcc_write_client_core_data(s, mcs) || !gcc_write_client_cluster_data(s, mcs) ||
!gcc_write_client_security_data(s, mcs) || !gcc_write_client_network_data(s, mcs))
return FALSE;
/* extended client data supported */
if (settings->NegotiationFlags & EXTENDED_CLIENT_DATA_SUPPORTED)
{
if (settings->UseMultimon && !settings->SpanMonitors)
{
2020-11-18 09:51:45 +03:00
if (!gcc_write_client_monitor_data(s, mcs) ||
!gcc_write_client_monitor_extended_data(s, mcs))
return FALSE;
}
2020-11-18 09:51:45 +03:00
if (!gcc_write_client_message_channel_data(s, mcs) ||
!gcc_write_client_multitransport_channel_data(s, mcs))
return FALSE;
}
else
{
if (settings->UseMultimon && !settings->SpanMonitors)
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "WARNING: true multi monitor support was not advertised by server!");
if (settings->ForceMultimon)
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "Sending multi monitor information anyway (may break connectivity!)");
2020-11-18 09:51:45 +03:00
if (!gcc_write_client_monitor_data(s, mcs) ||
!gcc_write_client_monitor_extended_data(s, mcs))
return FALSE;
}
2012-12-14 01:29:16 +04:00
else
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "Use /multimon:force to force sending multi monitor information");
2012-12-14 01:29:16 +04:00
}
}
}
return TRUE;
}
char* gcc_block_type_string(UINT16 type, char* buffer, size_t size)
{
switch (type)
{
case CS_CORE:
(void)_snprintf(buffer, size, "CS_CORE [0x%04" PRIx16 "]", type);
break;
case CS_SECURITY:
(void)_snprintf(buffer, size, "CS_SECURITY [0x%04" PRIx16 "]", type);
break;
case CS_NET:
(void)_snprintf(buffer, size, "CS_NET [0x%04" PRIx16 "]", type);
break;
case CS_CLUSTER:
(void)_snprintf(buffer, size, "CS_CLUSTER [0x%04" PRIx16 "]", type);
break;
case CS_MONITOR:
(void)_snprintf(buffer, size, "CS_MONITOR [0x%04" PRIx16 "]", type);
break;
case CS_MCS_MSGCHANNEL:
(void)_snprintf(buffer, size, "CS_MONITOR [0x%04" PRIx16 "]", type);
break;
case CS_MONITOR_EX:
(void)_snprintf(buffer, size, "CS_MONITOR_EX [0x%04" PRIx16 "]", type);
break;
case CS_UNUSED1:
(void)_snprintf(buffer, size, "CS_UNUSED1 [0x%04" PRIx16 "]", type);
break;
case CS_MULTITRANSPORT:
(void)_snprintf(buffer, size, "CS_MONITOR_EX [0x%04" PRIx16 "]", type);
break;
case SC_CORE:
(void)_snprintf(buffer, size, "SC_CORE [0x%04" PRIx16 "]", type);
break;
case SC_SECURITY:
(void)_snprintf(buffer, size, "SC_SECURITY [0x%04" PRIx16 "]", type);
break;
case SC_NET:
(void)_snprintf(buffer, size, "SC_NET [0x%04" PRIx16 "]", type);
break;
case SC_MCS_MSGCHANNEL:
(void)_snprintf(buffer, size, "SC_MCS_MSGCHANNEL [0x%04" PRIx16 "]", type);
break;
case SC_MULTITRANSPORT:
(void)_snprintf(buffer, size, "SC_MULTITRANSPORT [0x%04" PRIx16 "]", type);
break;
default:
(void)_snprintf(buffer, size, "UNKNOWN [0x%04" PRIx16 "]", type);
break;
}
return buffer;
}
2021-01-25 12:06:01 +03:00
BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, UINT16 length)
{
UINT16 type = 0;
UINT16 offset = 0;
UINT16 blockLength = 0;
BYTE* holdp = NULL;
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
while (offset < length)
{
char buffer[64] = { 0 };
size_t rest = 0;
wStream subbuffer;
wStream* sub = NULL;
2011-09-05 22:02:52 +04:00
if (!gcc_read_user_data_header(s, &type, &blockLength))
2011-09-05 22:02:52 +04:00
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_user_data_header failed");
return FALSE;
2011-09-05 22:02:52 +04:00
}
holdp = Stream_Pointer(s);
sub = Stream_StaticInit(&subbuffer, holdp, blockLength - 4);
if (!Stream_SafeSeek(s, blockLength - 4))
{
WLog_ERR(TAG, "gcc_read_server_data_blocks: stream too short");
return FALSE;
}
offset += blockLength;
switch (type)
{
case SC_CORE:
if (!gcc_read_server_core_data(sub, mcs))
2011-09-05 22:02:52 +04:00
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_core_data failed");
return FALSE;
2011-09-05 22:02:52 +04:00
}
2016-09-20 09:58:04 +03:00
break;
case SC_SECURITY:
if (!gcc_read_server_security_data(sub, mcs))
return FALSE;
break;
case SC_NET:
if (!gcc_read_server_network_data(sub, mcs))
2011-09-05 22:02:52 +04:00
{
2016-09-20 09:58:04 +03:00
WLog_ERR(TAG,
"gcc_read_server_data_blocks: gcc_read_server_network_data failed");
return FALSE;
2011-09-05 22:02:52 +04:00
}
2016-09-20 09:58:04 +03:00
break;
case SC_MCS_MSGCHANNEL:
if (!gcc_read_server_message_channel_data(sub, mcs))
{
2019-11-06 17:24:51 +03:00
WLog_ERR(
TAG,
"gcc_read_server_data_blocks: gcc_read_server_message_channel_data failed");
return FALSE;
}
2016-09-20 09:58:04 +03:00
break;
case SC_MULTITRANSPORT:
if (!gcc_read_server_multitransport_channel_data(sub, mcs))
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "gcc_read_server_data_blocks: "
"gcc_read_server_multitransport_channel_data failed");
return FALSE;
}
2016-09-20 09:58:04 +03:00
break;
default:
WLog_ERR(TAG, "gcc_read_server_data_blocks: ignoring type=%s",
gcc_block_type_string(type, buffer, sizeof(buffer)));
winpr_HexDump(TAG, WLOG_TRACE, Stream_Pointer(sub), Stream_GetRemainingLength(sub));
break;
}
2016-09-20 09:58:04 +03:00
rest = Stream_GetRemainingLength(sub);
if (rest > 0)
{
WLog_WARN(TAG, "gcc_read_server_data_blocks: ignoring %" PRIuz " bytes with type=%s",
rest, gcc_block_type_string(type, buffer, sizeof(buffer)));
}
}
return TRUE;
}
BOOL gcc_write_server_data_blocks(wStream* s, rdpMcs* mcs)
2011-08-19 19:56:47 +04:00
{
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
if (!gcc_write_server_core_data(s, mcs) || /* serverCoreData */
!gcc_write_server_network_data(s, mcs) || /* serverNetworkData */
!gcc_write_server_security_data(s, mcs) || /* serverSecurityData */
!gcc_write_server_message_channel_data(s, mcs)) /* serverMessageChannelData */
return FALSE;
const rdpSettings* settings = mcs_get_const_settings(mcs);
WINPR_ASSERT(settings);
if (settings->SupportMultitransport && (settings->MultitransportFlags != 0))
/* serverMultitransportChannelData */
return gcc_write_server_multitransport_channel_data(s, mcs);
return TRUE;
2011-08-19 19:56:47 +04:00
}
BOOL gcc_read_user_data_header(wStream* s, UINT16* type, UINT16* length)
{
WINPR_ASSERT(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return FALSE;
2019-11-06 17:24:51 +03:00
Stream_Read_UINT16(s, *type); /* type */
2013-05-09 00:09:16 +04:00
Stream_Read_UINT16(s, *length); /* length */
if ((*length < 4) || (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(*length - 4))))
return FALSE;
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Write a user data header (TS_UD_HEADER).
* msdn{cc240509}
*
* @param s stream
* @param type data block type
* @param length data block length
2022-12-09 16:35:03 +03:00
*
* @return \b TRUE for success, \b FALSE otherwise
*/
2020-11-18 09:51:45 +03:00
BOOL gcc_write_user_data_header(wStream* s, UINT16 type, UINT16 length)
{
WINPR_ASSERT(s);
2020-11-18 09:51:45 +03:00
if (!Stream_EnsureRemainingCapacity(s, 4 + length))
return FALSE;
2019-11-06 17:24:51 +03:00
Stream_Write_UINT16(s, type); /* type */
2013-05-09 00:09:16 +04:00
Stream_Write_UINT16(s, length); /* length */
2020-11-18 09:51:45 +03:00
return TRUE;
}
static UINT32 filterAndLogEarlyServerCapabilityFlags(UINT32 flags)
{
const UINT32 mask =
(RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1 | RNS_UD_SC_DYNAMIC_DST_SUPPORTED |
2023-01-20 11:03:16 +03:00
RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2 | RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED);
const UINT32 filtered = flags & mask;
const UINT32 unknown = flags & (~mask);
if (unknown != 0)
{
char buffer[256] = { 0 };
WLog_WARN(TAG,
"TS_UD_SC_CORE::EarlyCapabilityFlags [0x%08" PRIx32 " & 0x%08" PRIx32
" --> 0x%08" PRIx32 "] filtering %s, feature not implemented",
flags, ~mask, unknown,
rdp_early_server_caps_string(unknown, buffer, sizeof(buffer)));
}
return filtered;
}
static UINT32 earlyServerCapsFromSettings(const rdpSettings* settings)
{
UINT32 EarlyCapabilityFlags = 0;
if (settings->SupportEdgeActionV1)
EarlyCapabilityFlags |= RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1;
if (settings->SupportDynamicTimeZone)
EarlyCapabilityFlags |= RNS_UD_SC_DYNAMIC_DST_SUPPORTED;
if (settings->SupportEdgeActionV2)
EarlyCapabilityFlags |= RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2;
if (settings->SupportSkipChannelJoin)
EarlyCapabilityFlags |= RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED;
return filterAndLogEarlyServerCapabilityFlags(EarlyCapabilityFlags);
}
static UINT16 filterAndLogEarlyClientCapabilityFlags(UINT32 flags)
{
const UINT32 mask =
(RNS_UD_CS_SUPPORT_ERRINFO_PDU | RNS_UD_CS_WANT_32BPP_SESSION |
RNS_UD_CS_SUPPORT_STATUSINFO_PDU | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS |
RNS_UD_CS_RELATIVE_MOUSE_INPUT | RNS_UD_CS_VALID_CONNECTION_TYPE |
RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU | RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT |
RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL | RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE |
RNS_UD_CS_SUPPORT_HEARTBEAT_PDU | RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN);
const UINT32 filtered = flags & mask;
const UINT32 unknown = flags & ~mask;
if (unknown != 0)
{
char buffer[256] = { 0 };
WLog_WARN(TAG,
"(TS_UD_CS_CORE)::EarlyCapabilityFlags [0x%08" PRIx32 " & 0x%08" PRIx32
" --> 0x%08" PRIx32 "] filtering %s, feature not implemented",
flags, ~mask, unknown,
rdp_early_client_caps_string(unknown, buffer, sizeof(buffer)));
}
return filtered;
}
static UINT16 earlyClientCapsFromSettings(const rdpSettings* settings)
{
UINT32 earlyCapabilityFlags = 0;
WINPR_ASSERT(settings);
if (settings->SupportErrorInfoPdu)
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_ERRINFO_PDU;
if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) == 32)
earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
if (settings->SupportStatusInfoPdu)
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_STATUSINFO_PDU;
if (settings->ConnectionType)
earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
if (settings->SupportMonitorLayoutPdu)
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU;
if (freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect))
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT;
if (settings->SupportGraphicsPipeline)
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL;
if (settings->SupportDynamicTimeZone)
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE;
if (settings->SupportHeartbeatPdu)
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_HEARTBEAT_PDU;
if (settings->SupportAsymetricKeys)
earlyCapabilityFlags |= RNS_UD_CS_STRONG_ASYMMETRIC_KEYS;
if (settings->HasRelativeMouseEvent)
earlyCapabilityFlags |= RNS_UD_CS_RELATIVE_MOUSE_INPUT;
if (settings->SupportSkipChannelJoin)
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN;
return filterAndLogEarlyClientCapabilityFlags(earlyCapabilityFlags);
}
static BOOL updateEarlyClientCaps(rdpSettings* settings, UINT32 earlyCapabilityFlags,
UINT32 connectionType)
{
WINPR_ASSERT(settings);
if (settings->SupportErrorInfoPdu)
settings->SupportErrorInfoPdu =
(earlyCapabilityFlags & RNS_UD_CS_SUPPORT_ERRINFO_PDU) ? TRUE : FALSE;
/* RNS_UD_CS_WANT_32BPP_SESSION is already handled in gcc_read_client_core_data:
*
* it is evaluated in combination with highColorDepth and the server side
* settings to determine the session color depth to use.
*/
if (settings->SupportStatusInfoPdu)
settings->SupportStatusInfoPdu =
(earlyCapabilityFlags & RNS_UD_CS_SUPPORT_STATUSINFO_PDU) ? TRUE : FALSE;
if (settings->SupportAsymetricKeys)
settings->SupportAsymetricKeys =
(earlyCapabilityFlags & RNS_UD_CS_STRONG_ASYMMETRIC_KEYS) ? TRUE : FALSE;
if (settings->HasRelativeMouseEvent)
settings->HasRelativeMouseEvent =
(earlyCapabilityFlags & RNS_UD_CS_RELATIVE_MOUSE_INPUT) ? TRUE : FALSE;
if (settings->NetworkAutoDetect)
settings->NetworkAutoDetect =
(earlyCapabilityFlags & RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT) ? TRUE : FALSE;
if (settings->SupportSkipChannelJoin)
settings->SupportSkipChannelJoin =
(earlyCapabilityFlags & RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN) ? TRUE : FALSE;
if (settings->SupportMonitorLayoutPdu)
settings->SupportMonitorLayoutPdu =
(earlyCapabilityFlags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) ? TRUE : FALSE;
if (settings->SupportHeartbeatPdu)
settings->SupportHeartbeatPdu =
(earlyCapabilityFlags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU) ? TRUE : FALSE;
if (settings->SupportGraphicsPipeline)
settings->SupportGraphicsPipeline =
(earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) ? TRUE : FALSE;
if (settings->SupportDynamicTimeZone)
settings->SupportDynamicTimeZone =
(earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE) ? TRUE : FALSE;
if ((earlyCapabilityFlags & RNS_UD_CS_VALID_CONNECTION_TYPE) == 0)
connectionType = 0;
settings->ConnectionType = connectionType;
filterAndLogEarlyClientCapabilityFlags(earlyCapabilityFlags);
return TRUE;
}
static BOOL updateEarlyServerCaps(rdpSettings* settings, UINT32 earlyCapabilityFlags,
UINT32 connectionType)
{
WINPR_ASSERT(settings);
settings->SupportEdgeActionV1 =
settings->SupportEdgeActionV1 &&
(earlyCapabilityFlags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1)
? TRUE
: FALSE;
settings->SupportDynamicTimeZone =
settings->SupportDynamicTimeZone && (earlyCapabilityFlags & RNS_UD_SC_DYNAMIC_DST_SUPPORTED)
? TRUE
: FALSE;
settings->SupportEdgeActionV2 =
settings->SupportEdgeActionV2 &&
(earlyCapabilityFlags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2)
? TRUE
: FALSE;
settings->SupportSkipChannelJoin =
settings->SupportSkipChannelJoin &&
(earlyCapabilityFlags & RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED)
? TRUE
: FALSE;
filterAndLogEarlyServerCapabilityFlags(earlyCapabilityFlags);
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Read a client core data block (TS_UD_CS_CORE).
* msdn{cc240510}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs)
{
char buffer[2048] = { 0 };
char strbuffer[130] = { 0 };
UINT32 version = 0;
BYTE connectionType = 0;
UINT32 clientColorDepth = 0;
UINT16 colorDepth = 0;
UINT16 postBeta2ColorDepth = 0;
UINT16 highColorDepth = 0;
2012-10-09 11:26:39 +04:00
UINT32 serverSelectedProtocol = 0;
rdpSettings* settings = mcs_get_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
size_t blockLength = Stream_GetRemainingLength(s);
/* Length of all required fields, until imeFileName */
if (blockLength < 128)
return FALSE;
Stream_Read_UINT32(s, version); /* version (4 bytes) */
2018-11-14 12:14:48 +03:00
settings->RdpVersion = rdp_version_common(version, settings->RdpVersion);
2019-11-06 17:24:51 +03:00
Stream_Read_UINT16(s, settings->DesktopWidth); /* DesktopWidth (2 bytes) */
Stream_Read_UINT16(s, settings->DesktopHeight); /* DesktopHeight (2 bytes) */
2019-11-06 17:24:51 +03:00
Stream_Read_UINT16(s, colorDepth); /* ColorDepth (2 bytes) */
Stream_Seek_UINT16(s); /* SASSequence (Secure Access Sequence) (2 bytes) */
Stream_Read_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout (4 bytes) */
2019-11-06 17:24:51 +03:00
Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild (4 bytes) */
/* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
if (Stream_Read_UTF16_String_As_UTF8_Buffer(s, 32 / sizeof(WCHAR), strbuffer,
ARRAYSIZE(strbuffer)) < 0)
{
WLog_ERR(TAG, "failed to convert client host name");
return FALSE;
}
2016-09-20 09:58:04 +03:00
if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, strbuffer))
return FALSE;
2019-11-06 17:24:51 +03:00
Stream_Read_UINT32(s, settings->KeyboardType); /* KeyboardType (4 bytes) */
Stream_Read_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType (4 bytes) */
Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey (4 bytes) */
Stream_Seek(s, 64); /* imeFileName (64 bytes) */
blockLength -= 128;
/**
* The following fields are all optional. If one field is present, all of the preceding
* fields MUST also be present. If one field is not present, all of the subsequent fields
* MUST NOT be present.
* We must check the bytes left before reading each field.
*/
do
{
UINT16 clientProductIdLen = 0;
if (blockLength < 2)
break;
2016-09-20 09:58:04 +03:00
Stream_Read_UINT16(s, postBeta2ColorDepth); /* postBeta2ColorDepth (2 bytes) */
blockLength -= 2;
if (blockLength < 2)
break;
2016-09-20 09:58:04 +03:00
Stream_Read_UINT16(s, clientProductIdLen); /* clientProductID (2 bytes) */
blockLength -= 2;
if (blockLength < 4)
break;
2016-09-20 09:58:04 +03:00
Stream_Seek_UINT32(s); /* serialNumber (4 bytes) */
blockLength -= 4;
if (blockLength < 2)
break;
2016-09-20 09:58:04 +03:00
Stream_Read_UINT16(s, highColorDepth); /* highColorDepth (2 bytes) */
blockLength -= 2;
if (blockLength < 2)
break;
2016-09-20 09:58:04 +03:00
Stream_Read_UINT16(s, settings->SupportedColorDepths); /* supportedColorDepths (2 bytes) */
blockLength -= 2;
if (blockLength < 2)
break;
2016-09-20 09:58:04 +03:00
Stream_Read_UINT16(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags (2 bytes) */
blockLength -= 2;
/* clientDigProductId (64 bytes): Contains a value that uniquely identifies the client */
if (blockLength < 64)
break;
if (Stream_Read_UTF16_String_As_UTF8_Buffer(s, 64 / sizeof(WCHAR), strbuffer,
ARRAYSIZE(strbuffer)) < 0)
{
WLog_ERR(TAG, "failed to convert the client product identifier");
return FALSE;
}
2016-09-20 09:58:04 +03:00
if (!freerdp_settings_set_string(settings, FreeRDP_ClientProductId, strbuffer))
return FALSE;
blockLength -= 64;
if (blockLength < 1)
break;
2016-09-20 09:58:04 +03:00
Stream_Read_UINT8(s, connectionType); /* connectionType (1 byte) */
blockLength -= 1;
if (blockLength < 1)
break;
2016-09-20 09:58:04 +03:00
Stream_Seek_UINT8(s); /* pad1octet (1 byte) */
blockLength -= 1;
if (blockLength < 4)
break;
2016-09-20 09:58:04 +03:00
2019-11-06 17:24:51 +03:00
Stream_Read_UINT32(s, serverSelectedProtocol); /* serverSelectedProtocol (4 bytes) */
blockLength -= 4;
if (blockLength < 4)
break;
2016-09-20 09:58:04 +03:00
2019-11-06 17:24:51 +03:00
Stream_Read_UINT32(s, settings->DesktopPhysicalWidth); /* desktopPhysicalWidth (4 bytes) */
blockLength -= 4;
if (blockLength < 4)
break;
2016-09-20 09:58:04 +03:00
Stream_Read_UINT32(s,
settings->DesktopPhysicalHeight); /* desktopPhysicalHeight (4 bytes) */
blockLength -= 4;
if (blockLength < 2)
break;
2016-09-20 09:58:04 +03:00
2019-11-06 17:24:51 +03:00
Stream_Read_UINT16(s, settings->DesktopOrientation); /* desktopOrientation (2 bytes) */
blockLength -= 2;
if (blockLength < 4)
break;
2016-09-20 09:58:04 +03:00
2019-11-06 17:24:51 +03:00
Stream_Read_UINT32(s, settings->DesktopScaleFactor); /* desktopScaleFactor (4 bytes) */
blockLength -= 4;
if (blockLength < 4)
break;
2016-09-20 09:58:04 +03:00
2019-11-06 17:24:51 +03:00
Stream_Read_UINT32(s, settings->DeviceScaleFactor); /* deviceScaleFactor (4 bytes) */
if (freerdp_settings_get_bool(settings, FreeRDP_TransportDumpReplay))
settings->SelectedProtocol = serverSelectedProtocol;
else if (settings->SelectedProtocol != serverSelectedProtocol)
return FALSE;
2019-11-06 17:24:51 +03:00
} while (0);
if (highColorDepth > 0)
{
if (settings->EarlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION)
clientColorDepth = 32;
else
clientColorDepth = highColorDepth;
}
else if (postBeta2ColorDepth > 0)
{
switch (postBeta2ColorDepth)
{
case RNS_UD_COLOR_4BPP:
clientColorDepth = 4;
break;
2016-09-20 09:58:04 +03:00
case RNS_UD_COLOR_8BPP:
clientColorDepth = 8;
break;
2016-09-20 09:58:04 +03:00
case RNS_UD_COLOR_16BPP_555:
clientColorDepth = 15;
break;
2016-09-20 09:58:04 +03:00
case RNS_UD_COLOR_16BPP_565:
clientColorDepth = 16;
break;
2016-09-20 09:58:04 +03:00
case RNS_UD_COLOR_24BPP:
clientColorDepth = 24;
break;
2016-09-20 09:58:04 +03:00
default:
return FALSE;
}
}
else
{
switch (colorDepth)
{
case RNS_UD_COLOR_4BPP:
clientColorDepth = 4;
break;
2016-09-20 09:58:04 +03:00
case RNS_UD_COLOR_8BPP:
clientColorDepth = 8;
break;
2016-09-20 09:58:04 +03:00
default:
return FALSE;
}
}
/*
* If we are in server mode, accept client's color depth only if
* it is smaller than ours. This is what Windows server does.
*/
if ((clientColorDepth < freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth)) ||
!settings->ServerMode)
{
if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, clientColorDepth))
return FALSE;
}
WLog_DBG(TAG, "Received EarlyCapabilityFlags=%s",
rdp_early_client_caps_string(settings->EarlyCapabilityFlags, buffer, sizeof(buffer)));
return updateEarlyClientCaps(settings, settings->EarlyCapabilityFlags, connectionType);
}
/**
2022-12-09 16:35:03 +03:00
* Write a client core data block (TS_UD_CS_CORE).
* msdn{cc240510}
* @param s The stream to write to
* @param mcs The MSC instance to get the data from
*
* @return \b TRUE for success, \b FALSE otherwise
*/
BOOL gcc_write_client_core_data(wStream* s, const rdpMcs* mcs)
{
char buffer[2048] = { 0 };
char dbuffer[2048] = { 0 };
BYTE connectionType = 0;
HIGH_COLOR_DEPTH highColorDepth = HIGH_COLOR_4BPP;
UINT16 earlyCapabilityFlags = 0;
const rdpSettings* settings = mcs_get_const_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
const UINT16 SupportedColorDepths =
freerdp_settings_get_uint16(settings, FreeRDP_SupportedColorDepths);
const UINT32 ColorDepth = freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, CS_CORE, 234))
return FALSE;
2019-11-06 17:24:51 +03:00
Stream_Write_UINT32(s, settings->RdpVersion); /* Version */
Stream_Write_UINT16(s, settings->DesktopWidth); /* DesktopWidth */
2013-05-09 00:09:16 +04:00
Stream_Write_UINT16(s, settings->DesktopHeight); /* DesktopHeight */
2016-09-20 09:58:04 +03:00
Stream_Write_UINT16(s,
RNS_UD_COLOR_8BPP); /* ColorDepth, ignored because of postBeta2ColorDepth */
2019-11-06 17:24:51 +03:00
Stream_Write_UINT16(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout */
2019-11-06 17:24:51 +03:00
Stream_Write_UINT32(s, settings->ClientBuild); /* ClientBuild */
2024-08-07 10:24:56 +03:00
if (!Stream_EnsureRemainingCapacity(s, 32 + 12 + 64 + 8))
return FALSE;
2024-08-07 10:24:56 +03:00
/* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
size_t clientNameLength = 0;
WCHAR* clientName = ConvertUtf8ToWCharAlloc(settings->ClientHostname, &clientNameLength);
if (clientNameLength >= 16)
{
clientNameLength = 16;
clientName[clientNameLength - 1] = 0;
}
2013-05-09 00:09:16 +04:00
Stream_Write(s, clientName, (clientNameLength * 2));
2013-05-09 00:27:21 +04:00
Stream_Zero(s, 32 - (clientNameLength * 2));
free(clientName);
2019-11-06 17:24:51 +03:00
Stream_Write_UINT32(s, settings->KeyboardType); /* KeyboardType */
Stream_Write_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType */
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey */
2019-11-06 17:24:51 +03:00
Stream_Zero(s, 64); /* imeFileName */
Stream_Write_UINT16(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
Stream_Write_UINT16(s, 1); /* clientProductID */
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(s, 0); /* serialNumber (should be initialized to 0) */
highColorDepth = ColorDepthToHighColor(ColorDepth);
earlyCapabilityFlags = earlyClientCapsFromSettings(settings);
connectionType = settings->ConnectionType;
2020-11-18 09:51:45 +03:00
if (!Stream_EnsureRemainingCapacity(s, 6))
return FALSE;
WLog_DBG(TAG, "Sending highColorDepth=%s, supportedColorDepths=%s, earlyCapabilityFlags=%s",
HighColorToString(highColorDepth),
freerdp_supported_color_depths_string(SupportedColorDepths, dbuffer, sizeof(dbuffer)),
rdp_early_client_caps_string(earlyCapabilityFlags, buffer, sizeof(buffer)));
2019-11-06 17:24:51 +03:00
Stream_Write_UINT16(s, highColorDepth); /* highColorDepth */
Stream_Write_UINT16(s, SupportedColorDepths); /* supportedColorDepths */
2013-05-09 00:09:16 +04:00
Stream_Write_UINT16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
2024-08-07 10:24:56 +03:00
if (!Stream_EnsureRemainingCapacity(s, 64 + 24))
return FALSE;
/* clientDigProductId (64 bytes, null-terminated unicode, truncated to 31 characters) */
2024-08-07 10:24:56 +03:00
size_t clientDigProductIdLength = 0;
WCHAR* clientDigProductId =
ConvertUtf8ToWCharAlloc(settings->ClientProductId, &clientDigProductIdLength);
if (clientDigProductIdLength >= 32)
{
clientDigProductIdLength = 32;
clientDigProductId[clientDigProductIdLength - 1] = 0;
}
2016-09-20 09:58:04 +03:00
Stream_Write(s, clientDigProductId, (clientDigProductIdLength * 2));
Stream_Zero(s, 64 - (clientDigProductIdLength * 2));
free(clientDigProductId);
2019-11-06 17:24:51 +03:00
Stream_Write_UINT8(s, connectionType); /* connectionType */
Stream_Write_UINT8(s, 0); /* pad1octet */
Stream_Write_UINT32(s, settings->SelectedProtocol); /* serverSelectedProtocol */
Stream_Write_UINT32(s, settings->DesktopPhysicalWidth); /* desktopPhysicalWidth */
Stream_Write_UINT32(s, settings->DesktopPhysicalHeight); /* desktopPhysicalHeight */
Stream_Write_UINT16(s, settings->DesktopOrientation); /* desktopOrientation */
Stream_Write_UINT32(s, settings->DesktopScaleFactor); /* desktopScaleFactor */
Stream_Write_UINT32(s, settings->DeviceScaleFactor); /* deviceScaleFactor */
2020-11-18 09:51:45 +03:00
return TRUE;
}
BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs)
{
UINT32 serverVersion = 0;
rdpSettings* settings = mcs_get_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return FALSE;
2018-11-14 12:14:48 +03:00
Stream_Read_UINT32(s, serverVersion); /* version */
settings->RdpVersion = rdp_version_common(serverVersion, settings->RdpVersion);
if (Stream_GetRemainingLength(s) >= 4)
{
Stream_Read_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols */
}
if (Stream_GetRemainingLength(s) >= 4)
{
char buffer[2048] = { 0 };
Stream_Read_UINT32(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags */
WLog_DBG(
TAG, "Received EarlyCapabilityFlags=%s",
rdp_early_client_caps_string(settings->EarlyCapabilityFlags, buffer, sizeof(buffer)));
}
return updateEarlyServerCaps(settings, settings->EarlyCapabilityFlags,
settings->ConnectionType);
}
/* TODO: This function modifies rdpMcs
* TODO: Split this out of this function
*/
BOOL gcc_write_server_core_data(wStream* s, rdpMcs* mcs)
2011-08-19 19:56:47 +04:00
{
const rdpSettings* settings = mcs_get_const_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, SC_CORE, 16))
2015-04-01 16:11:57 +03:00
return FALSE;
const UINT32 EarlyCapabilityFlags = earlyServerCapsFromSettings(settings);
2019-11-06 17:24:51 +03:00
Stream_Write_UINT32(s, settings->RdpVersion); /* version (4 bytes) */
Stream_Write_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols (4 bytes) */
Stream_Write_UINT32(s, EarlyCapabilityFlags); /* earlyCapabilityFlags (4 bytes) */
2015-04-01 16:11:57 +03:00
return TRUE;
2011-08-19 19:56:47 +04:00
}
/**
2022-12-09 16:35:03 +03:00
* Read a client security data block (TS_UD_CS_SEC).
* msdn{cc240511}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
BOOL gcc_read_client_security_data(wStream* s, rdpMcs* mcs)
{
rdpSettings* settings = mcs_get_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
const size_t blockLength = Stream_GetRemainingLength(s);
if (blockLength < 8)
return FALSE;
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
2014-12-12 04:17:12 +03:00
if (settings->UseRdpSecurityLayer)
{
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
2016-09-20 09:58:04 +03:00
if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(s, settings->EncryptionMethods); /* extEncryptionMethods */
else
Stream_Seek(s, 4);
}
else
{
Stream_Seek(s, 8);
}
2016-09-20 09:58:04 +03:00
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Write a client security data block (TS_UD_CS_SEC).
* msdn{cc240511}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
2020-11-18 09:51:45 +03:00
BOOL gcc_write_client_security_data(wStream* s, const rdpMcs* mcs)
{
const rdpSettings* settings = mcs_get_const_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, CS_SECURITY, 12))
return FALSE;
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
2014-12-12 04:17:12 +03:00
if (settings->UseRdpSecurityLayer)
{
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
2019-11-06 17:24:51 +03:00
Stream_Write_UINT32(s, 0); /* extEncryptionMethods */
}
else
{
/* French locale, disable encryption */
2019-11-06 17:24:51 +03:00
Stream_Write_UINT32(s, 0); /* encryptionMethods */
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(s, settings->EncryptionMethods); /* extEncryptionMethods */
}
2020-11-18 09:51:45 +03:00
return TRUE;
}
BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs)
{
const BYTE* data = NULL;
UINT32 length = 0;
2021-09-06 12:01:36 +03:00
BOOL validCryptoConfig = FALSE;
UINT32 EncryptionMethod = 0;
UINT32 EncryptionLevel = 0;
rdpSettings* settings = mcs_get_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
2021-09-06 12:01:36 +03:00
WINPR_ASSERT(settings);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return FALSE;
Stream_Read_UINT32(s, EncryptionMethod); /* encryptionMethod */
Stream_Read_UINT32(s, EncryptionLevel); /* encryptionLevel */
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
2014-12-12 04:17:12 +03:00
/* Only accept valid/known encryption methods */
switch (EncryptionMethod)
{
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
2014-12-12 04:17:12 +03:00
case ENCRYPTION_METHOD_NONE:
WLog_DBG(TAG, "Server rdp encryption method: NONE");
break;
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
case ENCRYPTION_METHOD_40BIT:
WLog_DBG(TAG, "Server rdp encryption method: 40BIT");
break;
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
case ENCRYPTION_METHOD_56BIT:
WLog_DBG(TAG, "Server rdp encryption method: 56BIT");
break;
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
case ENCRYPTION_METHOD_128BIT:
WLog_DBG(TAG, "Server rdp encryption method: 128BIT");
break;
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
case ENCRYPTION_METHOD_FIPS:
WLog_DBG(TAG, "Server rdp encryption method: FIPS");
break;
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
default:
WLog_ERR(TAG, "Received unknown encryption method %08" PRIX32 "", EncryptionMethod);
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
2014-12-12 04:17:12 +03:00
return FALSE;
}
if (settings->UseRdpSecurityLayer && !(settings->EncryptionMethods & EncryptionMethod))
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
2014-12-12 04:17:12 +03:00
{
2019-11-06 17:24:51 +03:00
WLog_WARN(TAG, "Server uses non-advertised encryption method 0x%08" PRIX32 "",
EncryptionMethod);
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
2014-12-12 04:17:12 +03:00
/* FIXME: Should we return FALSE; in this case ?? */
}
settings->EncryptionMethods = EncryptionMethod;
settings->EncryptionLevel = EncryptionLevel;
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
2014-12-12 04:17:12 +03:00
/* 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;
}
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
break;
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
case ENCRYPTION_LEVEL_FIPS:
if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
{
validCryptoConfig = TRUE;
}
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
break;
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
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;
}
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
break;
2016-09-20 09:58:04 +03:00
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
2014-12-12 04:17:12 +03:00
default:
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "Received unknown encryption level 0x%08" PRIX32 "",
2016-09-20 09:58:04 +03:00
settings->EncryptionLevel);
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
2014-12-12 04:17:12 +03:00
}
if (!validCryptoConfig)
{
2016-09-20 09:58:04 +03:00
WLog_ERR(TAG,
2019-11-06 17:24:51 +03:00
"Received invalid cryptographic configuration (level=0x%08" PRIX32
" method=0x%08" PRIX32 ")",
2016-09-20 09:58:04 +03:00
settings->EncryptionLevel, settings->EncryptionMethods);
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
2014-12-12 04:17:12 +03:00
return FALSE;
}
if (settings->EncryptionLevel == ENCRYPTION_LEVEL_NONE)
{
/* serverRandomLen and serverCertLen must not be present */
settings->UseRdpSecurityLayer = FALSE;
return TRUE;
}
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return FALSE;
2019-11-06 17:24:51 +03:00
Stream_Read_UINT32(s, settings->ServerRandomLength); /* serverRandomLen */
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(s, settings->ServerCertificateLength); /* serverCertLen */
if ((settings->ServerRandomLength == 0) || (settings->ServerCertificateLength == 0))
{
WLog_ERR(TAG,
"Invalid ServerRandom (length=%" PRIu32 ") or ServerCertificate (length=%" PRIu32
")",
settings->ServerRandomLength, settings->ServerCertificateLength);
return FALSE;
}
if (!Stream_CheckAndLogRequiredLength(TAG, s, settings->ServerRandomLength))
return FALSE;
/* serverRandom */
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerRandom, NULL,
2022-06-23 08:57:38 +03:00
settings->ServerRandomLength))
goto fail;
2016-09-20 09:58:04 +03:00
Stream_Read(s, settings->ServerRandom, settings->ServerRandomLength);
if (!Stream_CheckAndLogRequiredLength(TAG, s, settings->ServerCertificateLength))
goto fail;
/* serverCertificate */
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerCertificate, NULL,
2022-06-23 08:57:38 +03:00
settings->ServerCertificateLength))
goto fail;
2016-09-20 09:58:04 +03:00
Stream_Read(s, settings->ServerCertificate, settings->ServerCertificateLength);
data = settings->ServerCertificate;
length = settings->ServerCertificateLength;
2017-11-14 15:58:31 +03:00
2023-02-03 13:53:49 +03:00
if (!freerdp_certificate_read_server_cert(settings->RdpServerCertificate, data, length))
goto fail;
return TRUE;
fail:
2017-11-14 15:58:31 +03:00
free(settings->ServerRandom);
free(settings->ServerCertificate);
settings->ServerRandom = NULL;
settings->ServerCertificate = NULL;
return FALSE;
}
static BOOL gcc_update_server_random(rdpSettings* settings)
{
const size_t length = 32;
WINPR_ASSERT(settings);
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerRandom, NULL, length))
return FALSE;
2023-01-30 14:18:35 +03:00
BYTE* data = freerdp_settings_get_pointer_writable(settings, FreeRDP_ServerRandom);
if (!data)
return FALSE;
winpr_RAND(data, length);
return TRUE;
}
/* TODO: This function does manipulate data in rdpMcs
* TODO: Split this out of this function
*/
BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs)
2011-08-19 19:56:47 +04:00
{
if (!gcc_update_server_random(mcs_get_settings(mcs)))
return FALSE;
const rdpSettings* settings = mcs_get_const_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
const size_t posHeader = Stream_GetPosition(s);
if (!gcc_write_user_data_header(s, SC_SECURITY, 12))
2015-04-01 16:11:57 +03:00
return FALSE;
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethod */
2019-11-06 17:24:51 +03:00
Stream_Write_UINT32(s, settings->EncryptionLevel); /* encryptionLevel */
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
2014-12-12 04:17:12 +03:00
if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
2015-04-01 16:11:57 +03:00
return TRUE;
2023-01-28 14:48:00 +03:00
if (!Stream_EnsureRemainingCapacity(s, sizeof(UINT32) + settings->ServerRandomLength))
return FALSE;
Stream_Write_UINT32(s, settings->ServerRandomLength); /* serverRandomLen */
const size_t posCertLen = Stream_GetPosition(s);
Stream_Seek_UINT32(s); /* serverCertLen */
2023-01-28 14:48:00 +03:00
Stream_Write(s, settings->ServerRandom, settings->ServerRandomLength);
2017-11-14 15:58:31 +03:00
2023-02-03 13:53:49 +03:00
const SSIZE_T len = freerdp_certificate_write_server_cert(
2023-01-30 14:18:35 +03:00
settings->RdpServerCertificate, CERT_TEMPORARILY_ISSUED | CERT_CHAIN_VERSION_1, s);
if (len < 0)
2017-09-26 10:20:38 +03:00
return FALSE;
const size_t end = Stream_GetPosition(s);
Stream_SetPosition(s, posHeader);
if (!gcc_write_user_data_header(s, SC_SECURITY, end - posHeader))
return FALSE;
Stream_SetPosition(s, posCertLen);
WINPR_ASSERT(len <= UINT32_MAX);
Stream_Write_UINT32(s, (UINT32)len);
Stream_SetPosition(s, end);
2015-04-01 16:11:57 +03:00
return TRUE;
2011-08-19 19:56:47 +04:00
}
/**
2022-12-09 16:35:03 +03:00
* Read a client network data block (TS_UD_CS_NET).
* msdn{cc240512}
*
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
BOOL gcc_read_client_network_data(wStream* s, rdpMcs* mcs)
{
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
const size_t blockLength = Stream_GetRemainingLength(s);
if (blockLength < 4)
return FALSE;
Stream_Read_UINT32(s, mcs->channelCount); /* channelCount */
2014-02-11 07:12:13 +04:00
if (blockLength < 4 + mcs->channelCount * 12)
return FALSE;
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
2014-12-12 04:17:12 +03:00
if (mcs->channelCount > CHANNEL_MAX_COUNT)
return FALSE;
/* channelDefArray */
for (UINT32 i = 0; i < mcs->channelCount; i++)
{
/**
* CHANNEL_DEF
* - name: an 8-byte array containing a null-terminated collection
* of seven ANSI characters that uniquely identify the channel.
* - options: a 32-bit, unsigned integer. Channel option flags
*/
rdpMcsChannel* channel = &mcs->channels[i];
Stream_Read(s, channel->Name, CHANNEL_NAME_LEN + 1); /* name (8 bytes) */
2016-09-20 09:58:04 +03:00
if (!memchr(channel->Name, 0, CHANNEL_NAME_LEN + 1))
{
2019-11-06 17:24:51 +03:00
WLog_ERR(
TAG,
"protocol violation: received a static channel name with missing null-termination");
return FALSE;
}
2016-09-20 09:58:04 +03:00
Stream_Read_UINT32(s, channel->options); /* options (4 bytes) */
channel->ChannelId = mcs->baseChannelId++;
}
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Write a client network data block (TS_UD_CS_NET).
* msdn{cc240512}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS to use
*
* @return \b TRUE for success, \b FALSE otherwise
*/
2020-11-18 09:51:45 +03:00
BOOL gcc_write_client_network_data(wStream* s, const rdpMcs* mcs)
{
UINT16 length = 0;
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
if (mcs->channelCount > 0)
{
length = mcs->channelCount * 12 + 8;
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, CS_NET, length))
return FALSE;
Stream_Write_UINT32(s, mcs->channelCount); /* channelCount */
/* channelDefArray */
for (UINT32 i = 0; i < mcs->channelCount; i++)
{
/* CHANNEL_DEF */
rdpMcsChannel* channel = &mcs->channels[i];
Stream_Write(s, channel->Name, CHANNEL_NAME_LEN + 1); /* name (8 bytes) */
Stream_Write_UINT32(s, channel->options); /* options (4 bytes) */
}
}
2020-11-18 09:51:45 +03:00
return TRUE;
}
BOOL gcc_read_server_network_data(wStream* s, rdpMcs* mcs)
{
UINT16 channelId = 0;
UINT16 MCSChannelId = 0;
UINT16 channelCount = 0;
UINT32 parsedChannelCount = 0;
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return FALSE;
2013-05-09 00:09:16 +04:00
Stream_Read_UINT16(s, MCSChannelId); /* MCSChannelId */
Stream_Read_UINT16(s, channelCount); /* channelCount */
parsedChannelCount = channelCount;
if (channelCount != mcs->channelCount)
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "requested %" PRIu32 " channels, got %" PRIu16 " instead", mcs->channelCount,
channelCount);
/* we ensure that the response is not bigger than the request */
mcs->channelCount = channelCount;
}
if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, channelCount, 2ull))
return FALSE;
if (mcs->channelMaxCount < parsedChannelCount)
{
WLog_ERR(TAG, "requested %" PRIu32 " channels > channelMaxCount %" PRIu16,
mcs->channelCount, mcs->channelMaxCount);
return FALSE;
}
2023-01-20 11:03:16 +03:00
for (UINT32 i = 0; i < parsedChannelCount; i++)
{
rdpMcsChannel* channel = &mcs->channels[i];
2013-05-09 00:09:16 +04:00
Stream_Read_UINT16(s, channelId); /* channelId */
channel->ChannelId = channelId;
}
if (channelCount % 2 == 1)
2013-05-09 01:48:30 +04:00
return Stream_SafeSeek(s, 2); /* padding */
return TRUE;
}
2020-11-18 09:51:45 +03:00
BOOL gcc_write_server_network_data(wStream* s, const rdpMcs* mcs)
2011-08-19 19:56:47 +04:00
{
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
2020-11-18 09:51:45 +03:00
const size_t payloadLen = 8 + mcs->channelCount * 2 + (mcs->channelCount % 2 == 1 ? 2 : 0);
2015-04-01 16:11:57 +03:00
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, SC_NET, payloadLen))
2015-04-01 16:11:57 +03:00
return FALSE;
2011-08-19 19:56:47 +04:00
2013-05-09 00:09:16 +04:00
Stream_Write_UINT16(s, MCS_GLOBAL_CHANNEL_ID); /* MCSChannelId */
2019-11-06 17:24:51 +03:00
Stream_Write_UINT16(s, mcs->channelCount); /* channelCount */
2011-08-19 19:56:47 +04:00
for (UINT32 i = 0; i < mcs->channelCount; i++)
2011-08-19 19:56:47 +04:00
{
const rdpMcsChannel* channel = &mcs->channels[i];
Stream_Write_UINT16(s, channel->ChannelId);
2011-08-19 19:56:47 +04:00
}
if (mcs->channelCount % 2 == 1)
2013-05-09 00:09:16 +04:00
Stream_Write_UINT16(s, 0);
2016-09-20 09:58:04 +03:00
2015-04-01 16:11:57 +03:00
return TRUE;
2011-08-19 19:56:47 +04:00
}
/**
2022-12-09 16:35:03 +03:00
* Read a client cluster data block (TS_UD_CS_CLUSTER).
* msdn{cc240514}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
BOOL gcc_read_client_cluster_data(wStream* s, rdpMcs* mcs)
{
char buffer[128] = { 0 };
UINT32 redirectedSessionId = 0;
rdpSettings* settings = mcs_get_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
const size_t blockLength = Stream_GetRemainingLength(s);
if (blockLength < 8)
return FALSE;
Stream_Read_UINT32(s, settings->ClusterInfoFlags); /* flags */
Stream_Read_UINT32(s, redirectedSessionId); /* redirectedSessionId */
WLog_VRB(TAG, "read ClusterInfoFlags=%s, RedirectedSessionId=0x%08" PRIx32,
rdp_cluster_info_flags_to_string(settings->ClusterInfoFlags, buffer, sizeof(buffer)),
redirectedSessionId);
if (settings->ClusterInfoFlags & REDIRECTED_SESSIONID_FIELD_VALID)
settings->RedirectedSessionId = redirectedSessionId;
settings->ConsoleSession =
(settings->ClusterInfoFlags & REDIRECTED_SESSIONID_FIELD_VALID) ? TRUE : FALSE;
settings->RedirectSmartCards =
(settings->ClusterInfoFlags & REDIRECTED_SMARTCARD) ? TRUE : FALSE;
2024-09-03 11:38:12 +03:00
if (blockLength > 8ULL)
{
2024-09-03 11:38:12 +03:00
if (Stream_GetRemainingLength(s) >= (blockLength - 8ULL))
{
/* The old Microsoft Mac RDP client can send a pad here */
Stream_Seek(s, (blockLength - 8));
}
}
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Write a client cluster data block (TS_UD_CS_CLUSTER).
* msdn{cc240514}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
2020-11-18 09:51:45 +03:00
BOOL gcc_write_client_cluster_data(wStream* s, const rdpMcs* mcs)
{
char buffer[128] = { 0 };
UINT32 flags = 0;
const rdpSettings* settings = mcs_get_const_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, CS_CLUSTER, 12))
return FALSE;
flags = settings->ClusterInfoFlags;
if (settings->ConsoleSession || settings->RedirectedSessionId)
flags |= REDIRECTED_SESSIONID_FIELD_VALID;
if (settings->RedirectSmartCards && settings->SmartcardLogon)
flags |= REDIRECTED_SMARTCARD;
if (flags & REDIRECTION_SUPPORTED)
{
/* REDIRECTION_VERSION6 requires multitransport enabled.
* if we run without that use REDIRECTION_VERSION5 */
if (freerdp_settings_get_bool(settings, FreeRDP_SupportMultitransport))
flags |= (REDIRECTION_VERSION6 << 2);
else
flags |= (REDIRECTION_VERSION5 << 2);
}
WLog_VRB(TAG, "write ClusterInfoFlags=%s, RedirectedSessionId=0x%08" PRIx32,
rdp_cluster_info_flags_to_string(flags, buffer, sizeof(buffer)),
settings->RedirectedSessionId);
2019-11-06 17:24:51 +03:00
Stream_Write_UINT32(s, flags); /* flags */
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(s, settings->RedirectedSessionId); /* redirectedSessionID */
2020-11-18 09:51:45 +03:00
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Read a client monitor data block (TS_UD_CS_MONITOR).
* msdn{dd305336}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
BOOL gcc_read_client_monitor_data(wStream* s, rdpMcs* mcs)
{
UINT32 monitorCount = 0;
rdpSettings* settings = mcs_get_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
const size_t blockLength = Stream_GetRemainingLength(s);
if (blockLength < 8)
return FALSE;
Stream_Read_UINT32(s, settings->MonitorFlags); /* flags */
Stream_Read_UINT32(s, monitorCount); /* monitorCount */
/* 2.2.1.3.6 Client Monitor Data -
* monitorCount (4 bytes): A 32-bit, unsigned integer. The number of display
* monitor definitions in the monitorDefArray field (the maximum allowed is 16).
*/
if (monitorCount > 16)
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "announced monitors(%" PRIu32 ") exceed the 16 limit", monitorCount);
return FALSE;
}
if (monitorCount > settings->MonitorDefArraySize)
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "too many announced monitors(%" PRIu32 "), clamping to %" PRIu32 "",
monitorCount, settings->MonitorDefArraySize);
monitorCount = settings->MonitorDefArraySize;
}
2019-11-06 17:24:51 +03:00
if ((UINT32)((blockLength - 8) / 20) < monitorCount)
return FALSE;
settings->MonitorCount = monitorCount;
for (UINT32 index = 0; index < monitorCount; index++)
{
UINT32 left = 0;
UINT32 top = 0;
UINT32 right = 0;
UINT32 bottom = 0;
UINT32 flags = 0;
2021-12-16 14:42:36 +03:00
rdpMonitor* current = &settings->MonitorDefArray[index];
2019-11-06 17:24:51 +03:00
Stream_Read_UINT32(s, left); /* left */
Stream_Read_UINT32(s, top); /* top */
Stream_Read_UINT32(s, right); /* right */
Stream_Read_UINT32(s, bottom); /* bottom */
2019-11-06 17:24:51 +03:00
Stream_Read_UINT32(s, flags); /* flags */
2021-12-16 14:42:36 +03:00
current->x = left;
current->y = top;
current->width = right - left + 1;
current->height = bottom - top + 1;
current->is_primary = (flags & MONITOR_PRIMARY) ? TRUE : FALSE;
}
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Write a client monitor data block (TS_UD_CS_MONITOR).
* msdn{dd305336}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS to use
*
* @return \b TRUE for success, \b FALSE otherwise
*/
2020-11-18 09:51:45 +03:00
BOOL gcc_write_client_monitor_data(wStream* s, const rdpMcs* mcs)
{
UINT16 length = 0;
INT32 baseX = 0;
INT32 baseY = 0;
const rdpSettings* settings = mcs_get_const_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
WLog_DBG(TAG, "MonitorCount=%" PRIu32, settings->MonitorCount);
if (settings->MonitorCount > 1)
{
length = (20 * settings->MonitorCount) + 12;
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, CS_MONITOR, length))
return FALSE;
Stream_Write_UINT32(s, settings->MonitorFlags); /* flags */
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(s, settings->MonitorCount); /* monitorCount */
/* first pass to get the primary monitor coordinates (it is supposed to be
* in (0,0) */
for (UINT32 i = 0; i < settings->MonitorCount; i++)
{
2021-12-16 14:42:36 +03:00
const rdpMonitor* current = &settings->MonitorDefArray[i];
if (current->is_primary)
{
2021-12-16 14:42:36 +03:00
baseX = current->x;
baseY = current->y;
break;
}
}
for (UINT32 i = 0; i < settings->MonitorCount; i++)
{
2021-12-16 14:42:36 +03:00
const rdpMonitor* current = &settings->MonitorDefArray[i];
const UINT32 left = current->x - baseX;
const UINT32 top = current->y - baseY;
const UINT32 right = left + current->width - 1;
const UINT32 bottom = top + current->height - 1;
const UINT32 flags = current->is_primary ? MONITOR_PRIMARY : 0;
WLog_DBG(TAG,
"Monitor[%" PRIu32 "]: top=%" PRIu32 ", left=%" PRIu32 ", bottom=%" PRIu32
", right=%" PRIu32 ", flags=%" PRIu32,
i, top, left, bottom, right, flags);
2019-11-06 17:24:51 +03:00
Stream_Write_UINT32(s, left); /* left */
Stream_Write_UINT32(s, top); /* top */
Stream_Write_UINT32(s, right); /* right */
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(s, bottom); /* bottom */
2019-11-06 17:24:51 +03:00
Stream_Write_UINT32(s, flags); /* flags */
}
}
WLog_DBG(TAG, "FINISHED");
return TRUE;
}
BOOL gcc_read_client_monitor_extended_data(wStream* s, rdpMcs* mcs)
{
UINT32 monitorCount = 0;
UINT32 monitorAttributeSize = 0;
rdpSettings* settings = mcs_get_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
const size_t blockLength = Stream_GetRemainingLength(s);
if (blockLength < 12)
return FALSE;
Stream_Read_UINT32(s, settings->MonitorAttributeFlags); /* flags */
Stream_Read_UINT32(s, monitorAttributeSize); /* monitorAttributeSize */
Stream_Read_UINT32(s, monitorCount); /* monitorCount */
if (monitorAttributeSize != 20)
return FALSE;
if ((blockLength - 12) / monitorAttributeSize < monitorCount)
return FALSE;
if (settings->MonitorCount != monitorCount)
return FALSE;
settings->HasMonitorAttributes = TRUE;
for (UINT32 index = 0; index < monitorCount; index++)
{
2021-12-16 14:42:36 +03:00
rdpMonitor* current = &settings->MonitorDefArray[index];
Stream_Read_UINT32(s, current->attributes.physicalWidth); /* physicalWidth */
Stream_Read_UINT32(s, current->attributes.physicalHeight); /* physicalHeight */
Stream_Read_UINT32(s, current->attributes.orientation); /* orientation */
Stream_Read_UINT32(s, current->attributes.desktopScaleFactor); /* desktopScaleFactor */
Stream_Read_UINT32(s, current->attributes.deviceScaleFactor); /* deviceScaleFactor */
}
return TRUE;
}
2020-11-18 09:51:45 +03:00
BOOL gcc_write_client_monitor_extended_data(wStream* s, const rdpMcs* mcs)
{
UINT16 length = 0;
const rdpSettings* settings = mcs_get_const_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
if (settings->HasMonitorAttributes)
{
length = (20 * settings->MonitorCount) + 16;
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, CS_MONITOR_EX, length))
return FALSE;
Stream_Write_UINT32(s, settings->MonitorAttributeFlags); /* flags */
Stream_Write_UINT32(s, 20); /* monitorAttributeSize */
Stream_Write_UINT32(s, settings->MonitorCount); /* monitorCount */
for (UINT32 i = 0; i < settings->MonitorCount; i++)
{
2021-12-16 14:42:36 +03:00
const rdpMonitor* current = &settings->MonitorDefArray[i];
Stream_Write_UINT32(s, current->attributes.physicalWidth); /* physicalWidth */
Stream_Write_UINT32(s, current->attributes.physicalHeight); /* physicalHeight */
Stream_Write_UINT32(s, current->attributes.orientation); /* orientation */
Stream_Write_UINT32(s, current->attributes.desktopScaleFactor); /* desktopScaleFactor */
Stream_Write_UINT32(s, current->attributes.deviceScaleFactor); /* deviceScaleFactor */
}
}
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Read a client message channel data block (TS_UD_CS_MCS_MSGCHANNEL).
* msdn{jj217627}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
BOOL gcc_read_client_message_channel_data(wStream* s, rdpMcs* mcs)
{
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
const size_t blockLength = Stream_GetRemainingLength(s);
if (blockLength < 4)
return FALSE;
Stream_Read_UINT32(s, mcs->flags);
mcs->messageChannelId = mcs->baseChannelId++;
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Write a client message channel data block (TS_UD_CS_MCS_MSGCHANNEL).
* msdn{jj217627}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
2020-11-18 09:51:45 +03:00
BOOL gcc_write_client_message_channel_data(wStream* s, const rdpMcs* mcs)
{
const rdpSettings* settings = mcs_get_const_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
WINPR_ASSERT(settings);
if (freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect) ||
settings->SupportHeartbeatPdu || settings->SupportMultitransport)
{
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, CS_MCS_MSGCHANNEL, 8))
return FALSE;
Stream_Write_UINT32(s, mcs->flags); /* flags */
}
2020-11-18 09:51:45 +03:00
return TRUE;
}
BOOL gcc_read_server_message_channel_data(wStream* s, rdpMcs* mcs)
{
UINT16 MCSChannelId = 0;
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
return FALSE;
Stream_Read_UINT16(s, MCSChannelId); /* MCSChannelId */
/* Save the MCS message channel id */
mcs->messageChannelId = MCSChannelId;
return TRUE;
}
2020-11-18 09:51:45 +03:00
BOOL gcc_write_server_message_channel_data(wStream* s, const rdpMcs* mcs)
{
WINPR_ASSERT(s);
WINPR_ASSERT(mcs);
if (mcs->messageChannelId == 0)
2015-04-01 16:11:57 +03:00
return TRUE;
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, SC_MCS_MSGCHANNEL, 6))
2015-04-01 16:11:57 +03:00
return FALSE;
Stream_Write_UINT16(s, mcs->messageChannelId); /* mcsChannelId (2 bytes) */
2015-04-01 16:11:57 +03:00
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Read a client multitransport channel data block (TS_UD_CS_MULTITRANSPORT).
* msdn{jj217498}
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
BOOL gcc_read_client_multitransport_channel_data(wStream* s, rdpMcs* mcs)
{
rdpSettings* settings = mcs_get_settings(mcs);
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
const size_t blockLength = Stream_GetRemainingLength(s);
if (blockLength < 4)
return FALSE;
UINT32 remoteFlags = 0;
Stream_Read_UINT32(s, remoteFlags);
settings->MultitransportFlags &= remoteFlags; /* merge local and remote flags */
return TRUE;
}
/**
2022-12-09 16:35:03 +03:00
* Write a client multitransport channel data block (TS_UD_CS_MULTITRANSPORT).
* msdn{jj217498}
*
* @param s stream
2022-12-09 16:35:03 +03:00
* @param mcs The MCS instance
*
* @return \b TRUE for success, \b FALSE otherwise
*/
2020-11-18 09:51:45 +03:00
BOOL gcc_write_client_multitransport_channel_data(wStream* s, const rdpMcs* mcs)
{
const rdpSettings* settings = mcs_get_const_settings(mcs);
2021-09-03 12:31:21 +03:00
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, CS_MULTITRANSPORT, 8))
return FALSE;
Stream_Write_UINT32(s, settings->MultitransportFlags); /* flags */
2020-11-18 09:51:45 +03:00
return TRUE;
}
BOOL gcc_read_server_multitransport_channel_data(wStream* s, rdpMcs* mcs)
{
rdpSettings* settings = mcs_get_settings(mcs);
UINT32 remoteFlags = 0;
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return FALSE;
Stream_Read_UINT32(s, remoteFlags);
settings->MultitransportFlags &= remoteFlags; /* merge with client setting */
return TRUE;
}
2020-11-18 09:51:45 +03:00
BOOL gcc_write_server_multitransport_channel_data(wStream* s, const rdpMcs* mcs)
{
const rdpSettings* settings = mcs_get_const_settings(mcs);
WINPR_ASSERT(s);
WINPR_ASSERT(settings);
2020-11-18 09:51:45 +03:00
if (!gcc_write_user_data_header(s, SC_MULTITRANSPORT, 8))
return FALSE;
Stream_Write_UINT32(s, settings->MultitransportFlags); /* flags (4 bytes) */
2020-11-18 09:51:45 +03:00
return TRUE;
}