Blame SOURCES/FIPS-mode-support.patch

56112c
From 1511f1959b2a48cb2d41550441df366276e3c5cb Mon Sep 17 00:00:00 2001
56112c
From: Ondrej Holy <oholy@redhat.com>
56112c
Date: Tue, 7 Nov 2017 14:57:12 +0100
56112c
Subject: [PATCH] FIPS mode support
56112c
56112c
---
56112c
 libfreerdp-core/certificate.c | 17 +++++++-----
56112c
 libfreerdp-core/connection.c  |  3 +++
56112c
 libfreerdp-core/crypto.c      | 61 ++++++++++++++++++++++++++++++++++++++-----
56112c
 libfreerdp-core/crypto.h      |  6 +++--
56112c
 libfreerdp-core/license.c     | 15 ++++++++---
56112c
 libfreerdp-core/nego.c        |  5 +++-
56112c
 libfreerdp-core/security.c    | 33 +++++++++++++++++++----
56112c
 libfreerdp-utils/args.c       |  3 ---
56112c
 8 files changed, 116 insertions(+), 27 deletions(-)
56112c
56112c
diff --git a/libfreerdp-core/certificate.c b/libfreerdp-core/certificate.c
56112c
index 801ed3609..1fd2cd216 100644
56112c
--- a/libfreerdp-core/certificate.c
56112c
+++ b/libfreerdp-core/certificate.c
56112c
@@ -276,15 +276,19 @@ static boolean certificate_process_server_public_key(rdpCertificate* certificate
56112c
 
56112c
 static boolean certificate_process_server_public_signature(rdpCertificate* certificate, uint8* sigdata, int sigdatalen, STREAM* s, uint32 siglen)
56112c
 {
56112c
-	uint8 md5hash[CRYPTO_MD5_DIGEST_LENGTH];
56112c
+	/*uint8 md5hash[CRYPTO_MD5_DIGEST_LENGTH];*/
56112c
 	uint8 encsig[TSSK_KEY_LENGTH + 8];
56112c
 	uint8 sig[TSSK_KEY_LENGTH];
56112c
-	CryptoMd5 md5ctx;
56112c
+	/*CryptoMd5 md5ctx;*/
56112c
 	int i, sum;
56112c
 
56112c
-	md5ctx = crypto_md5_init();
56112c
+	/* Do not bother with validation of server proprietary certificate. The use of MD5 here is not allowed under FIPS. */
56112c
+	/* Since the validation is not protecting against anything since the private/public keys are well known and documented in */
56112c
+	/* MS-RDPBCGR section 5.3.3.1, we are not gaining any security by using MD5 for signature comparison. Rather then use MD5 */
56112c
+	/* here we just dont do the validation to avoid its use. Historically, freerdp has been ignoring a failed validation anyways. */
56112c
+	/*md5ctx = crypto_md5_init();
56112c
 	crypto_md5_update(md5ctx, sigdata, sigdatalen);
56112c
-	crypto_md5_final(md5ctx, md5hash);
56112c
+	crypto_md5_final(md5ctx, md5hash);*/
56112c
 
56112c
 	stream_read(s, encsig, siglen);
56112c
 
56112c
@@ -304,11 +308,12 @@ static boolean certificate_process_server_public_signature(rdpCertificate* certi
56112c
 	crypto_rsa_public_decrypt(encsig, siglen, TSSK_KEY_LENGTH, tssk_modulus, tssk_exponent, sig);
56112c
 
56112c
 	/* Verify signature. */
56112c
-	if (memcmp(md5hash, sig, sizeof(md5hash)) != 0)
56112c
+	/* Do not bother with validation of server proprietary certificate as described above. */
56112c
+	/*if (memcmp(md5hash, sig, sizeof(md5hash)) != 0)
56112c
 	{
56112c
 		printf("certificate_process_server_public_signature: invalid signature\n");
56112c
 		//return false;
56112c
-	}
56112c
+	}*/
56112c
 
56112c
 	/*
56112c
 	 * Verify rest of decrypted data:
56112c
diff --git a/libfreerdp-core/connection.c b/libfreerdp-core/connection.c
56112c
index 7e1769ee4..7853c86bd 100644
56112c
--- a/libfreerdp-core/connection.c
56112c
+++ b/libfreerdp-core/connection.c
56112c
@@ -65,6 +65,9 @@ boolean rdp_client_connect(rdpRdp* rdp)
56112c
 	uint32 selectedProtocol;
56112c
 	rdpSettings* settings = rdp->settings;
56112c
 
56112c
+	if (FIPS_mode() == 1)
56112c
+		settings->nla_security = false;
56112c
+
56112c
 	nego_init(rdp->nego);
56112c
 	nego_set_target(rdp->nego, settings->hostname, settings->port);
56112c
 	nego_set_cookie(rdp->nego, settings->username);
56112c
diff --git a/libfreerdp-core/crypto.c b/libfreerdp-core/crypto.c
56112c
index a0e2ccb9d..e6115b867 100644
56112c
--- a/libfreerdp-core/crypto.c
56112c
+++ b/libfreerdp-core/crypto.c
56112c
@@ -37,34 +37,81 @@ void crypto_sha1_final(CryptoSha1 sha1, uint8* out_data)
56112c
 	xfree(sha1);
56112c
 }
56112c
 
56112c
-CryptoMd5 crypto_md5_init(void)
56112c
+static CryptoMd5 crypto_md5_init_internal(boolean override_fips)
56112c
 {
56112c
 	CryptoMd5 md5 = xmalloc(sizeof(*md5));
56112c
-	MD5_Init(&md5->md5_ctx);
56112c
+
56112c
+	EVP_MD_CTX_init(&md5->md5_ctx);
56112c
+	if (override_fips)
56112c
+		EVP_MD_CTX_set_flags(&md5->md5_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
56112c
+	if (EVP_DigestInit_ex(&md5->md5_ctx, EVP_md5(), NULL) != 1)
56112c
+	{
56112c
+		printf("EVP_DigestInit_ex failed\n");
56112c
+		abort();
56112c
+	}
56112c
+
56112c
 	return md5;
56112c
 }
56112c
 
56112c
+CryptoMd5 crypto_md5_init(void)
56112c
+{
56112c
+	return crypto_md5_init_internal(false);
56112c
+}
56112c
+
56112c
+CryptoMd5 crypto_md5_init_allow_fips(void)
56112c
+{
56112c
+	return crypto_md5_init_internal(true);
56112c
+}
56112c
+
56112c
 void crypto_md5_update(CryptoMd5 md5, const uint8* data, uint32 length)
56112c
 {
56112c
-	MD5_Update(&md5->md5_ctx, data, length);
56112c
+	EVP_DigestUpdate(&md5->md5_ctx, data, length);
56112c
 }
56112c
 
56112c
 void crypto_md5_final(CryptoMd5 md5, uint8* out_data)
56112c
 {
56112c
-	MD5_Final(out_data, &md5->md5_ctx);
56112c
+	EVP_DigestFinal_ex(&md5->md5_ctx, out_data, NULL);
56112c
 	xfree(md5);
56112c
 }
56112c
 
56112c
-CryptoRc4 crypto_rc4_init(const uint8* key, uint32 length)
56112c
+static CryptoRc4 crypto_rc4_init_internal(const uint8* key, uint32 length, boolean override_fips)
56112c
 {
56112c
 	CryptoRc4 rc4 = xmalloc(sizeof(*rc4));
56112c
-	RC4_set_key(&rc4->rc4_key, length, key);
56112c
+
56112c
+	EVP_CIPHER_CTX_init(&rc4->rc4_ctx);
56112c
+	if (EVP_EncryptInit_ex(&rc4->rc4_ctx, EVP_rc4(), NULL, NULL, NULL) != 1)
56112c
+	{
56112c
+		printf("EVP_EncryptInit_ex failed\n");
56112c
+		abort();
56112c
+	}
56112c
+
56112c
+	if (override_fips)
56112c
+		EVP_CIPHER_CTX_set_flags(&rc4->rc4_ctx, EVP_CIPH_FLAG_NON_FIPS_ALLOW);
56112c
+
56112c
+	EVP_CIPHER_CTX_set_key_length(&rc4->rc4_ctx, length);
56112c
+	if (EVP_EncryptInit_ex(&rc4->rc4_ctx, NULL, NULL, key, NULL) != 1)
56112c
+	{
56112c
+		printf("EVP_EncryptInit_ex failed\n");
56112c
+		abort();
56112c
+	}
56112c
+
56112c
 	return rc4;
56112c
 }
56112c
 
56112c
+CryptoRc4 crypto_rc4_init(const uint8* key, uint32 length)
56112c
+{
56112c
+	return crypto_rc4_init_internal(key, length, false);
56112c
+}
56112c
+
56112c
+CryptoRc4 crypto_rc4_init_allow_fips(const uint8* key, uint32 length)
56112c
+{
56112c
+	return crypto_rc4_init_internal(key, length, true);
56112c
+}
56112c
+
56112c
 void crypto_rc4(CryptoRc4 rc4, uint32 length, const uint8* in_data, uint8* out_data)
56112c
 {
56112c
-	RC4(&rc4->rc4_key, length, in_data, out_data);
56112c
+	int outputLength;
56112c
+	EVP_CipherUpdate(&rc4->rc4_ctx, out_data, &outputLength, in_data, length);
56112c
 }
56112c
 
56112c
 void crypto_rc4_free(CryptoRc4 rc4)
56112c
diff --git a/libfreerdp-core/crypto.h b/libfreerdp-core/crypto.h
56112c
index 15afca8a4..a595c3831 100644
56112c
--- a/libfreerdp-core/crypto.h
56112c
+++ b/libfreerdp-core/crypto.h
56112c
@@ -54,12 +54,12 @@ struct crypto_sha1_struct
56112c
 
56112c
 struct crypto_md5_struct
56112c
 {
56112c
-	MD5_CTX md5_ctx;
56112c
+	EVP_MD_CTX md5_ctx;
56112c
 };
56112c
 
56112c
 struct crypto_rc4_struct
56112c
 {
56112c
-	RC4_KEY rc4_key;
56112c
+	EVP_CIPHER_CTX rc4_ctx;
56112c
 };
56112c
 
56112c
 struct crypto_des3_struct
56112c
@@ -86,11 +86,13 @@ void crypto_sha1_final(CryptoSha1 sha1, uint8* out_data);
56112c
 #define	CRYPTO_MD5_DIGEST_LENGTH	MD5_DIGEST_LENGTH
56112c
 typedef struct crypto_md5_struct* CryptoMd5;
56112c
 CryptoMd5 crypto_md5_init(void);
56112c
+CryptoMd5 crypto_md5_init_allow_fips(void);
56112c
 void crypto_md5_update(CryptoMd5 md5, const uint8* data, uint32 length);
56112c
 void crypto_md5_final(CryptoMd5 md5, uint8* out_data);
56112c
 
56112c
 typedef struct crypto_rc4_struct* CryptoRc4;
56112c
 CryptoRc4 crypto_rc4_init(const uint8* key, uint32 length);
56112c
+CryptoRc4 crypto_rc4_init_allow_fips(const uint8* key, uint32 length);
56112c
 void crypto_rc4(CryptoRc4 rc4, uint32 length, const uint8* in_data, uint8* out_data);
56112c
 void crypto_rc4_free(CryptoRc4 rc4);
56112c
 
56112c
diff --git a/libfreerdp-core/license.c b/libfreerdp-core/license.c
56112c
index 60b9f9366..7e5734069 100644
56112c
--- a/libfreerdp-core/license.c
56112c
+++ b/libfreerdp-core/license.c
56112c
@@ -295,7 +295,10 @@ void license_generate_hwid(rdpLicense* license)
56112c
 	memset(license->hwid, 0, HWID_LENGTH);
56112c
 	mac_address = license->rdp->transport->tcp->mac_address;
56112c
 
56112c
-	md5 = crypto_md5_init();
56112c
+	/* Allow FIPS override for use of MD5 here, really this does not have to be MD5 as we are just taking a MD5 hash of the 6 bytes of 0's(macAddress) */
56112c
+	/* and filling in the Data1-Data4 fields of the CLIENT_HARDWARE_ID structure(from MS-RDPELE section 2.2.2.3.1). This is for RDP licensing packets */
56112c
+	/* which will already be encrypted under FIPS, so the use of MD5 here is not for sensitive data protection. */
56112c
+	md5 = crypto_md5_init_allow_fips();
56112c
 	crypto_md5_update(md5, mac_address, 6);
56112c
 	crypto_md5_final(md5, &license->hwid[HWID_PLATFORM_ID_LENGTH]);
56112c
 }
56112c
@@ -354,7 +357,10 @@ void license_decrypt_platform_challenge(rdpLicense* license)
56112c
 	license->platform_challenge->length =
56112c
 			license->encrypted_platform_challenge->length;
56112c
 
56112c
-	rc4 = crypto_rc4_init(license->licensing_encryption_key, LICENSING_ENCRYPTION_KEY_LENGTH);
56112c
+	/* Allow FIPS override for use of RC4 here, this is only used for decrypting the MACData field of the */
56112c
+	/* Server Platform Challenge packet (from MS-RDPELE section 2.2.2.4). This is for RDP licensing packets */
56112c
+	/* which will already be encrypted under FIPS, so the use of RC4 here is not for sensitive data protection. */
56112c
+	rc4 = crypto_rc4_init_allow_fips(license->licensing_encryption_key, LICENSING_ENCRYPTION_KEY_LENGTH);
56112c
 
56112c
 	crypto_rc4(rc4, license->encrypted_platform_challenge->length,
56112c
 			license->encrypted_platform_challenge->data,
56112c
@@ -829,8 +835,11 @@ void license_send_platform_challenge_response_packet(rdpLicense* license)
56112c
 	security_mac_data(license->mac_salt_key, buffer, length, mac_data);
56112c
 	xfree(buffer);
56112c
 
56112c
+	/* Allow FIPS override for use of RC4 here, this is only used for encrypting the EncryptedHWID field of the */
56112c
+	/* Client Platform Challenge Response packet (from MS-RDPELE section 2.2.2.5). This is for RDP licensing packets */
56112c
+	/* which will already be encrypted under FIPS, so the use of RC4 here is not for sensitive data protection. */
56112c
 	buffer = (uint8*) xmalloc(HWID_LENGTH);
56112c
-	rc4 = crypto_rc4_init(license->licensing_encryption_key, LICENSING_ENCRYPTION_KEY_LENGTH);
56112c
+	rc4 = crypto_rc4_init_allow_fips(license->licensing_encryption_key, LICENSING_ENCRYPTION_KEY_LENGTH);
56112c
 	crypto_rc4(rc4, HWID_LENGTH, license->hwid, buffer);
56112c
 	crypto_rc4_free(rc4);
56112c
 
56112c
diff --git a/libfreerdp-core/nego.c b/libfreerdp-core/nego.c
56112c
index 7eb810bba..199870408 100644
56112c
--- a/libfreerdp-core/nego.c
56112c
+++ b/libfreerdp-core/nego.c
56112c
@@ -89,7 +89,10 @@ boolean nego_connect(rdpNego* nego)
56112c
 	if(nego->selected_protocol == PROTOCOL_RDP)
56112c
 	{
56112c
 		nego->transport->settings->encryption = true;
56112c
-		nego->transport->settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
56112c
+		if (FIPS_mode() != 1)
56112c
+			nego->transport->settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
56112c
+		else
56112c
+			nego->transport->settings->encryption_method = ENCRYPTION_METHOD_FIPS;
56112c
 		nego->transport->settings->encryption_level = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
56112c
 	}
56112c
 
56112c
diff --git a/libfreerdp-core/security.c b/libfreerdp-core/security.c
56112c
index d93c3b9a8..d93390de2 100644
56112c
--- a/libfreerdp-core/security.c
56112c
+++ b/libfreerdp-core/security.c
56112c
@@ -131,7 +131,10 @@ static void security_salted_hash(uint8* salt, uint8* input, int length, uint8* s
56112c
 	crypto_sha1_final(sha1, sha1_digest);
56112c
 
56112c
 	/* SaltedHash(Salt, Input, Salt1, Salt2) = MD5(S + SHA1_Digest) */
56112c
-	md5 = crypto_md5_init();
56112c
+	/* Allow FIPS override for use of MD5 here, this is used for creating hashes of the premaster_secret and master_secret */
56112c
+	/* used for RDP licensing as described in MS-RDPELE. This is for RDP licensing packets */
56112c
+	/* which will already be encrypted under FIPS, so the use of MD5 here is not for sensitive data protection. */
56112c
+	md5 = crypto_md5_init_allow_fips();
56112c
 	crypto_md5_update(md5, salt, 48); /* Salt (48 bytes) */
56112c
 	crypto_md5_update(md5, sha1_digest, sizeof(sha1_digest)); /* SHA1_Digest */
56112c
 	crypto_md5_final(md5, output);
56112c
@@ -182,10 +185,24 @@ void security_md5_16_32_32(uint8* in0, uint8* in1, uint8* in2, uint8* output)
56112c
 	crypto_md5_final(md5, output);
56112c
 }
56112c
 
56112c
+void security_md5_16_32_32_allow_fips(uint8* in0, uint8* in1, uint8* in2, uint8* output)
56112c
+{
56112c
+	CryptoMd5 md5;
56112c
+
56112c
+	md5 = crypto_md5_init_allow_fips();
56112c
+	crypto_md5_update(md5, in0, 16);
56112c
+	crypto_md5_update(md5, in1, 32);
56112c
+	crypto_md5_update(md5, in2, 32);
56112c
+	crypto_md5_final(md5, output);
56112c
+}
56112c
+
56112c
 void security_licensing_encryption_key(uint8* session_key_blob, uint8* client_random, uint8* server_random, uint8* output)
56112c
 {
56112c
 	/* LicensingEncryptionKey = MD5(Second128Bits(SessionKeyBlob) + ClientRandom + ServerRandom)) */
56112c
-	security_md5_16_32_32(&session_key_blob[16], client_random, server_random, output);
56112c
+	/* Allow FIPS use of MD5 here, this is just used for creating the licensing encryption key as described in MS-RDPELE. */
56112c
+	/* This is for RDP licensing packets which will already be encrypted under FIPS, so the use of MD5 here is not for */
56112c
+	/* sensitive data protection. */
56112c
+	security_md5_16_32_32_allow_fips(&session_key_blob[16], client_random, server_random, output);
56112c
 }
56112c
 
56112c
 void security_uint32_le(uint8* output, uint32 value)
56112c
@@ -216,7 +233,10 @@ void security_mac_data(uint8* mac_salt_key, uint8* data, uint32 length, uint8* o
56112c
 	crypto_sha1_final(sha1, sha1_digest);
56112c
 
56112c
 	/* MacData = MD5(MacSaltKey + pad2 + SHA1_Digest) */
56112c
-	md5 = crypto_md5_init();
56112c
+	/* Allow FIPS override for use of MD5 here, this is only used for creating the MACData field of the */
56112c
+	/* Client Platform Challenge Response packet (from MS-RDPELE section 2.2.2.5). This is for RDP licensing packets */
56112c
+	/* which will already be encrypted under FIPS, so the use of MD5 here is not for sensitive data protection. */
56112c
+	md5 = crypto_md5_init_allow_fips();
56112c
 	crypto_md5_update(md5, mac_salt_key, 16); /* MacSaltKey */
56112c
 	crypto_md5_update(md5, pad2, sizeof(pad2)); /* pad2 */
56112c
 	crypto_md5_update(md5, sha1_digest, sizeof(sha1_digest)); /* SHA1_Digest */
56112c
@@ -400,9 +420,12 @@ boolean security_establish_keys(uint8* client_random, rdpRdp* rdp)
56112c
 		security_md5_16_32_32(&session_key_blob[32], client_random,
56112c
 		    server_random, rdp->decrypt_key);
56112c
 	} else {
56112c
-		security_md5_16_32_32(&session_key_blob[16], client_random,
56112c
+		/* Allow FIPS use of MD5 here, this is just used for generation of the SessionKeyBlob as described in MS-RDPELE. */
56112c
+		/* This is for RDP licensing packets which will already be encrypted under FIPS, so the use of MD5 here is not */
56112c
+		/* for sensitive data protection. */
56112c
+		security_md5_16_32_32_allow_fips(&session_key_blob[16], client_random,
56112c
 		    server_random, rdp->decrypt_key);
56112c
-		security_md5_16_32_32(&session_key_blob[32], client_random,
56112c
+		security_md5_16_32_32_allow_fips(&session_key_blob[32], client_random,
56112c
 		    server_random, rdp->encrypt_key);
56112c
 	}
56112c
 
56112c
diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c
56112c
index d9b08c41f..333742536 100644
56112c
--- a/libfreerdp-utils/args.c
56112c
+++ b/libfreerdp-utils/args.c
56112c
@@ -550,9 +550,6 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
56112c
 				settings->rdp_security = true;
56112c
 				settings->tls_security = false;
56112c
 				settings->nla_security = false;
56112c
-				settings->encryption = true;
56112c
-				settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
56112c
-				settings->encryption_level = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
56112c
 			}
56112c
 			else if (strncmp("tls", argv[index], 1) == 0) /* TLS */
56112c
 			{
56112c
-- 
56112c
2.15.0
56112c