diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 3bb62984b..c4814edb0 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -91,6 +91,7 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "encryption-methods", COMMAND_LINE_VALUE_REQUIRED, "[40,][56,][128,][FIPS]", NULL, NULL, -1, NULL, "RDP standard security encryption methods" }, { "f", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Fullscreen mode" }, { "fast-path", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Enable fast-path input/output" }, + { "fipsmode", COMMAND_LINE_VALUE_BOOL, NULL, NULL, NULL, -1, NULL, "Enable FIPS mode" }, { "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Enable smooth fonts (ClearType)" }, { "frame-ack", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Number of frame acknowledgement" }, { "from-stdin", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Read credentials from stdin, do not use defaults." }, @@ -2767,6 +2768,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (!(settings->ActionScript = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } + CommandLineSwitchCase(arg, "fipsmode") + { + settings->FIPSMode = TRUE; + } CommandLineSwitchDefault(arg) { } @@ -2822,6 +2827,17 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->ColorDepth = 32; } + /* FIPS Mode forces the following and overrides the following(by happening later */ + /* in the command line processing): */ + /* 1. Disables NLA Security since NLA in freerdp uses NTLM(no Kerberos support yet) which uses algorithms */ + /* not allowed in FIPS for sensitive data. So, we disallow NLA when FIPS is required. */ + /* 2. Forces the only supported RDP encryption method to be FIPS. */ + if (settings->FIPSMode) + { + settings->NlaSecurity = FALSE; + settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS; + } + arg = CommandLineFindArgumentA(args, "port"); if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT) diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 2f378dea7..d56039b33 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -606,6 +606,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_AllowedTlsCiphers 1101 #define FreeRDP_VmConnectMode 1102 #define FreeRDP_NtlmSamFile 1103 +#define FreeRDP_FIPSMode 1104 #define FreeRDP_MstscCookieMode 1152 #define FreeRDP_CookieMaxLength 1153 #define FreeRDP_PreconnectionId 1154 @@ -1018,7 +1019,8 @@ struct rdp_settings ALIGN64 char* AllowedTlsCiphers; /* 1101 */ ALIGN64 BOOL VmConnectMode; /* 1102 */ ALIGN64 char* NtlmSamFile; /* 1103 */ - UINT64 padding1152[1152 - 1104]; /* 1104 */ + ALIGN64 BOOL FIPSMode; /* 1104 */ + UINT64 padding1152[1152 - 1105]; /* 1105 */ /* Connection Cookie */ ALIGN64 BOOL MstscCookieMode; /* 1152 */ diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index b4fbfeff9..76d2439f4 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -921,6 +921,9 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id) case FreeRDP_ExternalCertificateManagement: return settings->ExternalCertificateManagement; + case FreeRDP_FIPSMode: + return settings->FIPSMode; + case FreeRDP_Workarea: return settings->Workarea; @@ -1381,6 +1384,10 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) settings->ExternalCertificateManagement = param; break; + case FreeRDP_FIPSMode: + settings->FIPSMode = param; + break; + case FreeRDP_Workarea: settings->Workarea = param; break; diff --git a/libfreerdp/core/certificate.c b/libfreerdp/core/certificate.c index e2d5c3a4e..482f6d423 100644 --- a/libfreerdp/core/certificate.c +++ b/libfreerdp/core/certificate.c @@ -408,8 +408,13 @@ static BOOL certificate_process_server_public_signature(rdpCertificate* certific BYTE encsig[TSSK_KEY_LENGTH + 8]; BYTE md5hash[WINPR_MD5_DIGEST_LENGTH]; - if (!winpr_Digest(WINPR_MD_MD5, sigdata, sigdatalen, md5hash, sizeof(md5hash))) - return FALSE; + /* Do not bother with validation of server proprietary certificate. The use of MD5 here is not allowed under FIPS. */ + /* Since the validation is not protecting against anything since the private/public keys are well known and documented in */ + /* MS-RDPBCGR section 5.3.3.1, we are not gaining any security by using MD5 for signature comparison. Rather then use MD5 */ + /* here we just dont do the validation to avoid its use. Historically, freerdp has been ignoring a failed validation anyways. */ + /*if (!winpr_Digest(WINPR_MD_MD5, sigdata, sigdatalen, md5hash, sizeof(md5hash))) + return FALSE;*/ + Stream_Read(s, encsig, siglen); /* Last 8 bytes shall be all zero. */ @@ -424,15 +429,17 @@ static BOOL certificate_process_server_public_signature(rdpCertificate* certific } siglen -= 8; + // TODO: check the result of decrypt crypto_rsa_public_decrypt(encsig, siglen, TSSK_KEY_LENGTH, tssk_modulus, tssk_exponent, sig); /* Verify signature. */ - if (memcmp(md5hash, sig, sizeof(md5hash)) != 0) + /* Do not bother with validation of server proprietary certificate as described above. */ + /*if (memcmp(md5hash, sig, sizeof(md5hash)) != 0) { WLog_ERR(TAG, "invalid signature"); //return FALSE; - } + }*/ /* * Verify rest of decrypted data: diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 71287865f..515a4d652 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -178,6 +179,13 @@ BOOL rdp_client_connect(rdpRdp* rdp) BOOL status; rdpSettings* settings = rdp->settings; + /* make sure SSL is initialize for earlier enough for crypto, by taking advantage of winpr SSL FIPS flag for openssl initialization */ + DWORD flags = WINPR_SSL_INIT_DEFAULT; + + if (settings->FIPSMode) + flags |= WINPR_SSL_INIT_ENABLE_FIPS; + winpr_InitializeSSL(flags); + nego_init(rdp->nego); nego_set_target(rdp->nego, settings->ServerHostname, settings->ServerPort); diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 9ab618da7..4468dc2d1 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -615,6 +615,7 @@ BOOL freerdp_context_new(freerdp* instance) rdpRdp* rdp; rdpContext* context; BOOL ret = TRUE; + DWORD flags = WINPR_SSL_INIT_DEFAULT; instance->context = (rdpContext*) calloc(1, instance->ContextSize); if (!instance->context) @@ -930,7 +931,6 @@ freerdp* freerdp_new() if (!instance) return NULL; - winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT); instance->ContextSize = sizeof(rdpContext); instance->SendChannelData = freerdp_send_channel_data; instance->ReceiveChannelData = freerdp_channels_data; diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c index 407e7691c..fc2d6b3ba 100644 --- a/libfreerdp/core/license.c +++ b/libfreerdp/core/license.c @@ -424,7 +424,10 @@ BOOL license_generate_hwid(rdpLicense* license) ZeroMemory(macAddress, sizeof(macAddress)); ZeroMemory(license->HardwareId, HWID_LENGTH); - if (!winpr_Digest(WINPR_MD_MD5, macAddress, sizeof(macAddress), &license->HardwareId[HWID_PLATFORM_ID_LENGTH], WINPR_MD5_DIGEST_LENGTH)) + /* 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) */ + /* 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 */ + /* which will already be encrypted under FIPS, so the use of MD5 here is not for sensitive data protection. */ + if (!winpr_Digest_Allow_FIPS(WINPR_MD_MD5, macAddress, sizeof(macAddress), &license->HardwareId[HWID_PLATFORM_ID_LENGTH], WINPR_MD5_DIGEST_LENGTH)) return FALSE; return TRUE; @@ -495,7 +498,10 @@ BOOL license_decrypt_platform_challenge(rdpLicense* license) return FALSE; license->PlatformChallenge->length = license->EncryptedPlatformChallenge->length; - if ((rc4 = winpr_RC4_New(license->LicensingEncryptionKey, + /* Allow FIPS override for use of RC4 here, this is only used for decrypting the MACData field of the */ + /* Server Platform Challenge packet (from MS-RDPELE section 2.2.2.4). This is for RDP licensing packets */ + /* which will already be encrypted under FIPS, so the use of RC4 here is not for sensitive data protection. */ + if ((rc4 = winpr_RC4_New_Allow_FIPS(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH)) == NULL) { free(license->PlatformChallenge->data); @@ -1089,7 +1095,10 @@ BOOL license_send_platform_challenge_response_packet(rdpLicense* license) if (!status) return FALSE; - rc4 = winpr_RC4_New(license->LicensingEncryptionKey, + /* Allow FIPS override for use of RC4 here, this is only used for encrypting the EncryptedHWID field of the */ + /* Client Platform Challenge Response packet (from MS-RDPELE section 2.2.2.5). This is for RDP licensing packets */ + /* which will already be encrypted under FIPS, so the use of RC4 here is not for sensitive data protection. */ + rc4 = winpr_RC4_New_Allow_FIPS(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH); if (!rc4) return FALSE; diff --git a/libfreerdp/core/security.c b/libfreerdp/core/security.c index dc5526ea9..e51898c24 100644 --- a/libfreerdp/core/security.c +++ b/libfreerdp/core/security.c @@ -153,7 +153,10 @@ static BOOL security_salted_hash(const BYTE* salt, const BYTE* input, int length /* SaltedHash(Salt, Input, Salt1, Salt2) = MD5(S + SHA1_Digest) */ if (!(md5 = winpr_Digest_New())) goto out; - if (!winpr_Digest_Init(md5, WINPR_MD_MD5)) + /* Allow FIPS override for use of MD5 here, this is used for creating hashes of the premaster_secret and master_secret */ + /* used for RDP licensing as described in MS-RDPELE. This is for RDP licensing packets */ + /* which will already be encrypted under FIPS, so the use of MD5 here is not for sensitive data protection. */ + if (!winpr_Digest_Init_Allow_FIPS(md5, WINPR_MD_MD5)) goto out; if (!winpr_Digest_Update(md5, salt, 48)) /* Salt (48 bytes) */ goto out; @@ -232,11 +235,38 @@ out: return result; } +BOOL security_md5_16_32_32_Allow_FIPS(const BYTE* in0, const BYTE* in1, const BYTE* in2, BYTE* output) +{ + WINPR_DIGEST_CTX* md5 = NULL; + BOOL result = FALSE; + + if (!(md5 = winpr_Digest_New())) + return FALSE; + if (!winpr_Digest_Init_Allow_FIPS(md5, WINPR_MD_MD5)) + goto out; + if (!winpr_Digest_Update(md5, in0, 16)) + goto out; + if (!winpr_Digest_Update(md5, in1, 32)) + goto out; + if (!winpr_Digest_Update(md5, in2, 32)) + goto out; + if (!winpr_Digest_Final(md5, output, WINPR_MD5_DIGEST_LENGTH)) + goto out; + + result = TRUE; +out: + winpr_Digest_Free(md5); + return result; +} + BOOL security_licensing_encryption_key(const BYTE* session_key_blob, const BYTE* client_random, const BYTE* server_random, BYTE* output) { /* LicensingEncryptionKey = MD5(Second128Bits(SessionKeyBlob) + ClientRandom + ServerRandom)) */ - return security_md5_16_32_32(&session_key_blob[16], client_random, server_random, output); + /* Allow FIPS use of MD5 here, this is just used for creating the licensing encryption key as described in MS-RDPELE. */ + /* This is for RDP licensing packets which will already be encrypted under FIPS, so the use of MD5 here is not for + /* sensitive data protection. */ + return security_md5_16_32_32_Allow_FIPS(&session_key_blob[16], client_random, server_random, output); } void security_UINT32_le(BYTE* output, UINT32 value) @@ -279,7 +309,10 @@ BOOL security_mac_data(const BYTE* mac_salt_key, const BYTE* data, UINT32 length /* MacData = MD5(MacSaltKey + pad2 + SHA1_Digest) */ if (!(md5 = winpr_Digest_New())) goto out; - if (!winpr_Digest_Init(md5, WINPR_MD_MD5)) + /* Allow FIPS override for use of MD5 here, this is only used for creating the MACData field of the */ + /* Client Platform Challenge Response packet (from MS-RDPELE section 2.2.2.5). This is for RDP licensing packets */ + /* which will already be encrypted under FIPS, so the use of MD5 here is not for sensitive data protection. */ + if (!winpr_Digest_Init_Allow_FIPS(md5, WINPR_MD_MD5)) goto out; if (!winpr_Digest_Update(md5, mac_salt_key, 16)) /* MacSaltKey */ goto out; @@ -546,8 +579,11 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) } else { - status = security_md5_16_32_32(&session_key_blob[16], client_random, server_random, rdp->decrypt_key); - status &= security_md5_16_32_32(&session_key_blob[32], client_random, server_random, rdp->encrypt_key); + /* Allow FIPS use of MD5 here, this is just used for generation of the SessionKeyBlob as described in MS-RDPELE. */ + /* This is for RDP licensing packets which will already be encrypted under FIPS, so the use of MD5 here is not */ + /* for sensitive data protection. */ + status = security_md5_16_32_32_Allow_FIPS(&session_key_blob[16], client_random, server_random, rdp->decrypt_key); + status &= security_md5_16_32_32_Allow_FIPS(&session_key_blob[32], client_random, server_random, rdp->encrypt_key); } if (!status) diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index fb23d8a71..eaf507046 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -333,6 +333,7 @@ rdpSettings* freerdp_settings_new(DWORD flags) settings->ConnectionType = CONNECTION_TYPE_LAN; settings->EncryptionMethods = ENCRYPTION_METHOD_NONE; settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; + settings->FIPSMode = FALSE; settings->CompressionEnabled = TRUE; settings->LogonNotify = TRUE; diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 034e2330f..34e25df7e 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -1466,7 +1466,6 @@ rdpTls* tls_new(rdpSettings* settings) if (!tls) return NULL; - winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT); tls->settings = settings; if (!settings->ServerMode) diff --git a/server/Sample/sfreerdp.c b/server/Sample/sfreerdp.c index 9d7f7aa4d..037f0308b 100644 --- a/server/Sample/sfreerdp.c +++ b/server/Sample/sfreerdp.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -919,6 +920,7 @@ int main(int argc, char* argv[]) } WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi()); + winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT); instance = freerdp_listener_new(); if (!instance) diff --git a/winpr/include/winpr/crypto.h b/winpr/include/winpr/crypto.h index 3ee989ec9..e56aa2b33 100644 --- a/winpr/include/winpr/crypto.h +++ b/winpr/include/winpr/crypto.h @@ -665,10 +665,12 @@ extern "C" { #endif WINPR_API WINPR_DIGEST_CTX* winpr_Digest_New(void); +WINPR_API BOOL winpr_Digest_Init_Allow_FIPS(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md); WINPR_API BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md); WINPR_API BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen); WINPR_API BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t ilen); WINPR_API void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx); +WINPR_API BOOL winpr_Digest_Allow_FIPS(int md, const BYTE* input, size_t ilen, BYTE* output, size_t olen); WINPR_API BOOL winpr_Digest(int md, const BYTE* input, size_t ilen, BYTE* output, size_t olen); #ifdef __cplusplus @@ -700,6 +702,7 @@ typedef struct _winpr_rc4_ctx_private_st WINPR_RC4_CTX; extern "C" { #endif +WINPR_API WINPR_RC4_CTX* winpr_RC4_New_Allow_FIPS(const BYTE* key, size_t keylen); WINPR_API WINPR_RC4_CTX* winpr_RC4_New(const BYTE* key, size_t keylen); WINPR_API BOOL winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output); WINPR_API void winpr_RC4_Free(WINPR_RC4_CTX* ctx); diff --git a/winpr/include/winpr/ssl.h b/winpr/include/winpr/ssl.h index 647c0e478..22b1a6f64 100644 --- a/winpr/include/winpr/ssl.h +++ b/winpr/include/winpr/ssl.h @@ -26,6 +26,7 @@ #define WINPR_SSL_INIT_DEFAULT 0x00 #define WINPR_SSL_INIT_ALREADY_INITIALIZED 0x01 #define WINPR_SSL_INIT_ENABLE_LOCKING 0x2 +#define WINPR_SSL_INIT_ENABLE_FIPS 0x4 #define WINPR_SSL_CLEANUP_GLOBAL 0x01 #define WINPR_SSL_CLEANUP_THREAD 0x02 diff --git a/winpr/libwinpr/crypto/cipher.c b/winpr/libwinpr/crypto/cipher.c index 72e13af6a..78a65019c 100644 --- a/winpr/libwinpr/crypto/cipher.c +++ b/winpr/libwinpr/crypto/cipher.c @@ -43,17 +43,36 @@ * RC4 */ -WINPR_RC4_CTX* winpr_RC4_New(const BYTE* key, size_t keylen) +WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOOL override_fips) { WINPR_RC4_CTX* ctx = NULL; +#if defined(WITH_OPENSSL) + EVP_CIPHER* evp = NULL; +#endif if (!key || (keylen == 0)) return NULL; #if defined(WITH_OPENSSL) - if (!(ctx = (WINPR_RC4_CTX*) calloc(1, sizeof(RC4_KEY)))) + if (!(ctx = EVP_CIPHER_CTX_new())) return NULL; - RC4_set_key((RC4_KEY*) ctx, keylen, key); + + evp = EVP_rc4(); + + if (!evp) + return NULL; + + EVP_CIPHER_CTX_init((EVP_CIPHER_CTX *) ctx); + EVP_EncryptInit_ex((EVP_CIPHER_CTX *) ctx, evp, NULL, NULL, NULL); + + /* 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((EVP_CIPHER_CTX *) ctx, EVP_CIPH_FLAG_NON_FIPS_ALLOW); +#endif + + EVP_CIPHER_CTX_set_key_length((EVP_CIPHER_CTX *) ctx, keylen); + EVP_EncryptInit_ex((EVP_CIPHER_CTX *) ctx, NULL, NULL, key, NULL); #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_ARC4_C) if (!(ctx = (WINPR_RC4_CTX*) calloc(1, sizeof(mbedtls_arc4_context)))) @@ -64,10 +83,21 @@ WINPR_RC4_CTX* winpr_RC4_New(const BYTE* key, size_t keylen) return ctx; } +WINPR_RC4_CTX* winpr_RC4_New_Allow_FIPS(const BYTE* key, size_t keylen) +{ + return winpr_RC4_New_Internal(key, keylen, TRUE); +} + +WINPR_RC4_CTX* winpr_RC4_New(const BYTE* key, size_t keylen) +{ + return winpr_RC4_New_Internal(key, keylen, FALSE); +} + BOOL winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output) { #if defined(WITH_OPENSSL) - RC4((RC4_KEY*) ctx, length, input, output); + int outputLength; + EVP_CipherUpdate((EVP_CIPHER_CTX *) ctx, output, &outputLength, input, length); return TRUE; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_ARC4_C) @@ -83,9 +113,7 @@ void winpr_RC4_Free(WINPR_RC4_CTX* ctx) return; #if defined(WITH_OPENSSL) - memset(ctx, 0, sizeof(RC4_KEY)); - free(ctx); - + EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *) ctx); #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_ARC4_C) mbedtls_arc4_free((mbedtls_arc4_context*) ctx); free(ctx); diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c index 27eb434f9..db529713b 100644 --- a/winpr/libwinpr/crypto/hash.c +++ b/winpr/libwinpr/crypto/hash.c @@ -143,29 +143,30 @@ mbedtls_md_type_t winpr_mbedtls_get_md_type(int md) WINPR_HMAC_CTX* winpr_HMAC_New(void) { WINPR_HMAC_CTX* ctx = NULL; - #if defined(WITH_OPENSSL) HMAC_CTX* hmac = NULL; #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) + if (!(hmac = (HMAC_CTX*) calloc(1, sizeof(HMAC_CTX)))) return NULL; + HMAC_CTX_init(hmac); #else + if (!(hmac = HMAC_CTX_new())) return NULL; + #endif ctx = (WINPR_HMAC_CTX*) hmac; - #elif defined(WITH_MBEDTLS) mbedtls_md_context_t* hmac; + if (!(hmac = (mbedtls_md_context_t*) calloc(1, sizeof(mbedtls_md_context_t)))) return NULL; mbedtls_md_init(hmac); - ctx = (WINPR_HMAC_CTX*) hmac; #endif - return ctx; } @@ -182,10 +183,11 @@ BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, siz HMAC_Init_ex(hmac, key, keylen, evp, NULL); /* no return value on OpenSSL 0.9.x */ return TRUE; #else + if (HMAC_Init_ex(hmac, key, keylen, evp, NULL) == 1) return TRUE; -#endif +#endif #elif defined(WITH_MBEDTLS) mbedtls_md_context_t* hmac = (mbedtls_md_context_t*) ctx; mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md); @@ -204,8 +206,8 @@ BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, siz if (mbedtls_md_hmac_starts(hmac, key, keylen) == 0) return TRUE; -#endif +#endif return FALSE; } @@ -213,21 +215,22 @@ BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen) { #if defined(WITH_OPENSSL) HMAC_CTX* hmac = (HMAC_CTX*) ctx; - #if (OPENSSL_VERSION_NUMBER < 0x10000000L) HMAC_Update(hmac, input, ilen); /* no return value on OpenSSL 0.9.x */ return TRUE; #else + if (HMAC_Update(hmac, input, ilen) == 1) return TRUE; -#endif +#endif #elif defined(WITH_MBEDTLS) mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*) ctx; + if (mbedtls_md_hmac_update(mdctx, input, ilen) == 0) return TRUE; -#endif +#endif return FALSE; } @@ -248,16 +251,18 @@ BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t olen) HMAC_Final(hmac, output, NULL); /* no return value on OpenSSL 0.9.x */ return TRUE; #else + if (HMAC_Final(hmac, output, NULL) == 1) return TRUE; -#endif +#endif #elif defined(WITH_MBEDTLS) mdctx = (mbedtls_md_context_t*) ctx; + if (mbedtls_md_hmac_finish(mdctx, output) == 0) return TRUE; -#endif +#endif return FALSE; } @@ -265,6 +270,7 @@ void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx) { #if defined(WITH_OPENSSL) HMAC_CTX* hmac = (HMAC_CTX*) ctx; + if (hmac) { #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) @@ -277,27 +283,31 @@ void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx) #elif defined(WITH_MBEDTLS) mbedtls_md_context_t* hmac = (mbedtls_md_context_t*) ctx; + if (hmac) { mbedtls_md_free(hmac); free(hmac); } + #endif } BOOL winpr_HMAC(WINPR_MD_TYPE md, const BYTE* key, size_t keylen, - const BYTE* input, size_t ilen, BYTE* output, size_t olen) + const BYTE* input, size_t ilen, BYTE* output, size_t olen) { BOOL result = FALSE; - WINPR_HMAC_CTX *ctx = winpr_HMAC_New(); + WINPR_HMAC_CTX* ctx = winpr_HMAC_New(); if (!ctx) return FALSE; if (!winpr_HMAC_Init(ctx, md, key, keylen)) goto out; + if (!winpr_HMAC_Update(ctx, input, ilen)) goto out; + if (!winpr_HMAC_Final(ctx, output, olen)) goto out; @@ -314,7 +324,6 @@ out: WINPR_DIGEST_CTX* winpr_Digest_New(void) { WINPR_DIGEST_CTX* ctx = NULL; - #if defined(WITH_OPENSSL) EVP_MD_CTX* mdctx; #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) @@ -323,23 +332,22 @@ WINPR_DIGEST_CTX* winpr_Digest_New(void) mdctx = EVP_MD_CTX_new(); #endif ctx = (WINPR_DIGEST_CTX*) mdctx; - #elif defined(WITH_MBEDTLS) mbedtls_md_context_t* mdctx; mdctx = (mbedtls_md_context_t*) calloc(1, sizeof(mbedtls_md_context_t)); + if (mdctx) mbedtls_md_init(mdctx); + ctx = (WINPR_DIGEST_CTX*) mdctx; #endif - return ctx; } -BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) -{ #if defined(WITH_OPENSSL) +BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md, const EVP_MD* evp) +{ EVP_MD_CTX* mdctx = (EVP_MD_CTX*) ctx; - const EVP_MD* evp = winpr_openssl_get_evp_md(md); if (!mdctx || !evp) return FALSE; @@ -347,7 +355,12 @@ BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) if (EVP_DigestInit_ex(mdctx, evp, NULL) != 1) return FALSE; + return TRUE; +} + #elif defined(WITH_MBEDTLS) +BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) +{ mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*) ctx; mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md); const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type); @@ -365,21 +378,57 @@ BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) if (mbedtls_md_starts(mdctx) != 0) return FALSE; -#endif return TRUE; } +#endif + +BOOL winpr_Digest_Init_Allow_FIPS(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) +{ +#if defined(WITH_OPENSSL) + EVP_MD_CTX* mdctx = (EVP_MD_CTX*) ctx; + const EVP_MD* evp = winpr_openssl_get_evp_md(md); + + /* Only MD5 is supported for FIPS allow override */ + if (md != WINPR_MD_MD5) + return FALSE; + + EVP_MD_CTX_set_flags(mdctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + return winpr_Digest_Init_Internal(ctx, md, evp); +#elif defined(WITH_MBEDTLS) + + /* Only MD5 is supported for FIPS allow override */ + if (md != WINPR_MD_MD5) + return FALSE; + + return winpr_Digest_Init_Internal(ctx, md); +#endif +} + +BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) +{ +#if defined(WITH_OPENSSL) + const EVP_MD* evp = winpr_openssl_get_evp_md(md); + return winpr_Digest_Init_Internal(ctx, md, evp); +#else + return winpr_Digest_Init_Internal(ctx, md); +#endif +} BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen) { #if defined(WITH_OPENSSL) EVP_MD_CTX* mdctx = (EVP_MD_CTX*) ctx; + if (EVP_DigestUpdate(mdctx, input, ilen) != 1) return FALSE; + #elif defined(WITH_MBEDTLS) mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*) ctx; + if (mbedtls_md_update(mdctx, input, ilen) != 0) return FALSE; + #endif return TRUE; } @@ -388,15 +437,17 @@ BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t olen) { #if defined(WITH_OPENSSL) EVP_MD_CTX* mdctx = (EVP_MD_CTX*) ctx; + if (EVP_DigestFinal_ex(mdctx, output, NULL) == 1) return TRUE; #elif defined(WITH_MBEDTLS) mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*) ctx; + if (mbedtls_md_finish(mdctx, output) == 0) return TRUE; -#endif +#endif return FALSE; } @@ -404,6 +455,7 @@ void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx) { #if defined(WITH_OPENSSL) EVP_MD_CTX* mdctx = (EVP_MD_CTX*) ctx; + if (mdctx) { #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) @@ -415,26 +467,53 @@ void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx) #elif defined(WITH_MBEDTLS) mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*) ctx; + if (mdctx) { mbedtls_md_free(mdctx); free(mdctx); } + #endif } -BOOL winpr_Digest(int md, const BYTE* input, size_t ilen, BYTE* output, size_t olen) +BOOL winpr_Digest_Allow_FIPS(int md, const BYTE* input, size_t ilen, BYTE* output, size_t olen) { BOOL result = FALSE; - WINPR_DIGEST_CTX *ctx = winpr_Digest_New(); + WINPR_DIGEST_CTX* ctx = winpr_Digest_New(); if (!ctx) return FALSE; - if (!winpr_Digest_Init(ctx, md)) + if (!winpr_Digest_Init_Allow_FIPS(ctx, md)) goto out; + if (!winpr_Digest_Update(ctx, input, ilen)) goto out; + + if (!winpr_Digest_Final(ctx, output, olen)) + goto out; + + result = TRUE; +out: + winpr_Digest_Free(ctx); + return result; +} + +BOOL winpr_Digest(int md, const BYTE* input, size_t ilen, BYTE* output, size_t olen) +{ + BOOL result = FALSE; + WINPR_DIGEST_CTX* ctx = winpr_Digest_New(); + + if (!ctx) + return FALSE; + + if (!winpr_Digest_Init(ctx, md)) + goto out; + + if (!winpr_Digest_Update(ctx, input, ilen)) + goto out; + if (!winpr_Digest_Final(ctx, output, olen)) goto out; diff --git a/winpr/libwinpr/utils/ssl.c b/winpr/libwinpr/utils/ssl.c index 322bb491f..7d6d7d6a7 100644 --- a/winpr/libwinpr/utils/ssl.c +++ b/winpr/libwinpr/utils/ssl.c @@ -276,6 +276,25 @@ static BOOL CALLBACK _winpr_openssl_initialize(PINIT_ONCE once, PVOID param, PVO #endif g_winpr_openssl_initialized_by_winpr = TRUE; + + if (flags & WINPR_SSL_INIT_ENABLE_FIPS) + { +#if (OPENSSL_VERSION_NUMBER < 0x10001000L) + WLog_ERR(TAG, "Openssl fips mode ENable not available on openssl versions less than 1.0.1!"); +#else + WLog_DBG(TAG, "Ensuring openssl fips mode is ENabled"); + + if (FIPS_mode() != 1) + { + if (FIPS_mode_set(1)) + WLog_INFO(TAG, "Openssl fips mode ENabled!"); + else + WLog_ERR(TAG, "Openssl fips mode ENable failed!"); + } + +#endif + } + return TRUE; }