diff options
author | Marc-André Moreau <marcandre.moreau@gmail.com> | 2011-06-29 07:13:47 +0400 |
---|---|---|
committer | Marc-André Moreau <marcandre.moreau@gmail.com> | 2011-06-29 07:13:47 +0400 |
commit | 88d53073073c6584cdfd6d1ddc74ef162de73e84 (patch) | |
tree | 27aef0e0f7dc65b5c2320686ae5c691e435425a7 | |
parent | 4bd25818ea7aea270e047504b4cefe3b259b49d7 (diff) |
libfreerdp-core: split secure.c into security.c and connect.c
-rw-r--r-- | dbg.txt | 0 | ||||
-rw-r--r-- | libfreerdp-core/Makefile.am | 3 | ||||
-rw-r--r-- | libfreerdp-core/asn1.c | 2 | ||||
-rw-r--r-- | libfreerdp-core/chan.c | 2 | ||||
-rw-r--r-- | libfreerdp-core/connect.c (renamed from libfreerdp-core/secure.c) | 588 | ||||
-rw-r--r-- | libfreerdp-core/connect.h | 26 | ||||
-rw-r--r-- | libfreerdp-core/credssp.c | 2 | ||||
-rw-r--r-- | libfreerdp-core/freerdp.c | 2 | ||||
-rw-r--r-- | libfreerdp-core/iso.c | 2 | ||||
-rw-r--r-- | libfreerdp-core/license.c | 2 | ||||
-rw-r--r-- | libfreerdp-core/mcs.c | 7 | ||||
-rw-r--r-- | libfreerdp-core/network.h | 2 | ||||
-rw-r--r-- | libfreerdp-core/ntlmssp.h | 2 | ||||
-rw-r--r-- | libfreerdp-core/rail.c | 2 | ||||
-rw-r--r-- | libfreerdp-core/rdp.c | 2 | ||||
-rw-r--r-- | libfreerdp-core/security.c | 549 | ||||
-rw-r--r-- | libfreerdp-core/security.h (renamed from libfreerdp-core/secure.h) | 18 | ||||
-rw-r--r-- | libfreerdp-core/tcp.c | 1 |
18 files changed, 635 insertions, 577 deletions
diff --git a/dbg.txt b/dbg.txt deleted file mode 100644 index e69de29..0000000 --- a/dbg.txt +++ /dev/null diff --git a/libfreerdp-core/Makefile.am b/libfreerdp-core/Makefile.am index b8ba907..140b39a 100644 --- a/libfreerdp-core/Makefile.am +++ b/libfreerdp-core/Makefile.am @@ -10,6 +10,7 @@ libfreerdp_core_la_SOURCES = \ bitmap.c bitmap.h \ cache.c cache.h \ capabilities.c capabilities.h \ + connect.c connect.h \ chan.c chan.h \ ext.c ext.h \ freerdp.c \ @@ -22,7 +23,7 @@ libfreerdp_core_la_SOURCES = \ pstcache.c pstcache.h \ rail.c rail.h \ rdp.c rdp.h \ - secure.c secure.h \ + security.c security.h \ network.c network.h \ crypto.h \ tcp.c tcp.h \ diff --git a/libfreerdp-core/asn1.c b/libfreerdp-core/asn1.c index e1896d6..11fc19b 100644 --- a/libfreerdp-core/asn1.c +++ b/libfreerdp-core/asn1.c @@ -21,9 +21,9 @@ #include "iso.h" #include "mcs.h" #include "chan.h" -#include "secure.h" #include "rdp.h" #include "asn1.h" +#include "security.h" /* Parse an ASN.1 BER header */ RD_BOOL diff --git a/libfreerdp-core/chan.c b/libfreerdp-core/chan.c index 5e94bdd..267cfe7 100644 --- a/libfreerdp-core/chan.c +++ b/libfreerdp-core/chan.c @@ -20,8 +20,8 @@ #include "frdp.h" #include "chan.h" #include "mcs.h" -#include "secure.h" #include "rdp.h" +#include "security.h" #include <freerdp/rdpset.h> #include <freerdp/utils/memory.h> #include <freerdp/constants/vchan.h> diff --git a/libfreerdp-core/secure.c b/libfreerdp-core/connect.c index 8b6f185..0345dc0 100644 --- a/libfreerdp-core/secure.c +++ b/libfreerdp-core/connect.c @@ -1,8 +1,8 @@ /* FreeRDP: A Remote Desktop Protocol client. - RDP encryption and licensing + Connection Sequence - Copyright (C) Matthew Chapman 1999-2008 + Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,381 +17,25 @@ limitations under the License. */ -#include "frdp.h" -#include "mcs.h" -#include "chan.h" -#include "license.h" #include "rdp.h" -#include "iso.h" -#include "tcp.h" +#include "nego.h" +#include "security.h" #include <freerdp/rdpset.h> +#include <freerdp/freerdp.h> #include <freerdp/utils/memory.h> +#include <freerdp/utils/unicode.h> -#ifndef DISABLE_TLS -#include "tls.h" -#include "credssp.h" -#endif - -#include "secure.h" - -static RD_BOOL sec_global_initialized = False; - -RD_BOOL -sec_global_init(void) -{ - if (!sec_global_initialized) - { - sec_global_initialized = crypto_global_init(); - } - return sec_global_initialized; -} - -void -sec_global_finish(void) -{ - crypto_global_finish(); - sec_global_initialized = False; -} - -/* these are read only */ -static uint8 pad_54[40] = { - 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54 -}; - -static uint8 pad_92[48] = { - 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92 -}; - -/* - * 48-byte transformation used to generate master secret (6.1) and key material (6.2.2). - * Both SHA1 and MD5 algorithms are used. - */ -void -sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt) -{ - int i; - uint8 pad[4]; - uint8 shasig[20]; - CryptoMd5 md5; - CryptoSha1 sha1; - - for (i = 0; i < 3; i++) - { - memset(pad, salt + i, i + 1); - - sha1 = crypto_sha1_init(); - crypto_sha1_update(sha1, pad, i + 1); - crypto_sha1_update(sha1, in, 48); - crypto_sha1_update(sha1, salt1, 32); - crypto_sha1_update(sha1, salt2, 32); - crypto_sha1_final(sha1, shasig); - - md5 = crypto_md5_init(); - crypto_md5_update(md5, in, 48); - crypto_md5_update(md5, shasig, 20); - crypto_md5_final(md5, &out[i * 16]); - } -} - -/* - * 16-byte transformation used to generate export keys (6.2.2). - */ -void -sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2) -{ - CryptoMd5 md5 = crypto_md5_init(); - crypto_md5_update(md5, in, 16); - crypto_md5_update(md5, salt1, 32); - crypto_md5_update(md5, salt2, 32); - crypto_md5_final(md5, out); -} - -/* Reduce key entropy from 64 to 40 bits */ -static void -sec_make_40bit(uint8 * key) -{ - key[0] = 0xd1; - key[1] = 0x26; - key[2] = 0x9e; -} - -/* Generate encryption keys given client and server randoms */ -static void -sec_generate_keys(rdpSec * sec, uint8 * client_random, uint8 * server_random, int rc4_key_size) -{ - uint8 pre_master_secret[48]; - uint8 master_secret[48]; - uint8 key_block[48]; - - /* Construct pre-master secret */ - memcpy(pre_master_secret, client_random, 24); - memcpy(pre_master_secret + 24, server_random, 24); - - /* Generate master secret and then key material */ - sec_hash_48(master_secret, pre_master_secret, client_random, server_random, 'A'); - sec_hash_48(key_block, master_secret, client_random, server_random, 'X'); - - /* First 16 bytes of key material is MAC secret */ - memcpy(sec->sec_sign_key, key_block, 16); - - /* Generate export keys from next two blocks of 16 bytes */ - sec_hash_16(sec->sec_decrypt_key, &key_block[16], client_random, server_random); - sec_hash_16(sec->sec_encrypt_key, &key_block[32], client_random, server_random); - - if (rc4_key_size == 1) - { - DEBUG_SEC("40-bit encryption enabled"); - sec_make_40bit(sec->sec_sign_key); - sec_make_40bit(sec->sec_decrypt_key); - sec_make_40bit(sec->sec_encrypt_key); - sec->rc4_key_len = 8; - } - else - { - DEBUG_SEC("rc_4_key_size == %d, 128-bit encryption enabled", rc4_key_size); - sec->rc4_key_len = 16; - } - - /* Save initial RC4 keys as update keys */ - memcpy(sec->sec_decrypt_update_key, sec->sec_decrypt_key, 16); - memcpy(sec->sec_encrypt_update_key, sec->sec_encrypt_key, 16); - - /* Initialize RC4 state arrays */ - sec->rc4_decrypt_key = crypto_rc4_init(sec->sec_decrypt_key, sec->rc4_key_len); - sec->rc4_encrypt_key = crypto_rc4_init(sec->sec_encrypt_key, sec->rc4_key_len); -} - -/* Output a uint32 into a buffer (little-endian) */ -void -buf_out_uint32(uint8 * buffer, uint32 value) -{ - buffer[0] = (value) & 0xff; - buffer[1] = (value >> 8) & 0xff; - buffer[2] = (value >> 16) & 0xff; - buffer[3] = (value >> 24) & 0xff; -} +#include "connect.h" -/* Generate a MAC hash (5.2.3.1), using a combination of SHA1 and MD5 */ -void -sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data, int datalen) -{ - uint8 shasig[20]; - uint8 md5sig[16]; - uint8 lenhdr[4]; - CryptoSha1 sha1; - CryptoMd5 md5; - - buf_out_uint32(lenhdr, datalen); - - sha1 = crypto_sha1_init(); - crypto_sha1_update(sha1, session_key, keylen); - crypto_sha1_update(sha1, pad_54, 40); - crypto_sha1_update(sha1, lenhdr, 4); - crypto_sha1_update(sha1, data, datalen); - crypto_sha1_final(sha1, shasig); - - md5 = crypto_md5_init(); - crypto_md5_update(md5, session_key, keylen); - crypto_md5_update(md5, pad_92, 48); - crypto_md5_update(md5, shasig, 20); - crypto_md5_final(md5, md5sig); - - memcpy(signature, md5sig, siglen); -} - -/* Update an encryption key */ static void -sec_update(rdpSec * sec, uint8 * key, uint8 * update_key) -{ - uint8 shasig[20]; - CryptoSha1 sha1; - CryptoMd5 md5; - CryptoRc4 update; - - sha1 = crypto_sha1_init(); - crypto_sha1_update(sha1, update_key, sec->rc4_key_len); - crypto_sha1_update(sha1, pad_54, 40); - crypto_sha1_update(sha1, key, sec->rc4_key_len); - crypto_sha1_final(sha1, shasig); - - md5 = crypto_md5_init(); - crypto_md5_update(md5, update_key, sec->rc4_key_len); - crypto_md5_update(md5, pad_92, 48); - crypto_md5_update(md5, shasig, 20); - crypto_md5_final(md5, key); - - update = crypto_rc4_init(key, sec->rc4_key_len); - crypto_rc4(update, sec->rc4_key_len, key, key); - crypto_rc4_free(update); - - if (sec->rc4_key_len == 8) - sec_make_40bit(key); -} - -/* Encrypt data using RC4 */ -static void -sec_encrypt(rdpSec * sec, uint8 * data, int length) -{ - if (sec->sec_encrypt_use_count == 4096) - { - sec_update(sec, sec->sec_encrypt_key, sec->sec_encrypt_update_key); - crypto_rc4_free(sec->rc4_encrypt_key); - sec->rc4_encrypt_key = crypto_rc4_init(sec->sec_encrypt_key, sec->rc4_key_len); - sec->sec_encrypt_use_count = 0; - } - - crypto_rc4(sec->rc4_encrypt_key, length, data, data); - sec->sec_encrypt_use_count++; -} - -/* Decrypt data using RC4 */ -static void -sec_decrypt(rdpSec * sec, uint8 * data, int length) -{ -#ifndef DISABLE_TLS - if (sec->net->tls_connected) - return; -#endif - - if (sec->sec_decrypt_use_count == 4096) - { - sec_update(sec, sec->sec_decrypt_key, sec->sec_decrypt_update_key); - crypto_rc4_free(sec->rc4_decrypt_key); - sec->rc4_decrypt_key = crypto_rc4_init(sec->sec_decrypt_key, sec->rc4_key_len); - sec->sec_decrypt_use_count = 0; - } - - crypto_rc4(sec->rc4_decrypt_key, length, data, data); - sec->sec_decrypt_use_count++; -} - -/* Initialize secure transport packet */ -STREAM -sec_init(rdpSec * sec, uint32 flags, int maxlen) -{ - STREAM s; - int hdrlen; - - if (flags) - { - if (!(sec->net->license->license_issued)) - hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4; - else - hdrlen = (flags & SEC_ENCRYPT) ? 12 : 0; - } - else - hdrlen = 0; - - s = mcs_init(sec->net->mcs, maxlen + hdrlen); - s_push_layer(s, sec_hdr, hdrlen); - - return s; -} - -/* Initialize fast path secure transport packet */ -STREAM -sec_fp_init(rdpSec * sec, uint32 flags, int maxlen) -{ - STREAM s; - int hdrlen; - - hdrlen = (flags & SEC_ENCRYPT) ? 8 : 0; - s = mcs_fp_init(sec->net->mcs, maxlen + hdrlen); - s_push_layer(s, sec_hdr, hdrlen); - - return s; -} - -/* Transmit secure transport packet over specified channel */ -void -sec_send_to_channel(rdpSec * sec, STREAM s, uint32 flags, uint16 channel) -{ - int datalen; - s_pop_layer(s, sec_hdr); - - if (flags) - { - /* Basic Security Header */ - if (!(sec->net->license->license_issued) || (flags & SEC_ENCRYPT)) - out_uint32_le(s, flags); /* flags */ - - if (flags & SEC_ENCRYPT) - { - flags &= ~SEC_ENCRYPT; - datalen = s->end - s->p - 8; - -#if WITH_DEBUG - DEBUG_SEC("Sending encrypted packet:"); - hexdump(s->p + 8, datalen); -#endif - - sec_sign(s->p, 8, sec->sec_sign_key, sec->rc4_key_len, s->p + 8, datalen); - sec_encrypt(sec, s->p + 8, datalen); - } - } - - mcs_send_to_channel(sec->net->mcs, s, channel); -} - -/* Transmit secure transport packet */ - -void -sec_send(rdpSec * sec, STREAM s, uint32 flags) -{ - sec_send_to_channel(sec, s, flags, MCS_GLOBAL_CHANNEL); -} - -/* Transmit secure fast path packet */ -void -sec_fp_send(rdpSec * sec, STREAM s, uint32 flags) -{ - int datalen; - s_pop_layer(s, sec_hdr); - if (flags & SEC_ENCRYPT) - { - datalen = ((int) (s->end - s->p)) - 8; - sec_sign(s->p, 8, sec->sec_sign_key, sec->rc4_key_len, s->p + 8, datalen); - sec_encrypt(sec, s->p + 8, datalen); - } - mcs_fp_send(sec->net->mcs, s, flags); -} - -/* Transfer the client random to the server */ -void -sec_establish_key(rdpSec * sec) -{ - uint32 length = sec->server_public_key_len + SEC_PADDING_SIZE; - uint32 flags = SEC_EXCHANGE_PKT; - STREAM s; - - s = sec_init(sec, flags, length + 4); - - out_uint32_le(s, length); - out_uint8p(s, sec->sec_crypted_random, sec->server_public_key_len); - out_uint8s(s, SEC_PADDING_SIZE); - - s_mark_end(s); - sec_send(sec, s, flags); -} - -static void -sec_out_client_core_data(rdpSec * sec, rdpSet * settings, STREAM s) +connect_output_client_core_data(rdpSec * sec, rdpSet * settings, STREAM s) { char * p; size_t len; + int con_type; uint16 highColorDepth; uint16 supportedColorDepths; uint16 earlyCapabilityFlags; - int con_type; out_uint16_le(s, UDH_CS_CORE); /* User Data Header type */ out_uint16_le(s, 216); /* total length */ @@ -451,11 +95,11 @@ sec_out_client_core_data(rdpSec * sec, rdpSet * settings, STREAM s) is set in earlyCapabilityFlags */ out_uint8(s, con_type); out_uint8(s, 0); /* pad1octet */ - out_uint32_le(s, sec->net->iso->nego->selected_protocol); /* serverSelectedProtocol */ + out_uint32_le(s, sec->net->nego->selected_protocol); /* serverSelectedProtocol */ } static void -sec_out_client_security_data(rdpSec * sec, rdpSet * settings, STREAM s) +connect_output_client_security_data(rdpSec * sec, rdpSet * settings, STREAM s) { uint16 encryptionMethods = 0; @@ -470,7 +114,7 @@ sec_out_client_security_data(rdpSec * sec, rdpSet * settings, STREAM s) } static void -sec_out_client_network_data(rdpSec * sec, rdpSet * settings, STREAM s) +connect_output_client_network_data(rdpSec * sec, rdpSet * settings, STREAM s) { int i; @@ -491,7 +135,7 @@ sec_out_client_network_data(rdpSec * sec, rdpSet * settings, STREAM s) } static void -sec_out_client_cluster_data(rdpSec * sec, rdpSet * settings, STREAM s) +connect_output_client_cluster_data(rdpSec * sec, rdpSet * settings, STREAM s) { out_uint16_le(s, UDH_CS_CLUSTER); /* User Data Header type */ out_uint16_le(s, 12); /* total length */ @@ -504,7 +148,7 @@ sec_out_client_cluster_data(rdpSec * sec, rdpSet * settings, STREAM s) } static void -sec_out_client_monitor_data(rdpSec * sec, rdpSet * settings, STREAM s) +connect_output_client_monitor_data(rdpSec * sec, rdpSet * settings, STREAM s) { int length, n; DEBUG_SEC("Setting monitor data... num_monitors: %d", settings->num_monitors); @@ -522,7 +166,7 @@ sec_out_client_monitor_data(rdpSec * sec, rdpSet * settings, STREAM s) { out_uint32_le(s, settings->monitors[n].x); /* left */ out_uint32_le(s, settings->monitors[n].y); /* top */ - out_uint32_le(s, settings->monitors[n].x + + out_uint32_le(s, settings->monitors[n].x + settings->monitors[n].width-1); /* right */ out_uint32_le(s, settings->monitors[n].y + settings->monitors[n].height-1); /* bottom */ @@ -531,7 +175,7 @@ sec_out_client_monitor_data(rdpSec * sec, rdpSet * settings, STREAM s) } void -sec_out_gcc_conference_create_request(rdpSec * sec, STREAM s) +connect_output_gcc_conference_create_request(rdpSec * sec, STREAM s) { int length; rdpSet * settings = sec->rdp->settings; @@ -540,11 +184,11 @@ sec_out_gcc_conference_create_request(rdpSec * sec, STREAM s) /* the part before userData is of a fixed size, making things convenient */ s->p = s->data + 23; - sec_out_client_core_data(sec, settings, s); - sec_out_client_cluster_data(sec, settings, s); - sec_out_client_security_data(sec, settings, s); - sec_out_client_network_data(sec, settings, s); - sec_out_client_monitor_data(sec, settings, s); + connect_output_client_core_data(sec, settings, s); + connect_output_client_cluster_data(sec, settings, s); + connect_output_client_security_data(sec, settings, s); + connect_output_client_network_data(sec, settings, s); + connect_output_client_monitor_data(sec, settings, s); length = (s->p - s->data) - 23; s->p = s->data; @@ -570,70 +214,9 @@ sec_out_gcc_conference_create_request(rdpSec * sec, STREAM s) s_mark_end(s); } -static void -revcpy(uint8 * out, uint8 * in, int len) -{ - int i; - in += len; - for (i = 0; i < len; i++) - { - *out++ = *--in; - } -} - -/* Parse a Server Proprietary Certificate RSA Public Key */ -static RD_BOOL -sec_parse_public_key(rdpSec * sec, STREAM s, uint32 len, uint8 * modulus, uint8 * exponent) -{ - uint32 magic; - uint32 modulus_len; - - in_uint32_le(s, magic); - if (magic != SEC_RSA_MAGIC) - { - ui_error(sec->rdp->inst, "RSA magic 0x%x\n", magic); - return False; - } - - in_uint32_le(s, modulus_len); - if (4 + 4 + 4 + 4 + SEC_EXPONENT_SIZE + modulus_len != len) - { - ui_error(sec->rdp->inst, "Inconsistent Server Proprietary Certificate public key size\n"); - return False; - } - modulus_len -= SEC_PADDING_SIZE; - if ((modulus_len < SEC_MODULUS_SIZE) || (modulus_len > SEC_MAX_MODULUS_SIZE)) - { - ui_error(sec->rdp->inst, "Bad Server Proprietary Certificate public key size (%u bits)\n", modulus_len * 8); - return False; - } - - in_uint8s(s, 4); /* modulus_bits - must match modulus_len */ - in_uint8s(s, 4); /* datalen - how much data can be encoded */ - revcpy(exponent, s->p, SEC_EXPONENT_SIZE); - in_uint8s(s, SEC_EXPONENT_SIZE); - revcpy(modulus, s->p, modulus_len); - in_uint8s(s, modulus_len); - in_uint8s(s, SEC_PADDING_SIZE); /* zero padding - included in modulus_len but not in modulus_bits */ - sec->server_public_key_len = modulus_len; - - return s_check(s); -} - -/* Parse a Proprietary Certificate signature */ -static RD_BOOL -sec_parse_public_sig(STREAM s, uint32 len) -{ - /* The Proprietary Certificate signature uses a static published private key. - * That is completely nonsense, so we won't bother checking it. */ - - in_uint8s(s, len); - return len == 72; -} - /* Parse Server Security Data */ static RD_BOOL -sec_parse_server_security_data(rdpSec * sec, STREAM s, uint32 * encryptionMethod, uint8 server_random[SEC_RANDOM_SIZE], uint8 * modulus, uint8 * exponent) +connect_process_server_security_data(rdpSec * sec, STREAM s, uint32 * encryptionMethod, uint8 server_random[SEC_RANDOM_SIZE], uint8 * modulus, uint8 * exponent) { uint32 encryptionLevel; uint32 serverRandomLen; @@ -789,7 +372,7 @@ sec_parse_server_security_data(rdpSec * sec, STREAM s, uint32 * encryptionMethod /* Process Server Security Data */ static void -sec_process_server_security_data(rdpSec * sec, STREAM s) +connect_input_server_security_data(rdpSec * sec, STREAM s) { uint32 rc4_key_size; uint8 server_random[SEC_RANDOM_SIZE]; @@ -801,7 +384,7 @@ sec_process_server_security_data(rdpSec * sec, STREAM s) memset(modulus, 0, sizeof(modulus)); memset(exponent, 0, sizeof(exponent)); - if (!sec_parse_server_security_data(sec, s, &rc4_key_size, server_random, modulus, exponent)) + if (!connect_process_server_security_data(sec, s, &rc4_key_size, server_random, modulus, exponent)) { /* encryptionMethod (rc4_key_size) = 0 means TLS */ if (rc4_key_size > 0) @@ -813,16 +396,16 @@ sec_process_server_security_data(rdpSec * sec, STREAM s) DEBUG_SEC("Generating client random"); generate_random(client_random); - revcpy(client_random_rev, client_random, SEC_RANDOM_SIZE); + sec_reverse_copy(client_random_rev, client_random, SEC_RANDOM_SIZE); crypto_rsa_encrypt(SEC_RANDOM_SIZE, client_random_rev, crypted_random_rev, sec->server_public_key_len, modulus, exponent); - revcpy(sec->sec_crypted_random, crypted_random_rev, sec->server_public_key_len); + sec_reverse_copy(sec->sec_crypted_random, crypted_random_rev, sec->server_public_key_len); sec_generate_keys(sec, client_random, server_random, rc4_key_size); } /* Process Server Core Data */ static void -sec_process_server_core_data(rdpSec * sec, STREAM s, uint16 length) +connect_input_server_core_data(rdpSec * sec, STREAM s, uint16 length) { uint32 server_rdp_version, clientRequestedProtocols; in_uint32_le(s, server_rdp_version); @@ -850,7 +433,7 @@ sec_process_server_core_data(rdpSec * sec, STREAM s, uint16 length) /* Process Server Network Data */ static void -sec_process_server_network_data(rdpSec * sec, STREAM s) +connect_input_server_network_data(rdpSec * sec, STREAM s) { int i; uint16 MCSChannelId; @@ -889,7 +472,7 @@ sec_process_server_network_data(rdpSec * sec, STREAM s) /* Process connect response data blob */ void -sec_process_mcs_data(rdpSec * sec, STREAM s) +connect_process_mcs_data(rdpSec * sec, STREAM s) { uint8 byte; uint16 type; @@ -923,15 +506,15 @@ sec_process_mcs_data(rdpSec * sec, STREAM s) switch (type) { case UDH_SC_CORE: /* Server Core Data */ - sec_process_server_core_data(sec, s, length); + connect_input_server_core_data(sec, s, length); break; case UDH_SC_NET: /* Server Network Data */ - sec_process_server_network_data(sec, s); + connect_input_server_network_data(sec, s); break; case UDH_SC_SECURITY: /* Server Security Data */ - sec_process_server_security_data(sec, s); + connect_input_server_security_data(sec, s); break; } @@ -939,111 +522,4 @@ sec_process_mcs_data(rdpSec * sec, STREAM s) } } -/* Receive secure transport packet - * Some package types are processed internally. - * If s is returned a package of *type must be processed by the caller */ -STREAM -sec_recv(rdpSec * sec, secRecvType * type) -{ - STREAM s; - uint16 channel; - uint32 sec_flags; - isoRecvType iso_type; - - while ((s = mcs_recv(sec->net->mcs, &iso_type, &channel)) != NULL) - { - if ((iso_type == ISO_RECV_FAST_PATH) || - (iso_type == ISO_RECV_FAST_PATH_ENCRYPTED)) - { - *type = SEC_RECV_FAST_PATH; - if (iso_type == ISO_RECV_FAST_PATH_ENCRYPTED) - { - in_uint8s(s, 8); /* dataSignature */ /* TODO: Check signature! */ - sec_decrypt(sec, s->p, s->end - s->p); - } - return s; - } - if (iso_type != ISO_RECV_X224) - { - ui_error(sec->rdp->inst, "expected ISO_RECV_X224, got %d\n", iso_type); - return NULL; - } - if (sec->rdp->settings->encryption || !sec->net->license->license_issued) - { - /* basicSecurityHeader: */ - in_uint32_le(s, sec_flags); - - if ((sec_flags & SEC_ENCRYPT) || (sec_flags & SEC_REDIRECTION_PKT)) - { - in_uint8s(s, 8); /* dataSignature */ /* TODO: Check signature! */ - sec_decrypt(sec, s->p, s->end - s->p); - } - - if (sec_flags & SEC_LICENSE_PKT) - { - *type = SEC_RECV_LICENSE; - license_process(sec->net->license, s); - continue; - } - - if (sec_flags & SEC_REDIRECTION_PKT) - { - *type = SEC_RECV_REDIRECT; - return s; - } - } - - if (channel != MCS_GLOBAL_CHANNEL) - { - vchan_process(sec->net->mcs->chan, s, channel); - *type = SEC_RECV_IOCHANNEL; - return s; - } - *type = SEC_RECV_SHARE_CONTROL; - return s; - } - - return NULL; -} - -/* Disconnect a connection */ -void -sec_disconnect(rdpSec * sec) -{ - mcs_disconnect(sec->net->mcs); - - if (sec->rc4_decrypt_key) - crypto_rc4_free(sec->rc4_decrypt_key); - sec->rc4_decrypt_key = NULL; - if (sec->rc4_encrypt_key) - crypto_rc4_free(sec->rc4_encrypt_key); - sec->rc4_encrypt_key = NULL; -} - -rdpSec * -sec_new(struct rdp_rdp * rdp) -{ - rdpSec * self; - - self = (rdpSec *) xmalloc(sizeof(rdpSec)); - if (self != NULL) - { - memset(self, 0, sizeof(rdpSec)); - self->rdp = rdp; - self->rc4_decrypt_key = NULL; - self->rc4_encrypt_key = NULL; - self->net = rdp->net; - } - return self; -} -void -sec_free(rdpSec * sec) -{ - if (sec != NULL) - { - license_free(sec->net->license); - mcs_free(sec->net->mcs); - xfree(sec); - } -} diff --git a/libfreerdp-core/connect.h b/libfreerdp-core/connect.h new file mode 100644 index 0000000..b8596b7 --- /dev/null +++ b/libfreerdp-core/connect.h @@ -0,0 +1,26 @@ +/* + FreeRDP: A Remote Desktop Protocol client. + Connection Sequence + + Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef __CONNECT_H +#define __CONNECT_H + +void +connect_output_gcc_conference_create_request(rdpSec * sec, STREAM s); + +#endif /* __CONNECT_H */ diff --git a/libfreerdp-core/credssp.c b/libfreerdp-core/credssp.c index 0e627ec..a80cd7b 100644 --- a/libfreerdp-core/credssp.c +++ b/libfreerdp-core/credssp.c @@ -21,7 +21,7 @@ #include "rdp.h" #include "tls.h" #include "asn1.h" -#include "secure.h" +#include "security.h" #include "stream.h" #include "tcp.h" #include "mcs.h" diff --git a/libfreerdp-core/freerdp.c b/libfreerdp-core/freerdp.c index a65a0eb..2637ce5 100644 --- a/libfreerdp-core/freerdp.c +++ b/libfreerdp-core/freerdp.c @@ -19,7 +19,7 @@ #include <stdarg.h> #include "frdp.h" #include "rdp.h" -#include "secure.h" +#include "security.h" #include "mcs.h" #include "iso.h" #include "tcp.h" diff --git a/libfreerdp-core/iso.c b/libfreerdp-core/iso.c index f73341a..de7b40d 100644 --- a/libfreerdp-core/iso.c +++ b/libfreerdp-core/iso.c @@ -20,7 +20,7 @@ #include "tcp.h" #include "mcs.h" #include "nego.h" -#include "secure.h" +#include "security.h" #include "credssp.h" #include "rdp.h" #include <freerdp/rdpset.h> diff --git a/libfreerdp-core/license.c b/libfreerdp-core/license.c index 7f2b14a..b79e52e 100644 --- a/libfreerdp-core/license.c +++ b/libfreerdp-core/license.c @@ -19,7 +19,7 @@ #include "frdp.h" #include "crypto.h" -#include "secure.h" +#include "security.h" #include "rdp.h" #include <freerdp/rdpset.h> #include <freerdp/utils/memory.h> diff --git a/libfreerdp-core/mcs.c b/libfreerdp-core/mcs.c index fb49173..80c54d1 100644 --- a/libfreerdp-core/mcs.c +++ b/libfreerdp-core/mcs.c @@ -20,10 +20,11 @@ #include "frdp.h" #include "iso.h" #include "chan.h" -#include "secure.h" #include "rdp.h" #include "asn1.h" #include "tcp.h" +#include "connect.h" +#include "security.h" #include <freerdp/rdpset.h> #include <freerdp/utils/memory.h> @@ -69,7 +70,7 @@ mcs_send_connect_initial(rdpMcs * mcs) gccCCrq.p = gccCCrq.data = (uint8 *) xmalloc(gccCCrq.size); gccCCrq.end = gccCCrq.data + gccCCrq.size; - sec_out_gcc_conference_create_request(mcs->net->sec, &gccCCrq); + connect_output_gcc_conference_create_request(mcs->net->sec, &gccCCrq); gccCCrq_length = gccCCrq.end - gccCCrq.data; length = 9 + 3 * 34 + 4 + gccCCrq_length; @@ -125,7 +126,7 @@ mcs_recv_connect_response(rdpMcs * mcs) ber_parse_header(mcs, s, BER_TAG_OCTET_STRING, &length); - sec_process_mcs_data(mcs->net->sec, s); + connect_process_mcs_data(mcs->net->sec, s); return s_check_end(s); } diff --git a/libfreerdp-core/network.h b/libfreerdp-core/network.h index bbda801..01a1796 100644 --- a/libfreerdp-core/network.h +++ b/libfreerdp-core/network.h @@ -28,7 +28,7 @@ #include "iso.h" #include "mcs.h" #include "rdp.h" -#include "secure.h" +#include "security.h" #include "stream.h" #include "credssp.h" #include "license.h" diff --git a/libfreerdp-core/ntlmssp.h b/libfreerdp-core/ntlmssp.h index 2bc7ed1..4b5f3f0 100644 --- a/libfreerdp-core/ntlmssp.h +++ b/libfreerdp-core/ntlmssp.h @@ -20,7 +20,7 @@ #ifndef __NTLMSSP_H #define __NTLMSSP_H -#include "secure.h" +#include "security.h" #include "credssp.h" #include <freerdp/utils/debug.h> diff --git a/libfreerdp-core/rail.c b/libfreerdp-core/rail.c index 5f232b6..a7bf8d9 100644 --- a/libfreerdp-core/rail.c +++ b/libfreerdp-core/rail.c @@ -19,7 +19,7 @@ #include "frdp.h" #include "rdp.h" -#include "secure.h" +#include "security.h" #include <freerdp/rdpset.h> #include <freerdp/utils/memory.h> diff --git a/libfreerdp-core/rdp.c b/libfreerdp-core/rdp.c index 29dffcd..d3fa364 100644 --- a/libfreerdp-core/rdp.c +++ b/libfreerdp-core/rdp.c @@ -26,7 +26,7 @@ #include "iso.h" #include "tcp.h" #include "mcs.h" -#include "secure.h" +#include "security.h" #include "rail.h" #include "capabilities.h" #include "orders.h" diff --git a/libfreerdp-core/security.c b/libfreerdp-core/security.c new file mode 100644 index 0000000..e3235f0 --- /dev/null +++ b/libfreerdp-core/security.c @@ -0,0 +1,549 @@ +/* + FreeRDP: A Remote Desktop Protocol client. + Standard RDP Security + + Copyright (C) Matthew Chapman 1999-2008 + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "frdp.h" +#include "mcs.h" +#include "chan.h" +#include "license.h" +#include "rdp.h" +#include "iso.h" +#include "tcp.h" +#include <freerdp/rdpset.h> +#include <freerdp/utils/memory.h> + +#ifndef DISABLE_TLS +#include "tls.h" +#include "credssp.h" +#endif + +#include "security.h" + +static RD_BOOL sec_global_initialized = False; + +RD_BOOL +sec_global_init(void) +{ + if (!sec_global_initialized) + { + sec_global_initialized = crypto_global_init(); + } + return sec_global_initialized; +} + +void +sec_global_finish(void) +{ + crypto_global_finish(); + sec_global_initialized = False; +} + +/* these are read only */ +static uint8 pad_54[40] = { + 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54 +}; + +static uint8 pad_92[48] = { + 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92 +}; + +/* + * 48-byte transformation used to generate master secret (6.1) and key material (6.2.2). + * Both SHA1 and MD5 algorithms are used. + */ +void +sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt) +{ + int i; + uint8 pad[4]; + uint8 shasig[20]; + CryptoMd5 md5; + CryptoSha1 sha1; + + for (i = 0; i < 3; i++) + { + memset(pad, salt + i, i + 1); + + sha1 = crypto_sha1_init(); + crypto_sha1_update(sha1, pad, i + 1); + crypto_sha1_update(sha1, in, 48); + crypto_sha1_update(sha1, salt1, 32); + crypto_sha1_update(sha1, salt2, 32); + crypto_sha1_final(sha1, shasig); + + md5 = crypto_md5_init(); + crypto_md5_update(md5, in, 48); + crypto_md5_update(md5, shasig, 20); + crypto_md5_final(md5, &out[i * 16]); + } +} + +/* + * 16-byte transformation used to generate export keys (6.2.2). + */ +void +sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2) +{ + CryptoMd5 md5 = crypto_md5_init(); + crypto_md5_update(md5, in, 16); + crypto_md5_update(md5, salt1, 32); + crypto_md5_update(md5, salt2, 32); + crypto_md5_final(md5, out); +} + +/* Reduce key entropy from 64 to 40 bits */ +static void +sec_make_40bit(uint8 * key) +{ + key[0] = 0xd1; + key[1] = 0x26; + key[2] = 0x9e; +} + +/* Generate encryption keys given client and server randoms */ +void +sec_generate_keys(rdpSec * sec, uint8 * client_random, uint8 * server_random, int rc4_key_size) +{ + uint8 pre_master_secret[48]; + uint8 master_secret[48]; + uint8 key_block[48]; + + /* Construct pre-master secret */ + memcpy(pre_master_secret, client_random, 24); + memcpy(pre_master_secret + 24, server_random, 24); + + /* Generate master secret and then key material */ + sec_hash_48(master_secret, pre_master_secret, client_random, server_random, 'A'); + sec_hash_48(key_block, master_secret, client_random, server_random, 'X'); + + /* First 16 bytes of key material is MAC secret */ + memcpy(sec->sec_sign_key, key_block, 16); + + /* Generate export keys from next two blocks of 16 bytes */ + sec_hash_16(sec->sec_decrypt_key, &key_block[16], client_random, server_random); + sec_hash_16(sec->sec_encrypt_key, &key_block[32], client_random, server_random); + + if (rc4_key_size == 1) + { + DEBUG_SEC("40-bit encryption enabled"); + sec_make_40bit(sec->sec_sign_key); + sec_make_40bit(sec->sec_decrypt_key); + sec_make_40bit(sec->sec_encrypt_key); + sec->rc4_key_len = 8; + } + else + { + DEBUG_SEC("rc_4_key_size == %d, 128-bit encryption enabled", rc4_key_size); + sec->rc4_key_len = 16; + } + + /* Save initial RC4 keys as update keys */ + memcpy(sec->sec_decrypt_update_key, sec->sec_decrypt_key, 16); + memcpy(sec->sec_encrypt_update_key, sec->sec_encrypt_key, 16); + + /* Initialize RC4 state arrays */ + sec->rc4_decrypt_key = crypto_rc4_init(sec->sec_decrypt_key, sec->rc4_key_len); + sec->rc4_encrypt_key = crypto_rc4_init(sec->sec_encrypt_key, sec->rc4_key_len); +} + +/* Output a uint32 into a buffer (little-endian) */ +void +buf_out_uint32(uint8 * buffer, uint32 value) +{ + buffer[0] = (value) & 0xff; + buffer[1] = (value >> 8) & 0xff; + buffer[2] = (value >> 16) & 0xff; + buffer[3] = (value >> 24) & 0xff; +} + +/* Generate a MAC hash (5.2.3.1), using a combination of SHA1 and MD5 */ +void +sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data, int datalen) +{ + uint8 shasig[20]; + uint8 md5sig[16]; + uint8 lenhdr[4]; + CryptoSha1 sha1; + CryptoMd5 md5; + + buf_out_uint32(lenhdr, datalen); + + sha1 = crypto_sha1_init(); + crypto_sha1_update(sha1, session_key, keylen); + crypto_sha1_update(sha1, pad_54, 40); + crypto_sha1_update(sha1, lenhdr, 4); + crypto_sha1_update(sha1, data, datalen); + crypto_sha1_final(sha1, shasig); + + md5 = crypto_md5_init(); + crypto_md5_update(md5, session_key, keylen); + crypto_md5_update(md5, pad_92, 48); + crypto_md5_update(md5, shasig, 20); + crypto_md5_final(md5, md5sig); + + memcpy(signature, md5sig, siglen); +} + +/* Update an encryption key */ +static void +sec_update(rdpSec * sec, uint8 * key, uint8 * update_key) +{ + uint8 shasig[20]; + CryptoSha1 sha1; + CryptoMd5 md5; + CryptoRc4 update; + + sha1 = crypto_sha1_init(); + crypto_sha1_update(sha1, update_key, sec->rc4_key_len); + crypto_sha1_update(sha1, pad_54, 40); + crypto_sha1_update(sha1, key, sec->rc4_key_len); + crypto_sha1_final(sha1, shasig); + + md5 = crypto_md5_init(); + crypto_md5_update(md5, update_key, sec->rc4_key_len); + crypto_md5_update(md5, pad_92, 48); + crypto_md5_update(md5, shasig, 20); + crypto_md5_final(md5, key); + + update = crypto_rc4_init(key, sec->rc4_key_len); + crypto_rc4(update, sec->rc4_key_len, key, key); + crypto_rc4_free(update); + + if (sec->rc4_key_len == 8) + sec_make_40bit(key); +} + +/* Encrypt data using RC4 */ +static void +sec_encrypt(rdpSec * sec, uint8 * data, int length) +{ + if (sec->sec_encrypt_use_count == 4096) + { + sec_update(sec, sec->sec_encrypt_key, sec->sec_encrypt_update_key); + crypto_rc4_free(sec->rc4_encrypt_key); + sec->rc4_encrypt_key = crypto_rc4_init(sec->sec_encrypt_key, sec->rc4_key_len); + sec->sec_encrypt_use_count = 0; + } + + crypto_rc4(sec->rc4_encrypt_key, length, data, data); + sec->sec_encrypt_use_count++; +} + +/* Decrypt data using RC4 */ +static void +sec_decrypt(rdpSec * sec, uint8 * data, int length) +{ + if (sec->sec_decrypt_use_count == 4096) + { + sec_update(sec, sec->sec_decrypt_key, sec->sec_decrypt_update_key); + crypto_rc4_free(sec->rc4_decrypt_key); + sec->rc4_decrypt_key = crypto_rc4_init(sec->sec_decrypt_key, sec->rc4_key_len); + sec->sec_decrypt_use_count = 0; + } + + crypto_rc4(sec->rc4_decrypt_key, length, data, data); + sec->sec_decrypt_use_count++; +} + +/* Initialize secure transport packet */ +STREAM +sec_init(rdpSec * sec, uint32 flags, int maxlen) +{ + STREAM s; + int hdrlen; + + if (flags) + { + if (!(sec->net->license->license_issued)) + hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4; + else + hdrlen = (flags & SEC_ENCRYPT) ? 12 : 0; + } + else + hdrlen = 0; + + s = mcs_init(sec->net->mcs, maxlen + hdrlen); + s_push_layer(s, sec_hdr, hdrlen); + + return s; +} + +/* Initialize fast path secure transport packet */ +STREAM +sec_fp_init(rdpSec * sec, uint32 flags, int maxlen) +{ + STREAM s; + int hdrlen; + + hdrlen = (flags & SEC_ENCRYPT) ? 8 : 0; + s = mcs_fp_init(sec->net->mcs, maxlen + hdrlen); + s_push_layer(s, sec_hdr, hdrlen); + + return s; +} + +/* Transmit secure transport packet over specified channel */ +void +sec_send_to_channel(rdpSec * sec, STREAM s, uint32 flags, uint16 channel) +{ + int datalen; + s_pop_layer(s, sec_hdr); + + if (flags) + { + /* Basic Security Header */ + if (!(sec->net->license->license_issued) || (flags & SEC_ENCRYPT)) + out_uint32_le(s, flags); /* flags */ + + if (flags & SEC_ENCRYPT) + { + flags &= ~SEC_ENCRYPT; + datalen = s->end - s->p - 8; + +#if WITH_DEBUG + DEBUG_SEC("Sending encrypted packet:"); + hexdump(s->p + 8, datalen); +#endif + + sec_sign(s->p, 8, sec->sec_sign_key, sec->rc4_key_len, s->p + 8, datalen); + sec_encrypt(sec, s->p + 8, datalen); + } + } + + mcs_send_to_channel(sec->net->mcs, s, channel); +} + +/* Transmit secure transport packet */ + +void +sec_send(rdpSec * sec, STREAM s, uint32 flags) +{ + sec_send_to_channel(sec, s, flags, MCS_GLOBAL_CHANNEL); +} + +/* Transmit secure fast path packet */ +void +sec_fp_send(rdpSec * sec, STREAM s, uint32 flags) +{ + int datalen; + s_pop_layer(s, sec_hdr); + if (flags & SEC_ENCRYPT) + { + datalen = ((int) (s->end - s->p)) - 8; + sec_sign(s->p, 8, sec->sec_sign_key, sec->rc4_key_len, s->p + 8, datalen); + sec_encrypt(sec, s->p + 8, datalen); + } + mcs_fp_send(sec->net->mcs, s, flags); +} + +/* Transfer the client random to the server */ +void +sec_establish_key(rdpSec * sec) +{ + uint32 length = sec->server_public_key_len + SEC_PADDING_SIZE; + uint32 flags = SEC_EXCHANGE_PKT; + STREAM s; + + s = sec_init(sec, flags, length + 4); + + out_uint32_le(s, length); + out_uint8p(s, sec->sec_crypted_random, sec->server_public_key_len); + out_uint8s(s, SEC_PADDING_SIZE); + + s_mark_end(s); + sec_send(sec, s, flags); +} + +void +sec_reverse_copy(uint8 * out, uint8 * in, int len) +{ + int i; + in += len; + for (i = 0; i < len; i++) + { + *out++ = *--in; + } +} + +/* Parse a Server Proprietary Certificate RSA Public Key */ +RD_BOOL +sec_parse_public_key(rdpSec * sec, STREAM s, uint32 len, uint8 * modulus, uint8 * exponent) +{ + uint32 magic; + uint32 modulus_len; + + in_uint32_le(s, magic); + if (magic != SEC_RSA_MAGIC) + { + ui_error(sec->rdp->inst, "RSA magic 0x%x\n", magic); + return False; + } + + in_uint32_le(s, modulus_len); + if (4 + 4 + 4 + 4 + SEC_EXPONENT_SIZE + modulus_len != len) + { + ui_error(sec->rdp->inst, "Inconsistent Server Proprietary Certificate public key size\n"); + return False; + } + modulus_len -= SEC_PADDING_SIZE; + if ((modulus_len < SEC_MODULUS_SIZE) || (modulus_len > SEC_MAX_MODULUS_SIZE)) + { + ui_error(sec->rdp->inst, "Bad Server Proprietary Certificate public key size (%u bits)\n", modulus_len * 8); + return False; + } + + in_uint8s(s, 4); /* modulus_bits - must match modulus_len */ + in_uint8s(s, 4); /* datalen - how much data can be encoded */ + sec_reverse_copy(exponent, s->p, SEC_EXPONENT_SIZE); + in_uint8s(s, SEC_EXPONENT_SIZE); + sec_reverse_copy(modulus, s->p, modulus_len); + in_uint8s(s, modulus_len); + in_uint8s(s, SEC_PADDING_SIZE); /* zero padding - included in modulus_len but not in modulus_bits */ + sec->server_public_key_len = modulus_len; + + return s_check(s); +} + +/* Parse a Proprietary Certificate signature */ +RD_BOOL +sec_parse_public_sig(STREAM s, uint32 len) +{ + /* The Proprietary Certificate signature uses a static published private key. + * That is completely nonsense, so we won't bother checking it. */ + + in_uint8s(s, len); + return len == 72; +} + +/* Receive secure transport packet + * Some package types are processed internally. + * If s is returned a package of *type must be processed by the caller */ +STREAM +sec_recv(rdpSec * sec, secRecvType * type) +{ + STREAM s; + uint16 channel; + uint32 sec_flags; + isoRecvType iso_type; + + while ((s = mcs_recv(sec->net->mcs, &iso_type, &channel)) != NULL) + { + if ((iso_type == ISO_RECV_FAST_PATH) || + (iso_type == ISO_RECV_FAST_PATH_ENCRYPTED)) + { + *type = SEC_RECV_FAST_PATH; + if (iso_type == ISO_RECV_FAST_PATH_ENCRYPTED) + { + in_uint8s(s, 8); /* dataSignature */ /* TODO: Check signature! */ + sec_decrypt(sec, s->p, s->end - s->p); + } + return s; + } + if (iso_type != ISO_RECV_X224) + { + ui_error(sec->rdp->inst, "expected ISO_RECV_X224, got %d\n", iso_type); + return NULL; + } + if (sec->rdp->settings->encryption || !sec->net->license->license_issued) + { + /* basicSecurityHeader: */ + in_uint32_le(s, sec_flags); + + if ((sec_flags & SEC_ENCRYPT) || (sec_flags & SEC_REDIRECTION_PKT)) + { + in_uint8s(s, 8); /* dataSignature */ /* TODO: Check signature! */ + sec_decrypt(sec, s->p, s->end - s->p); + } + + if (sec_flags & SEC_LICENSE_PKT) + { + *type = SEC_RECV_LICENSE; + license_process(sec->net->license, s); + continue; + } + + if (sec_flags & SEC_REDIRECTION_PKT) + { + *type = SEC_RECV_REDIRECT; + return s; + } + } + + if (channel != MCS_GLOBAL_CHANNEL) + { + vchan_process(sec->net->mcs->chan, s, channel); + *type = SEC_RECV_IOCHANNEL; + return s; + } + *type = SEC_RECV_SHARE_CONTROL; + return s; + } + + return NULL; +} + +/* Disconnect a connection */ +void +sec_disconnect(rdpSec * sec) +{ + mcs_disconnect(sec->net->mcs); + + if (sec->rc4_decrypt_key) + crypto_rc4_free(sec->rc4_decrypt_key); + sec->rc4_decrypt_key = NULL; + if (sec->rc4_encrypt_key) + crypto_rc4_free(sec->rc4_encrypt_key); + sec->rc4_encrypt_key = NULL; +} + +rdpSec * +sec_new(struct rdp_rdp * rdp) +{ + rdpSec * self; + + self = (rdpSec *) xmalloc(sizeof(rdpSec)); + if (self != NULL) + { + memset(self, 0, sizeof(rdpSec)); + self->rdp = rdp; + self->rc4_decrypt_key = NULL; + self->rc4_encrypt_key = NULL; + self->net = rdp->net; + } + return self; +} + +void +sec_free(rdpSec * sec) +{ + if (sec != NULL) + { + license_free(sec->net->license); + mcs_free(sec->net->mcs); + xfree(sec); + } +} diff --git a/libfreerdp-core/secure.h b/libfreerdp-core/security.h index d446cfe..a2af94c 100644 --- a/libfreerdp-core/secure.h +++ b/libfreerdp-core/security.h @@ -1,6 +1,6 @@ /* FreeRDP: A Remote Desktop Protocol client. - Protocol services - RDP encryption and licensing + Standard RDP Security Copyright (C) Jay Sorg 2009-2011 @@ -17,8 +17,8 @@ limitations under the License. */ -#ifndef __SECURE_H -#define __SECURE_H +#ifndef __SECURITY_H +#define __SECURITY_H typedef struct rdp_sec rdpSec; @@ -73,6 +73,12 @@ buf_out_uint32(uint8 * buffer, uint32 value); void sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data, int datalen); +RD_BOOL +sec_parse_public_key(rdpSec * sec, STREAM s, uint32 len, uint8 * modulus, uint8 * exponent); +RD_BOOL +sec_parse_public_sig(STREAM s, uint32 len); +void +sec_generate_keys(rdpSec * sec, uint8 * client_random, uint8 * server_random, int rc4_key_size); STREAM sec_init(rdpSec * sec, uint32 flags, int maxlen); STREAM @@ -84,12 +90,12 @@ sec_send(rdpSec * sec, STREAM s, uint32 flags); void sec_fp_send(rdpSec * sec, STREAM s, uint32 flags); void -sec_process_mcs_data(rdpSec * sec, STREAM s); +sec_reverse_copy(uint8 * out, uint8 * in, int len); +void +connect_process_mcs_data(rdpSec * sec, STREAM s); STREAM sec_recv(rdpSec * sec, secRecvType * type); void -sec_out_gcc_conference_create_request(rdpSec * sec, STREAM s); -void sec_establish_key(rdpSec * sec); void sec_disconnect(rdpSec * sec); diff --git a/libfreerdp-core/tcp.c b/libfreerdp-core/tcp.c index b7fe6e4..5bfbb27 100644 --- a/libfreerdp-core/tcp.c +++ b/libfreerdp-core/tcp.c @@ -32,7 +32,6 @@ #include "frdp.h" #include "iso.h" #include "mcs.h" -#include "secure.h" #include "rdp.h" #include <freerdp/utils/memory.h> #include <freerdp/utils/hexdump.h> |