From 7e6de563386facc4f0b551d6362c7fe8351c5155 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Sep 2025 14:32:12 +0200 Subject: [PATCH] [core,gateway] automatically accept ARM redirection When using ARM gateway transport auto accept the certificate provided by server response. --- libfreerdp/core/gateway/arm.c | 44 +++++++++++++++++++++-------------- libfreerdp/core/redirection.c | 39 +++++++++++++++++-------------- libfreerdp/core/redirection.h | 2 ++ libfreerdp/crypto/tls.c | 3 +++ 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/libfreerdp/core/gateway/arm.c b/libfreerdp/core/gateway/arm.c index 42e281ee4..a3fd0c347 100644 --- a/libfreerdp/core/gateway/arm.c +++ b/libfreerdp/core/gateway/arm.c @@ -796,12 +796,12 @@ out: return ret; } -static BOOL arm_fill_rdstls(rdpArm* arm, rdpSettings* settings, const WINPR_JSON* json) +static BOOL arm_fill_rdstls(rdpArm* arm, rdpSettings* settings, const WINPR_JSON* json, + const rdpCertificate* redirectedServerCert) { BOOL ret = TRUE; BYTE* cert = NULL; BYTE* authBlob = NULL; - rdpCertificate* redirectedServerCert = NULL; do { @@ -837,14 +837,6 @@ static BOOL arm_fill_rdstls(rdpArm* arm, rdpSettings* settings, const WINPR_JSON goto endOfFunction; } - /* redirectedServerCert */ - size_t certLen = 0; - if (!arm_pick_base64Utf16Field(arm->log, json, "redirectedServerCert", &cert, &certLen)) - break; - - if (!rdp_redirection_read_target_cert(&redirectedServerCert, cert, certLen)) - break; - /* redirectedAuthBlob */ size_t authBlobLen = 0; if (!arm_pick_base64Utf16Field(arm->log, json, "redirectedAuthBlob", &authBlob, @@ -865,7 +857,6 @@ static BOOL arm_fill_rdstls(rdpArm* arm, rdpSettings* settings, const WINPR_JSON } while (FALSE); free(cert); - freerdp_certificate_free(redirectedServerCert); free(authBlob); endOfFunction: @@ -878,6 +869,7 @@ static BOOL arm_fill_gateway_parameters(rdpArm* arm, const char* message, size_t WINPR_ASSERT(arm->context); WINPR_ASSERT(message); + rdpCertificate* redirectedServerCert = NULL; WINPR_JSON* json = WINPR_JSON_ParseWithLength(message, len); BOOL status = FALSE; if (!json) @@ -890,9 +882,7 @@ static BOOL arm_fill_gateway_parameters(rdpArm* arm, const char* message, size_t { WLog_Print(arm->log, WLOG_DEBUG, "extracted target url %s", gwurlstr); if (!freerdp_settings_set_string(settings, FreeRDP_GatewayUrl, gwurlstr)) - status = FALSE; - else - status = TRUE; + goto fail; } WINPR_JSON* serverNameNode = WINPR_JSON_GetObjectItem(json, "redirectedServerName"); @@ -900,7 +890,10 @@ static BOOL arm_fill_gateway_parameters(rdpArm* arm, const char* message, size_t { const char* serverName = WINPR_JSON_GetStringValue(serverNameNode); if (serverName) - status = freerdp_settings_set_string(settings, FreeRDP_ServerHostname, serverName); + { + if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname, serverName)) + goto fail; + } } WINPR_JSON* azureMeta = WINPR_JSON_GetObjectItem(json, "azureInstanceNetworkMetadata"); @@ -910,18 +903,35 @@ static BOOL arm_fill_gateway_parameters(rdpArm* arm, const char* message, size_t settings)) { WLog_Print(arm->log, WLOG_ERROR, "error when treating azureInstanceNetworkMetadata"); + goto fail; } } + /* redirectedServerCert */ + size_t certLen = 0; + BYTE* cert = NULL; + if (arm_pick_base64Utf16Field(arm->log, json, "redirectedServerCert", &cert, &certLen)) + { + const BOOL rc = rdp_redirection_read_target_cert(&redirectedServerCert, cert, certLen); + free(cert); + if (!rc) + goto fail; + else if (!rdp_set_target_certificate(settings, redirectedServerCert)) + goto fail; + } + if (freerdp_settings_get_string(settings, FreeRDP_Password)) { /* note: we retrieve some more fields for RDSTLS only if we have a password provided by the * user, otherwise these are useless: we will not be able to do RDSTLS */ - status = arm_fill_rdstls(arm, settings, json); + status = arm_fill_rdstls(arm, settings, json, redirectedServerCert); } - + else + status = TRUE; +fail: WINPR_JSON_Delete(json); + freerdp_certificate_free(redirectedServerCert); return status; } diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c index e9cdfc6cb..0fe53e1e9 100644 --- a/libfreerdp/core/redirection.c +++ b/libfreerdp/core/redirection.c @@ -453,6 +453,27 @@ static BOOL rdp_redirection_read_target_cert_stream(wStream* s, rdpRedirection* return rc; } +BOOL rdp_set_target_certificate(rdpSettings* settings, const rdpCertificate* tcert) +{ + rdpCertificate* cert = freerdp_certificate_clone(tcert); + if (!freerdp_settings_set_pointer(settings, FreeRDP_RedirectionTargetCertificate, cert)) + return FALSE; + + BOOL pres = FALSE; + size_t length = 0; + char* pem = freerdp_certificate_get_pem(cert, &length); + if (pem && (length <= UINT32_MAX)) + { + pres = + freerdp_settings_set_string_len(settings, FreeRDP_RedirectionAcceptedCert, pem, length); + if (pres) + pres = freerdp_settings_set_uint32(settings, FreeRDP_RedirectionAcceptedCertLength, + (UINT32)length); + } + free(pem); + return pres; +} + int rdp_redirection_apply_settings(rdpRdp* rdp) { rdpSettings* settings = NULL; @@ -610,23 +631,7 @@ int rdp_redirection_apply_settings(rdpRdp* rdp) if (settings->RedirectionFlags & LB_TARGET_CERTIFICATE) { - rdpCertificate* cert = freerdp_certificate_clone(redirection->TargetCertificate); - if (!freerdp_settings_set_pointer(settings, FreeRDP_RedirectionTargetCertificate, cert)) - return -1; - - BOOL pres = FALSE; - size_t length = 0; - char* pem = freerdp_certificate_get_pem(cert, &length); - if (pem && (length <= UINT32_MAX)) - { - pres = freerdp_settings_set_string_len(settings, FreeRDP_RedirectionAcceptedCert, pem, - length); - if (pres) - pres = freerdp_settings_set_uint32(settings, FreeRDP_RedirectionAcceptedCertLength, - (UINT32)length); - } - free(pem); - if (!pres) + if (!rdp_set_target_certificate(settings, redirection->TargetCertificate)) return -1; } diff --git a/libfreerdp/core/redirection.h b/libfreerdp/core/redirection.h index e0c243214..4a69b2bbf 100644 --- a/libfreerdp/core/redirection.h +++ b/libfreerdp/core/redirection.h @@ -45,6 +45,8 @@ rdp_write_enhanced_security_redirection_packet(wStream* s, const rdpRedirection* FREERDP_LOCAL BOOL rdp_redirection_read_target_cert(rdpCertificate** ptargetCertificate, const BYTE* data, size_t length); +FREERDP_LOCAL BOOL rdp_set_target_certificate(rdpSettings* settings, const rdpCertificate* tcert); + #define REDIR_TAG FREERDP_TAG("core.redirection") #ifdef WITH_DEBUG_REDIR #define DEBUG_REDIR(...) WLog_DBG(REDIR_TAG, __VA_ARGS__) diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 683385a2e..5ee6ba319 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -1343,6 +1343,9 @@ static BOOL is_redirected(rdpTls* tls) { rdpSettings* settings = tls->context->settings; + if (settings->GatewayArmTransport) + return TRUE; + if (LB_NOREDIRECT & settings->RedirectionFlags) return FALSE;