From 18cb418c8199821fa63c992e1cd81ba8f50c5789 Mon Sep 17 00:00:00 2001 From: Norbert Federa Date: Wed, 2 Apr 2014 14:17:39 +0200 Subject: [PATCH] core: FIPS for fastpath and RDP security fixes - fixed invalid stream position if extEncryptionMethods is not used - enabled 56bit rdp security method - fixed entropy reduction of the keys for 40 bit and 56 bit - added rdp security incl. FIPS for fastpath output - added FIPS encryption to fast path input - fixed FIPS key generation in server mode - fixed stream length correction in FIPS mode - added rdp encryption for licensing packets (apparently some clients, specifically cetsc, require the license packets received from the server to be encrypted under certain RDP encryption levels) - replace errnous virtual extended mouse event in focus in event --- client/common/cmdline.c | 2 +- client/common/compatibility.c | 2 +- libfreerdp/core/connection.c | 2 +- libfreerdp/core/fastpath.c | 160 ++++++++++++++++++++++++++-------- libfreerdp/core/gcc.c | 6 ++ libfreerdp/core/input.c | 2 +- libfreerdp/core/license.c | 33 +++---- libfreerdp/core/license.h | 2 +- libfreerdp/core/nego.c | 4 +- libfreerdp/core/rdp.c | 20 ++--- libfreerdp/core/security.c | 52 +++++++---- 11 files changed, 198 insertions(+), 87 deletions(-) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 2e4d2f01f..d8701a28a 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -1601,7 +1601,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->NlaSecurity = FALSE; settings->ExtSecurity = FALSE; settings->DisableEncryption = TRUE; - settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; + settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT| ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; } else if (strcmp("tls", arg->Value) == 0) /* TLS */ diff --git a/client/common/compatibility.c b/client/common/compatibility.c index 094faf75e..aeda88a2e 100644 --- a/client/common/compatibility.c +++ b/client/common/compatibility.c @@ -693,7 +693,7 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe settings->TlsSecurity = FALSE; settings->NlaSecurity = FALSE; settings->DisableEncryption = FALSE; - settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; + settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; } else if (strncmp("tls", arg->Value, 1) == 0) /* TLS */ diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 5beb44f90..b06b4e0fb 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -427,7 +427,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) s = Stream_New(NULL, length); rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID); - rdp_write_security_header(s, SEC_EXCHANGE_PKT); + rdp_write_security_header(s, SEC_EXCHANGE_PKT | SEC_LICENSE_ENCRYPT_SC); length = key_len + 8; Stream_Write_UINT32(s, length); diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index 9d5157567..48bf5b224 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -3,6 +3,7 @@ * Fast Path * * Copyright 2011 Vic Lee + * Copyright 2014 Norbert Federa * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -137,7 +138,7 @@ UINT32 fastpath_get_update_header_size(FASTPATH_UPDATE_HEADER* fpUpdateHeader) return (fpUpdateHeader->compression) ? 4 : 3; } -void fastpath_write_update_pdu_header(wStream* s, FASTPATH_UPDATE_PDU_HEADER* fpUpdatePduHeader) +void fastpath_write_update_pdu_header(wStream* s, FASTPATH_UPDATE_PDU_HEADER* fpUpdatePduHeader, rdpRdp* rdp) { fpUpdatePduHeader->fpOutputHeader = 0; fpUpdatePduHeader->fpOutputHeader |= (fpUpdatePduHeader->action & 0x03); @@ -147,18 +148,25 @@ void fastpath_write_update_pdu_header(wStream* s, FASTPATH_UPDATE_PDU_HEADER* fp Stream_Write_UINT8(s, 0x80 | (fpUpdatePduHeader->length >> 8)); /* length1 */ Stream_Write_UINT8(s, fpUpdatePduHeader->length & 0xFF); /* length2 */ -} - -UINT32 fastpath_get_update_pdu_header_size(FASTPATH_UPDATE_PDU_HEADER* fpUpdatePduHeader) -{ - UINT32 size = 1; - - size += 2; if (fpUpdatePduHeader->secFlags) { - size += 4; - size += 8; + if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) + Stream_Write(s, fpUpdatePduHeader->fipsInformation, 4); + Stream_Write(s, fpUpdatePduHeader->dataSignature, 8); + } +} + +UINT32 fastpath_get_update_pdu_header_size(FASTPATH_UPDATE_PDU_HEADER* fpUpdatePduHeader, rdpRdp* rdp) +{ + UINT32 size = 3; /* fpUpdatePduHeader + length1 + length2 */ + + if (fpUpdatePduHeader->secFlags) + { + size += 8; /* dataSignature */ + + if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) + size += 4; /* fipsInformation */ } return size; @@ -746,7 +754,6 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNu rdpRdp* rdp; UINT16 length; BYTE eventHeader; - int sec_bytes; /* * A maximum of 15 events are allowed per request @@ -776,7 +783,48 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNu Stream_SetPosition(s, 0); Stream_Write_UINT8(s, eventHeader); - sec_bytes = fastpath_get_sec_bytes(fastpath->rdp); + + /* Write length later, RDP encryption might add a padding */ + Stream_Seek(s, 2); + + if (rdp->sec_flags & SEC_ENCRYPT) + { + int sec_bytes = fastpath_get_sec_bytes(fastpath->rdp); + BYTE* fpInputEvents = Stream_Pointer(s) + sec_bytes; + UINT16 fpInputEvents_length = length - 3 - sec_bytes; + + if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) + { + BYTE pad; + + if ((pad = 8 - (fpInputEvents_length % 8)) == 8) + pad = 0; + + Stream_Write_UINT16(s, 0x10); /* length */ + Stream_Write_UINT8(s, 0x1); /* TSFIPS_VERSION 1*/ + Stream_Write_UINT8(s, pad); /* padding */ + + security_hmac_signature(fpInputEvents, fpInputEvents_length, Stream_Pointer(s), rdp); + + if (pad) + memset(fpInputEvents + fpInputEvents_length, 0, pad); + + security_fips_encrypt(fpInputEvents, fpInputEvents_length + pad, rdp); + + length += pad; + } + else + { + if (rdp->sec_flags & SEC_SECURE_CHECKSUM) + security_salted_mac_signature(rdp, fpInputEvents, fpInputEvents_length, TRUE, Stream_Pointer(s)); + else + security_mac_signature(rdp, fpInputEvents, fpInputEvents_length, Stream_Pointer(s)); + + security_encrypt(fpInputEvents, fpInputEvents_length, rdp); + } + } + + rdp->sec_flags = 0; /* * We always encode length in two bytes, even though we could use @@ -784,26 +832,9 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNu * because we can leave room for fixed-length header, store all * the data first and then store the header. */ + Stream_SetPosition(s, 1); Stream_Write_UINT16_BE(s, 0x8000 | length); - if (sec_bytes > 0) - { - BYTE* fpInputEvents; - UINT16 fpInputEvents_length; - - fpInputEvents = Stream_Pointer(s) + sec_bytes; - fpInputEvents_length = length - 3 - sec_bytes; - - if (rdp->sec_flags & SEC_SECURE_CHECKSUM) - security_salted_mac_signature(rdp, fpInputEvents, fpInputEvents_length, TRUE, Stream_Pointer(s)); - else - security_mac_signature(rdp, fpInputEvents, fpInputEvents_length, Stream_Pointer(s)); - - security_encrypt(fpInputEvents, fpInputEvents_length, rdp); - } - - rdp->sec_flags = 0; - Stream_SetPosition(s, length); Stream_SealLength(s); @@ -860,6 +891,14 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s maxLength -= 20; } + if (rdp->do_crypt) + { + rdp->sec_flags |= SEC_ENCRYPT; + + if (rdp->do_secure_checksum) + rdp->sec_flags |= SEC_SECURE_CHECKSUM; + } + totalLength = Stream_GetPosition(s); Stream_SetPosition(s, 0); @@ -870,6 +909,8 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s UINT32 DstSize = 0; BYTE* pDstData = NULL; UINT32 compressionFlags = 0; + BYTE pad = 0; + BYTE* pSignature; fpUpdatePduHeader.action = 0; fpUpdatePduHeader.secFlags = 0; @@ -882,6 +923,11 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s pSrcData = pDstData = Stream_Pointer(s); SrcSize = DstSize = fpUpdateHeader.size; + if (rdp->sec_flags & SEC_ENCRYPT) + fpUpdatePduHeader.secFlags |= FASTPATH_OUTPUT_ENCRYPTED; + if (rdp->sec_flags & SEC_SECURE_CHECKSUM) + fpUpdatePduHeader.secFlags |= FASTPATH_OUTPUT_SECURE_CHECKSUM; + if (settings->CompressionEnabled) { if (bulk_compress(rdp->bulk, pSrcData, SrcSize, &pDstData, &DstSize, &compressionFlags) >= 0) @@ -909,16 +955,58 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s fpUpdateHeader.fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT; fpUpdateHeaderSize = fastpath_get_update_header_size(&fpUpdateHeader); - fpUpdatePduHeaderSize = fastpath_get_update_pdu_header_size(&fpUpdatePduHeader); + fpUpdatePduHeaderSize = fastpath_get_update_pdu_header_size(&fpUpdatePduHeader, rdp); fpHeaderSize = fpUpdateHeaderSize + fpUpdatePduHeaderSize; - fpUpdatePduHeader.length = fpUpdateHeader.size + fpHeaderSize; + + if (rdp->sec_flags & SEC_ENCRYPT) + { + pSignature = Stream_Buffer(fs) + 3; + + if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) + { + pSignature += 4; + + if ((pad = 8 - ((DstSize + fpUpdateHeaderSize) % 8)) == 8) + pad = 0; + + fpUpdatePduHeader.fipsInformation[0] = 0x10; + fpUpdatePduHeader.fipsInformation[1] = 0x00; + fpUpdatePduHeader.fipsInformation[2] = 0x01; + fpUpdatePduHeader.fipsInformation[3] = pad; + } + } + + fpUpdatePduHeader.length = fpUpdateHeader.size + fpHeaderSize + pad; Stream_SetPosition(fs, 0); - - fastpath_write_update_pdu_header(fs, &fpUpdatePduHeader); + fastpath_write_update_pdu_header(fs, &fpUpdatePduHeader, rdp); fastpath_write_update_header(fs, &fpUpdateHeader); - Stream_Write(fs, pDstData, DstSize); + + if (pad) + Stream_Zero(fs, pad); + + if (rdp->sec_flags & SEC_ENCRYPT) + { + UINT32 dataSize = fpUpdateHeaderSize + DstSize + pad; + BYTE *data = Stream_Pointer(fs) - dataSize; + + if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) + { + security_hmac_signature(data, dataSize - pad, pSignature, rdp); + security_fips_encrypt(data, dataSize, rdp); + } + else + { + if (rdp->sec_flags & SEC_SECURE_CHECKSUM) + security_salted_mac_signature(rdp, data, dataSize, TRUE, pSignature); + else + security_mac_signature(rdp, data, dataSize, pSignature); + + security_encrypt(data, dataSize, rdp); + } + } + Stream_SealLength(fs); if (transport_write(rdp->transport, fs) < 0) @@ -930,6 +1018,8 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s Stream_Seek(s, SrcSize); } + rdp->sec_flags = 0; + return status; } diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c index 9e716b04e..9d8932aef 100644 --- a/libfreerdp/core/gcc.c +++ b/libfreerdp/core/gcc.c @@ -916,6 +916,8 @@ BOOL gcc_read_client_security_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) Stream_Read_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */ if (settings->EncryptionMethods == 0) Stream_Read_UINT32(s, settings->EncryptionMethods); /* extEncryptionMethods */ + else + Stream_Seek(s, 4); } else { @@ -1082,6 +1084,10 @@ void gcc_write_server_security_data(wStream* s, rdpMcs* mcs) { settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT; } + else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_56BIT) != 0) + { + settings->EncryptionMethods = ENCRYPTION_METHOD_56BIT; + } else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_40BIT) != 0) { settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT; diff --git a/libfreerdp/core/input.c b/libfreerdp/core/input.c index 546fc4c7c..a929b0d96 100644 --- a/libfreerdp/core/input.c +++ b/libfreerdp/core/input.c @@ -163,7 +163,7 @@ void input_send_focus_in_event(rdpInput* input, UINT16 toggleStates, UINT16 x, U input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f); /* finish with a mouse pointer position like mstsc.exe */ - input_send_extended_mouse_event(input, PTR_FLAGS_MOVE, x, y); + input_send_mouse_event(input, PTR_FLAGS_MOVE, x, y); } void input_send_fastpath_synchronize_event(rdpInput* input, UINT32 flags) diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c index e91aba6e0..29d6403bf 100644 --- a/libfreerdp/core/license.c +++ b/libfreerdp/core/license.c @@ -3,6 +3,7 @@ * RDP Licensing * * Copyright 2011-2013 Marc-Andre Moreau + * Copyright 2014 Norbert Federa * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -163,8 +164,15 @@ wStream* license_send_stream_init(rdpLicense* license) { wStream* s; - s = Stream_New(NULL, 4096); - Stream_Seek(s, LICENSE_PACKET_HEADER_MAX_LENGTH); + license->rdp->sec_flags = SEC_LICENSE_PKT; + if (license->rdp->do_crypt) + license->rdp->sec_flags |= SEC_LICENSE_ENCRYPT_CS; + + s = transport_send_stream_init(license->rdp->transport, 4096); + rdp_init_stream(license->rdp, s); + + license->PacketHeaderLength = Stream_GetPosition(s); + Stream_Seek(s, LICENSE_PREAMBLE_LENGTH); return s; } @@ -181,15 +189,13 @@ BOOL license_send(rdpLicense* license, wStream* s, BYTE type) int length; BYTE flags; UINT16 wMsgSize; - UINT16 sec_flags; + rdpRdp* rdp = license->rdp; DEBUG_LICENSE("Sending %s Packet", LICENSE_MESSAGE_STRINGS[type & 0x1F]); length = Stream_GetPosition(s); - Stream_SetPosition(s, 0); - - sec_flags = SEC_LICENSE_PKT; - wMsgSize = length - LICENSE_PACKET_HEADER_MAX_LENGTH + 4; + wMsgSize = length - license->PacketHeaderLength; + Stream_SetPosition(s, license->PacketHeaderLength); flags = PREAMBLE_VERSION_3_0; @@ -198,25 +204,20 @@ BOOL license_send(rdpLicense* license, wStream* s, BYTE type) * running in server mode! This flag seems to be incorrectly documented. */ - if (!license->rdp->settings->ServerMode) + if (!rdp->settings->ServerMode) flags |= EXTENDED_ERROR_MSG_SUPPORTED; - rdp_write_header(license->rdp, s, length, MCS_GLOBAL_CHANNEL_ID); - rdp_write_security_header(s, sec_flags); license_write_preamble(s, type, flags, wMsgSize); #ifdef WITH_DEBUG_LICENSE fprintf(stderr, "Sending %s Packet, length %d\n", LICENSE_MESSAGE_STRINGS[type & 0x1F], wMsgSize); - winpr_HexDump(Stream_Pointer(s) - 4, wMsgSize); + winpr_HexDump(Stream_Pointer(s) - LICENSE_PREAMBLE_LENGTH, wMsgSize); #endif Stream_SetPosition(s, length); - Stream_SealLength(s); + rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID); - if (transport_write(license->rdp->transport, s) < 0) - return FALSE; - - Stream_Free(s, TRUE); + rdp->sec_flags = 0; return TRUE; } diff --git a/libfreerdp/core/license.h b/libfreerdp/core/license.h index 38955e98d..547c710ef 100644 --- a/libfreerdp/core/license.h +++ b/libfreerdp/core/license.h @@ -48,7 +48,6 @@ typedef struct rdp_license rdpLicense; #define LICENSE_PKT_MASK (LICENSE_PKT_CS_MASK | LICENSE_PKT_SC_MASK) #define LICENSE_PREAMBLE_LENGTH 4 -#define LICENSE_PACKET_HEADER_MAX_LENGTH (RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + LICENSE_PREAMBLE_LENGTH) /* Cryptographic Lengths */ @@ -198,6 +197,7 @@ struct rdp_license LICENSE_BLOB* EncryptedPlatformChallenge; LICENSE_BLOB* EncryptedHardwareId; SCOPE_LIST* ScopeList; + UINT32 PacketHeaderLength; }; int license_recv(rdpLicense* license, wStream* s); diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index c53c6e610..8f7028231 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -156,7 +156,7 @@ BOOL nego_connect(rdpNego* nego) if (nego->selected_protocol == PROTOCOL_RDP) { nego->transport->settings->DisableEncryption = TRUE; - nego->transport->settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; + nego->transport->settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; nego->transport->settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; } @@ -939,7 +939,7 @@ BOOL nego_send_negotiation_response(rdpNego* nego) if (!settings->LocalConnection) { settings->DisableEncryption = TRUE; - settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; + settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; } diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 8dd4ccbb5..9533ac7e1 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -291,11 +291,19 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) { int reason = 0; TerminateEventArgs e; - rdpContext* context = rdp->instance->context; + rdpContext* context; if (!mcs_recv_disconnect_provider_ultimatum(rdp->mcs, s, &reason)) return FALSE; + if (rdp->instance == NULL) + { + rdp->disconnect = TRUE; + return FALSE; + } + + context = rdp->instance->context; + if (rdp->errorInfo == ERRINFO_SUCCESS) { /** @@ -467,20 +475,13 @@ static UINT32 rdp_get_sec_bytes(rdpRdp* rdp) BOOL rdp_send(rdpRdp* rdp, wStream* s, UINT16 channel_id) { - int secm; UINT16 length; - UINT32 sec_bytes; length = Stream_GetPosition(s); Stream_SetPosition(s, 0); rdp_write_header(rdp, s, length, channel_id); - sec_bytes = rdp_get_sec_bytes(rdp); - secm = Stream_GetPosition(s); - Stream_Seek(s, sec_bytes); - - Stream_SetPosition(s, secm); length += rdp_security_stream_out(rdp, s, length, 0); Stream_SetPosition(s, length); @@ -932,8 +933,7 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags) return FALSE; /* TODO */ } - /* is this what needs adjusting? */ - Stream_Capacity(s) -= pad; + Stream_Length(s) -= pad; return TRUE; } diff --git a/libfreerdp/core/security.c b/libfreerdp/core/security.c index 0712788e5..ccc6344f0 100644 --- a/libfreerdp/core/security.c +++ b/libfreerdp/core/security.c @@ -3,6 +3,7 @@ * RDP Security * * Copyright 2011 Marc-Andre Moreau + * Copyright 2014 Norbert Federa * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -406,7 +407,7 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) BYTE master_secret[48]; BYTE session_key_blob[48]; BYTE* server_random; - BYTE salt40[] = { 0xD1, 0x26, 0x9E }; + BYTE salt[] = { 0xD1, 0x26, 0x9E }; /* 40 bits: 3 bytes, 56 bits: 1 byte */ rdpSettings* settings; settings = rdp->settings; @@ -420,9 +421,6 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) fprintf(stderr, "FIPS Compliant encryption level.\n"); - /* disable fastpath input; it doesnt handle FIPS encryption yet */ - rdp->settings->FastPathInput = FALSE; - sha1 = crypto_sha1_init(); if (!sha1) { @@ -432,9 +430,7 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) crypto_sha1_update(sha1, client_random + 16, 16); crypto_sha1_update(sha1, server_random + 16, 16); crypto_sha1_final(sha1, client_encrypt_key_t); - client_encrypt_key_t[20] = client_encrypt_key_t[0]; - fips_expand_key_bits(client_encrypt_key_t, rdp->fips_encrypt_key); sha1 = crypto_sha1_init(); if (!sha1) @@ -445,9 +441,7 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) crypto_sha1_update(sha1, client_random, 16); crypto_sha1_update(sha1, server_random, 16); crypto_sha1_final(sha1, client_decrypt_key_t); - client_decrypt_key_t[20] = client_decrypt_key_t[0]; - fips_expand_key_bits(client_decrypt_key_t, rdp->fips_decrypt_key); sha1 = crypto_sha1_init(); if (!sha1) @@ -458,6 +452,17 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) crypto_sha1_update(sha1, client_decrypt_key_t, 20); crypto_sha1_update(sha1, client_encrypt_key_t, 20); crypto_sha1_final(sha1, rdp->fips_sign_key); + + if (rdp->settings->ServerMode) + { + fips_expand_key_bits(client_encrypt_key_t, rdp->fips_decrypt_key); + fips_expand_key_bits(client_decrypt_key_t, rdp->fips_encrypt_key); + } + else + { + fips_expand_key_bits(client_encrypt_key_t, rdp->fips_encrypt_key); + fips_expand_key_bits(client_decrypt_key_t, rdp->fips_decrypt_key); + } } memcpy(pre_master_secret, client_random, 24); @@ -483,14 +488,21 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) server_random, rdp->encrypt_key); } - if (settings->EncryptionMethods == 1) /* 40 and 56 bit */ + if (settings->EncryptionMethods == ENCRYPTION_METHOD_40BIT) { - memcpy(rdp->sign_key, salt40, 3); /* TODO 56 bit */ - memcpy(rdp->decrypt_key, salt40, 3); /* TODO 56 bit */ - memcpy(rdp->encrypt_key, salt40, 3); /* TODO 56 bit */ + memcpy(rdp->sign_key, salt, 3); + memcpy(rdp->decrypt_key, salt, 3); + memcpy(rdp->encrypt_key, salt, 3); rdp->rc4_key_len = 8; } - else if (settings->EncryptionMethods == 2) /* 128 bit */ + else if (settings->EncryptionMethods == ENCRYPTION_METHOD_56BIT) + { + memcpy(rdp->sign_key, salt, 1); + memcpy(rdp->decrypt_key, salt, 1); + memcpy(rdp->encrypt_key, salt, 1); + rdp->rc4_key_len = 8; + } + else if (settings->EncryptionMethods == ENCRYPTION_METHOD_128BIT) { rdp->rc4_key_len = 16; } @@ -505,13 +517,13 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) return TRUE; } -BOOL security_key_update(BYTE* key, BYTE* update_key, int key_len) +BOOL security_key_update(BYTE* key, BYTE* update_key, int key_len, rdpRdp* rdp) { BYTE sha1h[CRYPTO_SHA1_DIGEST_LENGTH]; CryptoMd5 md5; CryptoSha1 sha1; CryptoRc4 rc4; - BYTE salt40[] = { 0xD1, 0x26, 0x9E }; + BYTE salt[] = { 0xD1, 0x26, 0x9E }; /* 40 bits: 3 bytes, 56 bits: 1 byte */ sha1 = crypto_sha1_init(); if (!sha1) @@ -544,8 +556,10 @@ BOOL security_key_update(BYTE* key, BYTE* update_key, int key_len) crypto_rc4(rc4, key_len, key, key); crypto_rc4_free(rc4); - if (key_len == 8) - memcpy(key, salt40, 3); /* TODO 56 bit */ + if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_40BIT) + memcpy(key, salt, 3); + else if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_56BIT) + memcpy(key, salt, 1); return TRUE; } @@ -554,7 +568,7 @@ BOOL security_encrypt(BYTE* data, int length, rdpRdp* rdp) { if (rdp->encrypt_use_count >= 4096) { - security_key_update(rdp->encrypt_key, rdp->encrypt_update_key, rdp->rc4_key_len); + security_key_update(rdp->encrypt_key, rdp->encrypt_update_key, rdp->rc4_key_len, rdp); crypto_rc4_free(rdp->rc4_encrypt_key); rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len); if (!rdp->rc4_encrypt_key) @@ -576,7 +590,7 @@ BOOL security_decrypt(BYTE* data, int length, rdpRdp* rdp) return FALSE; if (rdp->decrypt_use_count >= 4096) { - security_key_update(rdp->decrypt_key, rdp->decrypt_update_key, rdp->rc4_key_len); + security_key_update(rdp->decrypt_key, rdp->decrypt_update_key, rdp->rc4_key_len, rdp); crypto_rc4_free(rdp->rc4_decrypt_key); rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len); if (!rdp->rc4_decrypt_key)