From 59b9895bf33d1875eaecdcf37839130ff782adcc Mon Sep 17 00:00:00 2001 From: Pavlo Myroniuk Date: Fri, 14 Nov 2025 15:52:35 +0200 Subject: [PATCH 1/3] fix(devolutions-gateway): ConnectionRequest PDU protocol field: set PROTOCOL_SSL; --- devolutions-gateway/src/rdp_proxy.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/devolutions-gateway/src/rdp_proxy.rs b/devolutions-gateway/src/rdp_proxy.rs index fce931d80..b3213d268 100644 --- a/devolutions-gateway/src/rdp_proxy.rs +++ b/devolutions-gateway/src/rdp_proxy.rs @@ -259,10 +259,10 @@ where // > Credential Security Support Provider protocol (CredSSP) (section 5.4.5.2). // > If this flag is set, then the PROTOCOL_SSL (0x00000001) flag SHOULD also be set // > because Transport Layer Security (TLS) is a subset of CredSSP. - // However, crucially, it’s not strictly required (not "MUST"). - // In fact, we purposefully choose to not set `PROTOCOL_SSL` unless `enable_winlogon` is `true`. - // This tells the server that we are not going to accept downgrading NLA to TLS security. - protocol: nego::SecurityProtocol::HYBRID | nego::SecurityProtocol::HYBRID_EX, + // Crucially, it’s not strictly required (not "MUST"). However, in practice, we cannot set PROTOCOL_HYBRID without PROTOCOL_SSL. + // Otherwise, the `mstsc.exe` will fail right after the CredSSP phase with the "An authentication error has occurred (0x609)" error. + // A similar case: https://serverfault.com/a/720161. + protocol: nego::SecurityProtocol::SSL | nego::SecurityProtocol::HYBRID | nego::SecurityProtocol::HYBRID_EX, }; trace!(?connection_request_to_send, "Send Connection Request PDU to server"); send_pdu(server_framed, &x224::X224(connection_request_to_send)) From 0b1b074762b6baf6a888069637bf59c9c558c2ce Mon Sep 17 00:00:00 2001 From: Pavlo Myroniuk Date: Mon, 1 Dec 2025 16:07:23 +0200 Subject: [PATCH 2/3] feat(devolutions-gateway): clarify protocol flags; --- devolutions-gateway/src/rdp_proxy.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/devolutions-gateway/src/rdp_proxy.rs b/devolutions-gateway/src/rdp_proxy.rs index b3213d268..ff01535e8 100644 --- a/devolutions-gateway/src/rdp_proxy.rs +++ b/devolutions-gateway/src/rdp_proxy.rs @@ -254,14 +254,27 @@ where }, flags: received_connection_request.0.flags, // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/902b090b-9cb3-4efc-92bf-ee13373371e3 - // The spec is stating that `PROTOCOL_SSL` "SHOULD" also be set when using `PROTOCOL_HYBRID`. + // + // The spec states that `PROTOCOL_SSL` "SHOULD" also be set when using `PROTOCOL_HYBRID`: + // // > PROTOCOL_HYBRID (0x00000002) // > Credential Security Support Provider protocol (CredSSP) (section 5.4.5.2). // > If this flag is set, then the PROTOCOL_SSL (0x00000001) flag SHOULD also be set // > because Transport Layer Security (TLS) is a subset of CredSSP. - // Crucially, it’s not strictly required (not "MUST"). However, in practice, we cannot set PROTOCOL_HYBRID without PROTOCOL_SSL. - // Otherwise, the `mstsc.exe` will fail right after the CredSSP phase with the "An authentication error has occurred (0x609)" error. - // A similar case: https://serverfault.com/a/720161. + // + // However, in practice `mstsc` is picky about these flags: it expects the + // SupportedProtocol bits in the ConnectionRequestPDU that reach the target + // server to match what the client originally sent. If the proxy modifies + // them (for example, forcing HYBRID | HYBRID_EX and/or clearing SSL), + // the connection can fail with an authentication error (Code: 0x609). + // + // We therefore *do not* synthesize a new protocol bitmask here anymore. + // Instead, we forward the client's SupportedProtocol flags as-is and + // enforce our policy by validating them: if HYBRID / HYBRID_EX are not + // present (i.e. NLA is not negotiated), we fail the connection rather + // than trying to "fix" the flags ourselves. + // + // See also: https://serverfault.com/a/720161 protocol: nego::SecurityProtocol::SSL | nego::SecurityProtocol::HYBRID | nego::SecurityProtocol::HYBRID_EX, }; trace!(?connection_request_to_send, "Send Connection Request PDU to server"); From 2b6e9080f7fc4beebb6b1543d1d7297bc0dcb072 Mon Sep 17 00:00:00 2001 From: Pavlo Myroniuk Date: Mon, 1 Dec 2025 16:13:55 +0200 Subject: [PATCH 3/3] feat(devolutions-gateway): rdp proxy: forward client protocol flags; --- devolutions-gateway/src/rdp_proxy.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/devolutions-gateway/src/rdp_proxy.rs b/devolutions-gateway/src/rdp_proxy.rs index ff01535e8..da5bf19e7 100644 --- a/devolutions-gateway/src/rdp_proxy.rs +++ b/devolutions-gateway/src/rdp_proxy.rs @@ -227,11 +227,8 @@ where trace!(message = ?received_connection_request, "Received Connection Request PDU from client"); // Choose the security protocol to use with the client. - let client_security_protocol = if received_connection_request - .0 - .protocol - .contains(nego::SecurityProtocol::HYBRID_EX) - { + let received_connection_request_protocol = received_connection_request.0.protocol; + let client_security_protocol = if received_connection_request_protocol.contains(nego::SecurityProtocol::HYBRID_EX) { nego::SecurityProtocol::HYBRID_EX } else if received_connection_request .0 @@ -275,7 +272,7 @@ where // than trying to "fix" the flags ourselves. // // See also: https://serverfault.com/a/720161 - protocol: nego::SecurityProtocol::SSL | nego::SecurityProtocol::HYBRID | nego::SecurityProtocol::HYBRID_EX, + protocol: received_connection_request_protocol, }; trace!(?connection_request_to_send, "Send Connection Request PDU to server"); send_pdu(server_framed, &x224::X224(connection_request_to_send))