From ac51bba8e3264786ad0d818a853de6bd64434085 Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Mon, 1 Jun 2026 14:39:53 +0200 Subject: [PATCH] Improve FIPS mode support Resolves: RHEL-140202 --- ...connection-disable-NTLM-in-FIPS-mode.patch | 50 ++++++ ...on-disable-RDP-Security-in-FIPS-mode.patch | 66 +++++++ ...ppress-expected-FIPS-cipher-warnings.patch | 166 ++++++++++++++++++ freerdp.spec | 12 +- ...-fix-RC4-FIPS-override-for-OpenSSL-3.patch | 66 +++++++ 5 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 core-connection-disable-NTLM-in-FIPS-mode.patch create mode 100644 core-connection-disable-RDP-Security-in-FIPS-mode.patch create mode 100644 core-rdp-suppress-expected-FIPS-cipher-warnings.patch create mode 100644 winpr-crypto-fix-RC4-FIPS-override-for-OpenSSL-3.patch diff --git a/core-connection-disable-NTLM-in-FIPS-mode.patch b/core-connection-disable-NTLM-in-FIPS-mode.patch new file mode 100644 index 0000000..d5b4d98 --- /dev/null +++ b/core-connection-disable-NTLM-in-FIPS-mode.patch @@ -0,0 +1,50 @@ +From e73687cb40d1a94214613ec5cd541cc8f676d55a Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 25 May 2026 11:01:12 +0200 +Subject: [PATCH] [core,connection] disable NTLM in FIPS mode + +Commit eed2d3421a enabled NLA in FIPS mode since Kerberos support +had been added to FreeRDP since the original FIPS implementation. + +However, that commit removed the NLA restriction entirely without +accounting for the fact that NTLM authentication still uses +MD4 and RC4 which are not FIPS-compliant. This means the Negotiate +SSP can fall back to NTLM, which violates FIPS requirements. + +This commit addresses that by setting `AuthenticationPackageList` +to `"!ntlm"` when FIPS mode is active and the user has not +explicitly configured a package list. This disables the NTLM +mechanism within the Negotiate SSP while keeping Kerberos +available for NLA. + +Made-with: Cursor +Co-authored-by: Cursor +--- + libfreerdp/core/connection.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c +index cc9c8899b..c013e9b38 100644 +--- a/libfreerdp/core/connection.c ++++ b/libfreerdp/core/connection.c +@@ -324,10 +324,16 @@ BOOL rdp_client_connect(rdpRdp* rdp) + + /* FIPS Mode forces the following and overrides the following(by happening later + * in the command line processing): +- * 1. Forces the only supported RDP encryption method to be FIPS. */ ++ * 1. Forces the only supported RDP encryption method to be FIPS. ++ * 2. Disables NTLM authentication (not FIPS compliant due to MD4/RC4). */ + if (settings->FIPSMode || winpr_FIPSMode()) + { + settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS; ++ if (!settings->AuthenticationPackageList) ++ { ++ if (!freerdp_settings_set_string(settings, FreeRDP_AuthenticationPackageList, "!ntlm")) ++ return FALSE; ++ } + } + + UINT32 TcpConnectTimeout = freerdp_settings_get_uint32(settings, FreeRDP_TcpConnectTimeout); +-- +2.54.0 + diff --git a/core-connection-disable-RDP-Security-in-FIPS-mode.patch b/core-connection-disable-RDP-Security-in-FIPS-mode.patch new file mode 100644 index 0000000..79dd1a2 --- /dev/null +++ b/core-connection-disable-RDP-Security-in-FIPS-mode.patch @@ -0,0 +1,66 @@ +From 56b0402e945360eaa2ad64922a6591f7ccea9ee5 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 25 May 2026 11:49:12 +0200 +Subject: [PATCH] [core,connection] disable RDP Security in FIPS mode + +The FIPS mode block in `rdp_client_connect` forces +`ENCRYPTION_METHOD_FIPS` which uses 3DES-EDE3-CBC for the RDP +Security layer encryption. + +Starting with OpenSSL 3.4, the FIPS provider marks Triple-DES as +a non-approved algorithm (`fips=no`) and rejects its use by +default. This causes connection failures when RDP Security +negotiation is attempted in FIPS mode on systems with OpenSSL 3.4 +or newer. + +This commit addresses that by disabling `RdpSecurity` entirely +when 3DES-EDE3-CBC is not available, so that only NLA/TLS (which +use FIPS-approved AES) are negotiated. On older OpenSSL versions, +the existing `ENCRYPTION_METHOD_FIPS` behavior is preserved since +3DES still works there. + +Made-with: Cursor +--- + libfreerdp/core/connection.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c +index c013e9b38..0d72c0e50 100644 +--- a/libfreerdp/core/connection.c ++++ b/libfreerdp/core/connection.c +@@ -325,15 +325,31 @@ BOOL rdp_client_connect(rdpRdp* rdp) + /* FIPS Mode forces the following and overrides the following(by happening later + * in the command line processing): + * 1. Forces the only supported RDP encryption method to be FIPS. +- * 2. Disables NTLM authentication (not FIPS compliant due to MD4/RC4). */ ++ * 2. Disables NTLM authentication (not FIPS compliant due to MD4/RC4). ++ * 3. Disables RDP Security if 3DES is not available in the crypto provider. */ + if (settings->FIPSMode || winpr_FIPSMode()) + { ++ + settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS; ++ + if (!settings->AuthenticationPackageList) + { + if (!freerdp_settings_set_string(settings, FreeRDP_AuthenticationPackageList, "!ntlm")) + return FALSE; + } ++ ++ const BYTE key[WINPR_CIPHER_MAX_KEY_LENGTH] = WINPR_C_ARRAY_INIT; ++ const BYTE iv[WINPR_CIPHER_MAX_IV_LENGTH] = WINPR_C_ARRAY_INIT; ++ WINPR_CIPHER_CTX* ctx = winpr_Cipher_NewEx(WINPR_CIPHER_DES_EDE3_CBC, WINPR_ENCRYPT, key, ++ sizeof(key), iv, sizeof(iv)); ++ if (ctx) ++ { ++ winpr_Cipher_Free(ctx); ++ } ++ else ++ { ++ settings->RdpSecurity = FALSE; ++ } + } + + UINT32 TcpConnectTimeout = freerdp_settings_get_uint32(settings, FreeRDP_TcpConnectTimeout); +-- +2.54.0 + diff --git a/core-rdp-suppress-expected-FIPS-cipher-warnings.patch b/core-rdp-suppress-expected-FIPS-cipher-warnings.patch new file mode 100644 index 0000000..08df2e6 --- /dev/null +++ b/core-rdp-suppress-expected-FIPS-cipher-warnings.patch @@ -0,0 +1,166 @@ +From 96ba0967557901ed8179e0e5997d1604064697bf Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 25 May 2026 14:59:47 +0200 +Subject: [PATCH] [core,rdp] suppress expected FIPS cipher warnings + +The build-time cipher and digest checks warn about missing crypto +functionality. In FIPS mode many algorithms (MD4, MD5, RC4) are +expected to be unavailable, producing misleading warnings that +obscure real problems. + +This commit addresses that by adding an `allowFIPS` parameter to +`log_build_warn_cipher` and `log_build_warn_hash`. When set, the +`_Allow_FIPS` variant is tested instead (e.g. +`winpr_RC4_New_Allow_FIPS`, `winpr_Digest_Init_Allow_FIPS`). +Checks for algorithms expected to be unavailable on FIPS (MD4, +HMAC-MD5) are skipped silently, and a single INFO message +summarizes the situation. The DES_EDE3_CBC check is skipped since +3DES is no longer available in the FIPS provider. + +Made-with: Cursor +--- + libfreerdp/core/rdp.c | 83 +++++++++++++++++++++++++++++++------------ + 1 file changed, 60 insertions(+), 23 deletions(-) + +diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c +index aec144796..12bfd0296 100644 +--- a/libfreerdp/core/rdp.c ++++ b/libfreerdp/core/rdp.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include "rdp.h" + +@@ -3043,7 +3044,7 @@ static void print_last_line(wLog* log, const log_line_t* firstLine) + } + + static void log_build_warn_cipher(rdpRdp* rdp, log_line_t* firstLine, WINPR_CIPHER_TYPE md, +- const char* what) ++ const char* what, BOOL allowFIPS) + { + BOOL haveCipher = FALSE; + +@@ -3054,7 +3055,11 @@ static void log_build_warn_cipher(rdpRdp* rdp, log_line_t* firstLine, WINPR_CIPH + * winpr_Cipher_* does not support that. */ + if (md == WINPR_CIPHER_ARC4_128) + { +- WINPR_RC4_CTX* enc = winpr_RC4_New(key, sizeof(key)); ++ WINPR_RC4_CTX* enc = nullptr; ++ if (allowFIPS) ++ enc = winpr_RC4_New_Allow_FIPS(key, sizeof(key)); ++ else ++ enc = winpr_RC4_New(key, sizeof(key)); + haveCipher = enc != nullptr; + winpr_RC4_Free(enc); + } +@@ -3101,13 +3106,17 @@ static void log_build_warn_hmac(rdpRdp* rdp, log_line_t* firstLine, WINPR_MD_TYP + } + + static void log_build_warn_hash(rdpRdp* rdp, log_line_t* firstLine, WINPR_MD_TYPE md, +- const char* what) ++ const char* what, BOOL allowFIPS) + { + BOOL haveDigestX = FALSE; +- + WINPR_DIGEST_CTX* digest = winpr_Digest_New(); + if (digest) +- haveDigestX = winpr_Digest_Init(digest, md); ++ { ++ if (allowFIPS) ++ haveDigestX = winpr_Digest_Init_Allow_FIPS(digest, md); ++ else ++ haveDigestX = winpr_Digest_Init(digest, md); ++ } + winpr_Digest_Free(digest); + + if (!haveDigestX) +@@ -3121,37 +3130,65 @@ static void log_build_warn_ssl(rdpRdp* rdp) + { + WINPR_ASSERT(rdp); + ++ const BOOL fips = winpr_FIPSMode(); ++ ++ if (fips) ++ { ++ WLog_Print(rdp->log, WLOG_INFO, ++ "FIPS mode active: non-approved algorithms are unavailable " ++ "as expected. NTLM, autoreconnect cookies, assistance files " ++ "with encrypted passwords and RDP security will not work."); ++ } ++ + log_line_t firstHashLine = WINPR_C_ARRAY_INIT; +- log_build_warn_hash(rdp, &firstHashLine, WINPR_MD_MD4, "NTLM support not available"); ++ if (!fips) ++ { ++ log_build_warn_hash(rdp, &firstHashLine, WINPR_MD_MD4, "NTLM support not available", FALSE); ++ log_build_warn_hash(rdp, &firstHashLine, WINPR_MD_MD5, ++ "NTLM, assistance files with encrypted passwords " ++ " and autoreconnect cookies will not work", ++ FALSE); ++ } + log_build_warn_hash(rdp, &firstHashLine, WINPR_MD_MD5, +- "NTLM, assistance files with encrypted passwords, autoreconnect cookies, " +- "licensing and RDP security will not work"); ++ "RDP licensing and RDP security will not work", TRUE); + log_build_warn_hash(rdp, &firstHashLine, WINPR_MD_SHA1, + "assistance files with encrypted passwords, Kerberos, Smartcard Logon, RDP " +- "security support not available"); +- log_build_warn_hash( +- rdp, &firstHashLine, WINPR_MD_SHA256, +- "file clipboard, AAD gateway, NLA security and certificates might not work"); ++ "security support not available", ++ FALSE); ++ log_build_warn_hash(rdp, &firstHashLine, WINPR_MD_SHA256, ++ "file clipboard, AAD gateway, NLA security and certificates might not work", ++ FALSE); + print_last_line(rdp->log, &firstHashLine); + +- log_line_t firstHmacLine = WINPR_C_ARRAY_INIT; +- log_build_warn_hmac(rdp, &firstHmacLine, WINPR_MD_MD5, "Autoreconnect cookie not supported"); +- log_build_warn_hmac(rdp, &firstHmacLine, WINPR_MD_SHA1, "RDP security not supported"); +- print_last_line(rdp->log, &firstHmacLine); ++ if (!fips) ++ { ++ log_line_t firstHmacLine = WINPR_C_ARRAY_INIT; ++ log_build_warn_hmac(rdp, &firstHmacLine, WINPR_MD_MD5, ++ "Autoreconnect cookie not supported"); ++ log_build_warn_hmac(rdp, &firstHmacLine, WINPR_MD_SHA1, "RDP security not supported"); ++ print_last_line(rdp->log, &firstHmacLine); ++ } + + log_line_t firstCipherLine = WINPR_C_ARRAY_INIT; ++ if (!fips) ++ { ++ log_build_warn_cipher(rdp, &firstCipherLine, WINPR_CIPHER_ARC4_128, ++ "assistance files with encrypted passwords, NTLM " ++ "and autoreconnect cookies will not work", ++ FALSE); ++ } + log_build_warn_cipher(rdp, &firstCipherLine, WINPR_CIPHER_ARC4_128, +- "assistance files with encrypted passwords, NTLM, RDP licensing and RDP " +- "security will not work"); +- log_build_warn_cipher(rdp, &firstCipherLine, WINPR_CIPHER_DES_EDE3_CBC, +- "RDP security FIPS mode will not work"); ++ "RDP licensing and RDP security will not work", TRUE); ++ if (!fips) ++ log_build_warn_cipher(rdp, &firstCipherLine, WINPR_CIPHER_DES_EDE3_CBC, ++ "RDP security will not work", TRUE); + log_build_warn_cipher( + rdp, &firstCipherLine, WINPR_CIPHER_AES_128_CBC, +- "assistance file encrypted LHTicket will not work and ARM gateway might not"); ++ "assistance file encrypted LHTicket will not work and ARM gateway might not", FALSE); + log_build_warn_cipher(rdp, &firstCipherLine, WINPR_CIPHER_AES_192_CBC, +- "ARM gateway might not work"); ++ "ARM gateway might not work", FALSE); + log_build_warn_cipher(rdp, &firstCipherLine, WINPR_CIPHER_AES_256_CBC, +- "ARM gateway might not work"); ++ "ARM gateway might not work", FALSE); + print_last_line(rdp->log, &firstCipherLine); + } + +-- +2.54.0 + diff --git a/freerdp.spec b/freerdp.spec index b5f88cb..e5153cf 100644 --- a/freerdp.spec +++ b/freerdp.spec @@ -30,7 +30,7 @@ Name: freerdp Epoch: 2 Version: 3.24.2 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Free implementation of the Remote Desktop Protocol (RDP) # The effective license is Apache-2.0 but: @@ -47,6 +47,12 @@ URL: http://www.freerdp.com/ Source0: FreeRDP-%{version}-repack.tar.gz Source1: freerdp_download_and_repack.sh +# https://github.com/FreeRDP/FreeRDP/pull/12811 +Patch: core-connection-disable-NTLM-in-FIPS-mode.patch +Patch: core-connection-disable-RDP-Security-in-FIPS-mode.patch +Patch: winpr-crypto-fix-RC4-FIPS-override-for-OpenSSL-3.patch +Patch: core-rdp-suppress-expected-FIPS-cipher-warnings.patch + BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: alsa-lib-devel @@ -371,6 +377,10 @@ find %{buildroot} -name "*.a" -delete %{_libdir}/pkgconfig/winpr-tools3.pc %changelog +* Mon Jun 01 2026 Ondrej Holy - 2:3.24.2-2 +- Improve FIPS mode support + Resolves: RHEL-140202 + * Thu Apr 09 2026 Ondrej Holy - 2:3.24.2-1 - Update to 3.24.2 Resolves: RHEL-80426 diff --git a/winpr-crypto-fix-RC4-FIPS-override-for-OpenSSL-3.patch b/winpr-crypto-fix-RC4-FIPS-override-for-OpenSSL-3.patch new file mode 100644 index 0000000..13848d8 --- /dev/null +++ b/winpr-crypto-fix-RC4-FIPS-override-for-OpenSSL-3.patch @@ -0,0 +1,66 @@ +From 13edfacb49d8c9843b339b528562eab839d81a0b Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 25 May 2026 11:21:05 +0200 +Subject: [PATCH] [winpr,crypto] fix RC4 FIPS override for OpenSSL 3 + +The `winpr_RC4_New_Allow_FIPS` function uses +`EVP_CIPH_FLAG_NON_FIPS_ALLOW` to permit RC4 usage in FIPS mode +for protocol-required operations like RDP licensing. + +In OpenSSL 3.x this flag is no longer honored, causing RC4 +operations to fail when the system is running in FIPS mode. + +This commit addresses that by using `EVP_CIPHER_fetch` with the +`"fips=no"` property string on OpenSSL 3.x, matching the approach +used for MD5 in commit 97d7a3fc6d. + +Made-with: Cursor +--- + winpr/libwinpr/crypto/cipher.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/winpr/libwinpr/crypto/cipher.c b/winpr/libwinpr/crypto/cipher.c +index 896a0d1d6..de65a4654 100644 +--- a/winpr/libwinpr/crypto/cipher.c ++++ b/winpr/libwinpr/crypto/cipher.c +@@ -90,7 +90,6 @@ static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOO + if (!ctx->ictx) + goto fail; + #elif defined(WITH_OPENSSL) +- const EVP_CIPHER* evp = nullptr; + + if (keylen > INT_MAX) + goto fail; +@@ -99,7 +98,11 @@ static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOO + if (!ctx->ctx) + goto fail; + +- evp = EVP_rc4(); ++#if OPENSSL_VERSION_NUMBER >= 0x30000000L ++ EVP_CIPHER* evp = EVP_CIPHER_fetch(NULL, "RC4", override_fips ? "fips=no" : NULL); ++#else ++ const EVP_CIPHER* evp = EVP_rc4(); ++#endif + + if (!evp) + goto fail; +@@ -108,12 +111,16 @@ static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOO + if (EVP_EncryptInit_ex(ctx->ctx, evp, nullptr, nullptr, nullptr) != 1) + goto fail; + ++#if OPENSSL_VERSION_NUMBER >= 0x30000000L ++ EVP_CIPHER_free(evp); ++ + /* EVP_CIPH_FLAG_NON_FIPS_ALLOW does not exist before openssl 1.0.1 */ + #if !(OPENSSL_VERSION_NUMBER < 0x10001000L) + + if (override_fips == TRUE) + EVP_CIPHER_CTX_set_flags(ctx->ctx, EVP_CIPH_FLAG_NON_FIPS_ALLOW); + ++#endif + #endif + EVP_CIPHER_CTX_set_key_length(ctx->ctx, (int)keylen); + if (EVP_EncryptInit_ex(ctx->ctx, nullptr, nullptr, key, nullptr) != 1) +-- +2.54.0 +