Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FreeRDP/FreeRDP-old.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc-André Moreau <marcandre.moreau@gmail.com>2011-06-29 14:55:25 +0400
committerMarc-André Moreau <marcandre.moreau@gmail.com>2011-06-29 14:55:25 +0400
commit1a61308b2d1da843f8f3d7120f10c8891becff65 (patch)
tree1214d12614c04ee9151012ad655db0cebbd52dc4
parent46c1d75a72521b548e8f0f677b86f3aab01027e8 (diff)
parentcecf7eb4f9e8aa2ba21dc22c09ec2d3279180f4d (diff)
Merge pull request #55 from awakecoding/master
core network refactoring
-rw-r--r--channels/drdynvc/drdynvc_main.c39
-rw-r--r--include/freerdp/types/base.h5
-rw-r--r--include/freerdp/types/ui.h5
-rw-r--r--include/freerdp/utils/Makefile.am3
-rw-r--r--include/freerdp/utils/hexdump.h27
-rw-r--r--libfreerdp-core/Makefile.am4
-rw-r--r--libfreerdp-core/asn1.c4
-rw-r--r--libfreerdp-core/chan.c12
-rw-r--r--libfreerdp-core/chan.h1
-rw-r--r--libfreerdp-core/connect.c438
-rw-r--r--libfreerdp-core/connect.h26
-rw-r--r--libfreerdp-core/credssp.c14
-rw-r--r--libfreerdp-core/credssp.h8
-rw-r--r--libfreerdp-core/crypto/openssl.c1
-rw-r--r--libfreerdp-core/frdp.h2
-rw-r--r--libfreerdp-core/freerdp.c41
-rw-r--r--libfreerdp-core/iso.c62
-rw-r--r--libfreerdp-core/iso.h6
-rw-r--r--libfreerdp-core/license.c29
-rw-r--r--libfreerdp-core/license.h5
-rw-r--r--libfreerdp-core/mcs.c42
-rw-r--r--libfreerdp-core/mcs.h5
-rw-r--r--libfreerdp-core/nego.c20
-rw-r--r--libfreerdp-core/nego.h6
-rw-r--r--libfreerdp-core/network.c346
-rw-r--r--libfreerdp-core/network.h73
-rw-r--r--libfreerdp-core/ntlmssp.h2
-rw-r--r--libfreerdp-core/rail.c2
-rw-r--r--libfreerdp-core/rdp.c34
-rw-r--r--libfreerdp-core/rdp.h5
-rw-r--r--libfreerdp-core/secure.c1200
-rw-r--r--libfreerdp-core/security.c681
-rw-r--r--libfreerdp-core/security.h (renamed from libfreerdp-core/secure.h)34
-rw-r--r--libfreerdp-core/surface.c3
-rw-r--r--libfreerdp-core/tcp.c218
-rw-r--r--libfreerdp-core/tcp.h21
-rw-r--r--libfreerdp-utils/Makefile.am3
-rw-r--r--libfreerdp-utils/hexdump.c56
38 files changed, 1908 insertions, 1575 deletions
diff --git a/channels/drdynvc/drdynvc_main.c b/channels/drdynvc/drdynvc_main.c
index 90ac6ac..1283b7d 100644
--- a/channels/drdynvc/drdynvc_main.c
+++ b/channels/drdynvc/drdynvc_main.c
@@ -28,6 +28,7 @@
#include <freerdp/utils/stream.h>
#include <freerdp/utils/chan_plugin.h>
#include <freerdp/utils/wait_obj.h>
+#include <freerdp/utils/hexdump.h>
#include "drdynvc_main.h"
@@ -72,43 +73,9 @@ struct drdynvc_plugin
};
#if LOG_LEVEL > 10
-void
-hexdump(char* p, int len)
-{
- unsigned char* line;
- int i;
- int thisline;
- int offset;
-
- line = (unsigned char*)p;
- offset = 0;
- while (offset < len)
- {
- printf("%04x ", offset);
- thisline = len - offset;
- if (thisline > 16)
- {
- thisline = 16;
- }
- for (i = 0; i < thisline; i++)
- {
- printf("%02x ", line[i]);
- }
- for (; i < 16; i++)
- {
- printf(" ");
- }
- for (i = 0; i < thisline; i++)
- {
- printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
- }
- printf("\n");
- offset += thisline;
- line += thisline;
- }
-}
+#define hexdump(data,length) freerdp_hexdump(data,length)
#else
-#define hexdump(p,len)
+#define hexdump(data,length) do { } while (0)
#endif
static int
diff --git a/include/freerdp/types/base.h b/include/freerdp/types/base.h
index de200ca..327c5b3 100644
--- a/include/freerdp/types/base.h
+++ b/include/freerdp/types/base.h
@@ -23,6 +23,11 @@
#ifndef __TYPES_BASE_H
#define __TYPES_BASE_H
+#ifndef True
+#define True (1)
+#define False (0)
+#endif
+
typedef unsigned char uint8;
typedef signed char sint8;
typedef unsigned short uint16;
diff --git a/include/freerdp/types/ui.h b/include/freerdp/types/ui.h
index 067363d..f96a32c 100644
--- a/include/freerdp/types/ui.h
+++ b/include/freerdp/types/ui.h
@@ -31,11 +31,6 @@ typedef void *RD_HGLYPH;
typedef void *RD_HPALETTE;
typedef void *RD_HCURSOR;
-#ifndef True
-#define True (1)
-#define False (0)
-#endif
-
typedef struct _RD_POINT
{
sint16 x, y;
diff --git a/include/freerdp/utils/Makefile.am b/include/freerdp/utils/Makefile.am
index 410babf..4788c93 100644
--- a/include/freerdp/utils/Makefile.am
+++ b/include/freerdp/utils/Makefile.am
@@ -11,4 +11,5 @@ include_HEADERS = \
stopwatch.h \
stream.h \
unicode.h \
- wait_obj.h
+ wait_obj.h \
+ hexdump.h
diff --git a/include/freerdp/utils/hexdump.h b/include/freerdp/utils/hexdump.h
new file mode 100644
index 0000000..d57ba8d
--- /dev/null
+++ b/include/freerdp/utils/hexdump.h
@@ -0,0 +1,27 @@
+/*
+ FreeRDP: A Remote Desktop Protocol client.
+ Hex Dump Utils
+
+ 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 __UTILS_HEXDUMP_H
+#define __UTILS_HEXDUMP_H
+
+#define FREERDP_HEXDUMP_LINE_LENGTH 16
+
+void freerdp_hexdump(uint8* data, int length);
+
+#endif /* __UTILS_HEXDUMP_H */
diff --git a/libfreerdp-core/Makefile.am b/libfreerdp-core/Makefile.am
index c443f53..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,8 @@ 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 \
nego.c nego.h \
diff --git a/libfreerdp-core/asn1.c b/libfreerdp-core/asn1.c
index 58a953c..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
@@ -42,7 +42,7 @@ ber_parse_header(rdpMcs * mcs, STREAM s, int tagval, int *length)
if (tag != tagval)
{
- ui_error(mcs->sec->rdp->inst, "expected tag %d, got %d\n", tagval, tag);
+ ui_error(mcs->net->rdp->inst, "expected tag %d, got %d\n", tagval, tag);
return False;
}
diff --git a/libfreerdp-core/chan.c b/libfreerdp-core/chan.c
index a0bbec4..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>
@@ -38,11 +38,11 @@ vchan_send(rdpChannels * chan, int mcs_id, char * data, int total_length)
rdpSet * settings;
struct rdp_chan * channel;
- settings = chan->mcs->sec->rdp->settings;
+ settings = chan->mcs->net->rdp->settings;
chan_index = (mcs_id - MCS_GLOBAL_CHANNEL) - 1;
if ((chan_index < 0) || (chan_index >= settings->num_channels))
{
- ui_error(chan->mcs->sec->rdp->inst, "error\n");
+ ui_error(chan->mcs->net->rdp->inst, "error\n");
return 0;
}
channel = &(settings->channels[chan_index]);
@@ -61,12 +61,12 @@ vchan_send(rdpChannels * chan, int mcs_id, char * data, int total_length)
{
chan_flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
}
- s = sec_init(chan->mcs->sec, sec_flags, length + 8);
+ s = sec_init(chan->mcs->net->sec, sec_flags, length + 8);
out_uint32_le(s, total_length);
out_uint32_le(s, chan_flags);
out_uint8p(s, data + sent, length);
s_mark_end(s);
- sec_send_to_channel(chan->mcs->sec, s, sec_flags, mcs_id);
+ sec_send_to_channel(chan->mcs->net->sec, s, sec_flags, mcs_id);
sent += length;
chan_flags = 0;
}
@@ -86,7 +86,7 @@ vchan_process(rdpChannels * chan, STREAM s, int mcs_id)
length = (int) (s->end - s->p);
data = (char *) (s->p);
s->p += length;
- ui_channel_data(chan->mcs->sec->rdp->inst, mcs_id, data, length, flags, total_length);
+ ui_channel_data(chan->mcs->net->sec->rdp->inst, mcs_id, data, length, flags, total_length);
}
rdpChannels *
diff --git a/libfreerdp-core/chan.h b/libfreerdp-core/chan.h
index 867b7b3..e2391e2 100644
--- a/libfreerdp-core/chan.h
+++ b/libfreerdp-core/chan.h
@@ -21,6 +21,7 @@
#define __CHAN_H
#include "mcs.h"
+#include "network.h"
struct rdp_channels
{
diff --git a/libfreerdp-core/connect.c b/libfreerdp-core/connect.c
new file mode 100644
index 0000000..b84169a
--- /dev/null
+++ b/libfreerdp-core/connect.c
@@ -0,0 +1,438 @@
+/*
+ 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.
+*/
+
+#include "rdp.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>
+
+#include "connect.h"
+
+static void
+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;
+
+ out_uint16_le(s, UDH_CS_CORE); /* User Data Header type */
+ out_uint16_le(s, 216); /* total length */
+
+ out_uint32_le(s, settings->rdp_version >= 5 ? 0x00080004 : 0x00080001); /* client version */
+ out_uint16_le(s, settings->width); /* desktopWidth */
+ out_uint16_le(s, settings->height); /* desktopHeight */
+ out_uint16_le(s, RNS_UD_COLOR_8BPP); /* colorDepth, ignored because of postBeta2ColorDepth */
+ out_uint16_le(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
+ out_uint32_le(s, settings->keyboard_layout); /* keyboardLayout */
+ out_uint32_le(s, 2600); /* clientBuild */
+
+ /* Unicode name of client, truncated to 15 characters */
+ p = freerdp_uniconv_out(sec->rdp->uniconv, settings->hostname, &len);
+ if (len > 30)
+ {
+ len = 30;
+ p[len] = 0;
+ p[len + 1] = 0;
+ }
+ out_uint8a(s, p, len + 2);
+ out_uint8s(s, 32 - len - 2);
+ xfree(p);
+
+ out_uint32_le(s, settings->keyboard_type); /* keyboardType */
+ out_uint32_le(s, settings->keyboard_subtype); /* keyboardSubType */
+ out_uint32_le(s, settings->keyboard_functionkeys); /* keyboardFunctionKey */
+
+ /* Input Method Editor (IME) file name associated with the input locale.
+ Up to 31 Unicode characters plus a NULL terminator */
+ /* FIXME: populate this field with real data */
+ out_uint8s(s, 64); /* imeFileName */
+
+ out_uint16_le(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
+ out_uint16_le(s, 1); /* clientProductID */
+ out_uint32_le(s, 0); /* serialNumber (should be initialized to 0) */
+
+ highColorDepth = MIN(settings->server_depth, 24); /* 32 must be reported as 24 and RNS_UD_CS_WANT_32BPP_SESSION */
+ out_uint16_le(s, highColorDepth); /* (requested) highColorDepth */
+
+ supportedColorDepths = RNS_UD_32BPP_SUPPORT | RNS_UD_24BPP_SUPPORT | RNS_UD_16BPP_SUPPORT | RNS_UD_15BPP_SUPPORT;
+ out_uint16_le(s, supportedColorDepths); /* supportedColorDepths */
+
+ con_type = 0;
+ earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
+ if (sec->rdp->settings->performanceflags == PERF_FLAG_NONE)
+ {
+ earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
+ con_type = CONNECTION_TYPE_LAN;
+ }
+ if (settings->server_depth == 32)
+ earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
+
+ out_uint16_le(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
+ out_uint8s(s, 64); /* clientDigProductId (64 bytes) */
+ /* connectionType, only valid when RNS_UD_CS_VALID_CONNECTION_TYPE
+ is set in earlyCapabilityFlags */
+ out_uint8(s, con_type);
+ out_uint8(s, 0); /* pad1octet */
+ out_uint32_le(s, sec->net->nego->selected_protocol); /* serverSelectedProtocol */
+}
+
+static void
+connect_output_client_security_data(rdpSec * sec, rdpSet * settings, STREAM s)
+{
+ uint16 encryptionMethods = 0;
+
+ out_uint16_le(s, UDH_CS_SECURITY); /* User Data Header type */
+ out_uint16_le(s, 12); /* total length */
+
+ if (settings->encryption || sec->net->tls_connected)
+ encryptionMethods = ENCRYPTION_40BIT_FLAG | ENCRYPTION_128BIT_FLAG;
+
+ out_uint32_le(s, encryptionMethods); /* encryptionMethods */
+ out_uint32_le(s, 0); /* extEncryptionMethods */
+}
+
+static void
+connect_output_client_network_data(rdpSec * sec, rdpSet * settings, STREAM s)
+{
+ int i;
+
+ DEBUG_SEC("num_channels is %d", settings->num_channels);
+ if (settings->num_channels > 0)
+ {
+ out_uint16_le(s, UDH_CS_NET); /* User Data Header type */
+ out_uint16_le(s, settings->num_channels * 12 + 8); /* total length */
+
+ out_uint32_le(s, settings->num_channels); /* channelCount */
+ for (i = 0; i < settings->num_channels; i++)
+ {
+ DEBUG_SEC("Requesting channel %s", settings->channels[i].name);
+ out_uint8a(s, settings->channels[i].name, 8); /* name (8 bytes) 7 characters with null terminator */
+ out_uint32_le(s, settings->channels[i].flags); /* options (4 bytes) */
+ }
+ }
+}
+
+static void
+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 */
+
+ out_uint32_le(s, (settings->console_session || sec->rdp->redirect_session_id) ?
+ REDIRECTED_SESSIONID_FIELD_VALID | REDIRECTION_SUPPORTED | REDIRECTION_VERSION4 :
+ REDIRECTION_SUPPORTED | REDIRECTION_VERSION4); /* flags */
+
+ out_uint32_le(s, sec->rdp->redirect_session_id); /* RedirectedSessionID */
+}
+
+static void
+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);
+ if (settings->num_monitors <= 1)
+ return;
+
+ DEBUG_SEC("Setting monitor data...");
+ out_uint16_le(s, UDH_CS_MONITOR); /* User Data Header type */
+
+ length = 12 + (20 * settings->num_monitors);
+ out_uint16_le(s, length);
+ out_uint32_le(s, 0); /* flags (unused) */
+ out_uint32_le(s, settings->num_monitors); /* monitorCount */
+ for (n = 0; n < settings->num_monitors; n++)
+ {
+ 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 +
+ settings->monitors[n].width-1); /* right */
+ out_uint32_le(s, settings->monitors[n].y +
+ settings->monitors[n].height-1); /* bottom */
+ out_uint32_le(s, settings->monitors[n].is_primary ? 1 : 0); /* isPrimary */
+ }
+}
+
+void
+connect_output_gcc_conference_create_request(rdpSec * sec, STREAM s)
+{
+ int length;
+ rdpSet * settings = sec->rdp->settings;
+
+ /* See ITU-T Rec. T.124 (02/98) Generic Conference Control */
+
+ /* the part before userData is of a fixed size, making things convenient */
+ s->p = s->data + 23;
+ 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;
+
+ /* t124Identifier = 0.0.20.124.0.1 */
+ out_uint16_be(s, 5);
+ out_uint16_be(s, 0x14);
+ out_uint8(s, 0x7c);
+ out_uint16_be(s, 1);
+
+ /* connectPDU octet string */
+ out_uint16_be(s, ((length + 14) | 0x8000)); /* connectPDU length in two bytes*/
+
+ /* connectPDU content is ConnectGCCPDU PER encoded: */
+ out_uint16_be(s, 8); /* ConferenceCreateRequest ... */
+ out_uint16_be(s, 16);
+ out_uint8(s, 0);
+ out_uint16_le(s, 0xC001); /* userData key is h221NonStandard */
+ out_uint8(s, 0); /* 4 bytes: */
+ out_uint32_le(s, 0x61637544); /* "Duca" */
+ out_uint16_be(s, (length | 0x8000)); /* userData value length in two bytes */
+ s->p = s->data + length + 23; /* userData (outputted earlier) */
+
+ s_mark_end(s);
+}
+
+/* Parse Server Security Data */
+static RD_BOOL
+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;
+ uint32 serverCertLen;
+ uint32 certChainVersion;
+ uint32 dwVersion;
+
+ /**
+ * encryptionMethod:
+ *
+ * ENCRYPTION_METHOD_NONE 0
+ * ENCRYPTION_METHOD_40BIT 1
+ * ENCRYPTION_METHOD_128BIT 2
+ * ENCRYPTION_METHOD_56BIT 8
+ * ENCRYPTION_METHOD_FIPS 16
+ *
+ */
+ in_uint32_le(s, *encryptionMethod); /* encryptionMethod, 0 for TLS/NLA */
+
+ /**
+ * encryptionLevel:
+ *
+ * ENCRYPTION_LEVEL_NONE 0
+ * ENCRYPTION_LEVEL_LOW 1
+ * ENCRYPTION_LEVEL_CLIENT_COMPATIBLE 2
+ * ENCRYPTION_LEVEL_HIGH 3
+ * ENCRYPTION_LEVEL_FIPS 4
+ *
+ */
+ in_uint32_le(s, encryptionLevel); /* encryptionLevel, 0 for TLS/NLA */
+
+ if (encryptionLevel == 0) /* no encryption */
+ return False;
+
+ in_uint32_le(s, serverRandomLen); /* serverRandomLen */
+ in_uint32_le(s, serverCertLen); /* serverCertLen */
+
+ if (serverRandomLen != SEC_RANDOM_SIZE)
+ {
+ ui_error(sec->rdp->inst, "serverRandomLen %d, expected %d\n", serverRandomLen, SEC_RANDOM_SIZE);
+ return False;
+ }
+
+ in_uint8a(s, server_random, SEC_RANDOM_SIZE); /* serverRandom */
+
+ /* Server Certificate: */
+ in_uint32_le(s, dwVersion); /* bit 0x80000000 = temporary certificate */
+ certChainVersion = dwVersion & 0x7FFFFFFF;
+
+ if (certChainVersion == 1) /* Server Proprietary Certificate */
+ {
+ sec_parse_cert_chain_v1(sec, s, modulus, exponent);
+ }
+ else if (certChainVersion == 2) /* X.509 */
+ {
+ sec_parse_cert_chain_v2(sec, s, modulus, exponent);
+ }
+ else
+ {
+ ui_error(sec->rdp->inst, "invalid cert chain version: %d\n", certChainVersion);
+ return False;
+ }
+
+ return s_check_end(s);
+}
+
+/* Process Server Security Data */
+static void
+connect_input_server_security_data(rdpSec * sec, STREAM s)
+{
+ uint32 rc4_key_size;
+ uint8 server_random[SEC_RANDOM_SIZE];
+ uint8 client_random[SEC_RANDOM_SIZE];
+ uint8 modulus[SEC_MAX_MODULUS_SIZE];
+ uint8 exponent[SEC_EXPONENT_SIZE];
+ uint8 client_random_rev[SEC_RANDOM_SIZE];
+ uint8 crypted_random_rev[SEC_MAX_MODULUS_SIZE];
+
+ memset(modulus, 0, sizeof(modulus));
+ memset(exponent, 0, sizeof(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)
+ {
+ DEBUG_SEC("Failed to parse crypt info");
+ }
+ return;
+ }
+
+ DEBUG_SEC("Generating client random");
+ generate_random(client_random);
+ 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);
+ 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
+connect_input_server_core_data(rdpSec * sec, STREAM s, uint16 length)
+{
+ uint32 server_rdp_version, clientRequestedProtocols;
+ in_uint32_le(s, server_rdp_version);
+
+ if(server_rdp_version == 0x00080001)
+ {
+ sec->rdp->settings->rdp_version = 4;
+ sec->rdp->settings->server_depth = 8;
+ }
+ else if(server_rdp_version == 0x00080004)
+ {
+ sec->rdp->settings->rdp_version = 5; /* FIXME: We can't just upgrade the RDP version! */
+ }
+ else
+ {
+ ui_error(sec->rdp->inst, "Invalid server rdp version %ul\n", server_rdp_version);
+ }
+
+ DEBUG_SEC("Server RDP version is %d", sec->rdp->settings->rdp_version);
+ if (length >= 12)
+ {
+ in_uint32_le(s, clientRequestedProtocols);
+ }
+}
+
+/* Process Server Network Data */
+static void
+connect_input_server_network_data(rdpSec * sec, STREAM s)
+{
+ int i;
+ uint16 MCSChannelId;
+ uint16 channelCount;
+
+ in_uint16_le(s, MCSChannelId); /* MCSChannelId */
+ if (MCSChannelId != MCS_GLOBAL_CHANNEL)
+ ui_error(sec->rdp->inst, "expected IO channel 0x%x=%d but got 0x%x=%d\n",
+ MCS_GLOBAL_CHANNEL, MCS_GLOBAL_CHANNEL, MCSChannelId, MCSChannelId);
+ in_uint16_le(s, channelCount); /* channelCount */
+
+ /* TODO: Check that it matches rdp->settings->num_channels */
+ if (channelCount != sec->rdp->settings->num_channels)
+ {
+ ui_error(sec->rdp->inst, "client requested %d channels, server replied with %d channels",
+ sec->rdp->settings->num_channels, channelCount);
+ }
+
+ /* channelIdArray */
+ for (i = 0; i < channelCount; i++)
+ {
+ uint16 channelId;
+ in_uint16_le(s, channelId); /* Channel ID allocated to requested channel number i */
+
+ /* TODO: Assign channel ids here instead of in freerdp.c l_rdp_connect */
+ if (channelId != sec->rdp->settings->channels[i].chan_id)
+ {
+ ui_error(sec->rdp->inst, "channel %d is %d but should have been %d\n",
+ i, channelId, sec->rdp->settings->channels[i].chan_id);
+ }
+ }
+
+ if (channelCount % 2 == 1)
+ in_uint8s(s, 2); /* Padding */
+}
+
+/* Process connect response data blob */
+void
+connect_process_mcs_data(rdpSec * sec, STREAM s)
+{
+ uint8 byte;
+ uint16 type;
+ uint16 length;
+ uint16 totalLength;
+ uint8 *next_tag;
+
+ in_uint8s(s, 21); /* TODO: T.124 ConferenceCreateResponse userData with key h221NonStandard McDn */
+
+ in_uint8(s, byte);
+ totalLength = (uint16) byte;
+
+ if (byte & 0x80)
+ {
+ totalLength &= ~0x80;
+ totalLength <<= 8;
+ in_uint8(s, byte);
+ totalLength += (uint16) byte;
+ }
+
+ while (s->p < s->end)
+ {
+ in_uint16_le(s, type);
+ in_uint16_le(s, length);
+
+ if (length <= 4)
+ return;
+
+ next_tag = s->p + length - 4;
+
+ switch (type)
+ {
+ case UDH_SC_CORE: /* Server Core Data */
+ connect_input_server_core_data(sec, s, length);
+ break;
+
+ case UDH_SC_NET: /* Server Network Data */
+ connect_input_server_network_data(sec, s);
+ break;
+
+ case UDH_SC_SECURITY: /* Server Security Data */
+ connect_input_server_security_data(sec, s);
+ break;
+ }
+
+ s->p = next_tag;
+ }
+}
+
+
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 86e60d5..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"
@@ -58,7 +58,7 @@ asn1_write(const void *buffer, size_t size, void *fd)
void credssp_ntlmssp_init(rdpCredssp *credssp)
{
NTLMSSP *ntlmssp = credssp->ntlmssp;
- rdpSet *settings = credssp->sec->rdp->settings;
+ rdpSet *settings = credssp->net->rdp->settings;
ntlmssp_set_password(ntlmssp, settings->password);
ntlmssp_set_username(ntlmssp, settings->username);
@@ -92,7 +92,7 @@ int credssp_get_public_key(rdpCredssp *credssp)
CryptoCert cert;
int ret;
- cert = tls_get_certificate(credssp->sec->tls);
+ cert = tls_get_certificate(credssp->net->tls);
if (cert == NULL)
{
printf("credssp_get_public_key: tls_get_certificate failed to return the server certificate.\n");
@@ -396,7 +396,7 @@ void credssp_send(rdpCredssp *credssp, DATABLOB *negoToken, DATABLOB *pubKeyAuth
if (enc_rval.encoded != -1)
{
- tls_write(credssp->sec->tls, buffer, size);
+ tls_write(credssp->net->tls, buffer, size);
}
asn_DEF_TSRequest.free_struct(&asn_DEF_TSRequest, ts_request, 0);
@@ -422,7 +422,7 @@ int credssp_recv(rdpCredssp *credssp, DATABLOB *negoToken, DATABLOB *pubKeyAuth,
TSRequest_t *ts_request = 0;
recv_buffer = xmalloc(size);
- bytes_read = tls_read(credssp->sec->tls, recv_buffer, size);
+ bytes_read = tls_read(credssp->net->tls, recv_buffer, size);
if (bytes_read < 0)
return -1;
@@ -503,7 +503,7 @@ void credssp_current_time(uint8* timestamp)
*/
rdpCredssp *
-credssp_new(struct rdp_sec * sec)
+credssp_new(struct rdp_network * net)
{
rdpCredssp * self;
@@ -511,7 +511,7 @@ credssp_new(struct rdp_sec * sec)
if (self != NULL)
{
memset(self, 0, sizeof(rdpCredssp));
- self->sec = sec;
+ self->net = net;
self->send_seq_num = 0;
self->ntlmssp = ntlmssp_new();
}
diff --git a/libfreerdp-core/credssp.h b/libfreerdp-core/credssp.h
index 2ed888e..8d8b6e4 100644
--- a/libfreerdp-core/credssp.h
+++ b/libfreerdp-core/credssp.h
@@ -20,7 +20,7 @@
#ifndef __CREDSSP_H
#define __CREDSSP_H
-#include "secure.h"
+#include "network.h"
#include "ntlmssp.h"
struct rdp_credssp
@@ -33,7 +33,7 @@ struct rdp_credssp
DATABLOB ts_credentials;
CryptoRc4 rc4_seal_state;
struct _NTLMSSP *ntlmssp;
- struct rdp_sec * sec;
+ struct rdp_network * net;
};
typedef struct rdp_credssp rdpCredssp;
@@ -50,7 +50,7 @@ void credssp_encode_ts_credentials(rdpCredssp *credssp);
void credssp_current_time(uint8* timestamp);
void credssp_rc4k(uint8* key, int length, uint8* plaintext, uint8* ciphertext);
-rdpCredssp* credssp_new(rdpSec *sec);
+rdpCredssp* credssp_new(struct rdp_network * net);
void credssp_free(rdpCredssp *credssp);
-#endif // __CREDSSP_H
+#endif /* __CREDSSP_H */
diff --git a/libfreerdp-core/crypto/openssl.c b/libfreerdp-core/crypto/openssl.c
index 84417d7..507288c 100644
--- a/libfreerdp-core/crypto/openssl.c
+++ b/libfreerdp-core/crypto/openssl.c
@@ -19,6 +19,7 @@
#include "frdp.h"
#include "crypto.h"
+#include <freerdp/types/base.h>
#include <freerdp/utils/memory.h>
#include <freerdp/constants/constants.h>
#include <time.h>
diff --git a/libfreerdp-core/frdp.h b/libfreerdp-core/frdp.h
index 68614b8..19f79f1 100644
--- a/libfreerdp-core/frdp.h
+++ b/libfreerdp-core/frdp.h
@@ -53,8 +53,6 @@ void
ui_warning(rdpInst * inst, char * format, ...);
void
ui_unimpl(rdpInst * inst, char * format, ...);
-void
-hexdump(unsigned char * p, int len);
int
load_license(unsigned char ** data);
RD_BOOL
diff --git a/libfreerdp-core/freerdp.c b/libfreerdp-core/freerdp.c
index 503203a..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"
@@ -27,6 +27,7 @@
#include "ext.h"
#include <freerdp/freerdp.h>
#include <freerdp/utils/memory.h>
+#include <freerdp/utils/hexdump.h>
#define RDP_FROM_INST(_inst) ((rdpRdp *) (_inst->rdp))
@@ -90,34 +91,6 @@ ui_unimpl(rdpInst * inst, char * format, ...)
xfree(text2);
}
-void
-hexdump(unsigned char * p, int len)
-{
- unsigned char *line = p;
- int i, thisline, offset = 0;
-
- while (offset < len)
- {
- printf("%04x ", offset);
- thisline = len - offset;
- if (thisline > 16)
- thisline = 16;
-
- for (i = 0; i < thisline; i++)
- printf("%02x ", line[i]);
-
- for (; i < 16; i++)
- printf(" ");
-
- for (i = 0; i < thisline; i++)
- printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
-
- printf("\n");
- offset += thisline;
- line += thisline;
- }
-}
-
int
load_license(unsigned char ** data)
{
@@ -477,9 +450,9 @@ l_rdp_get_fds(rdpInst * inst, void ** read_fds, int * read_count,
rdp = RDP_FROM_INST(inst);
#ifdef _WIN32
- read_fds[*read_count] = (void *) (rdp->sec->mcs->iso->tcp->wsa_event);
+ read_fds[*read_count] = (void *) (rdp->net->tcp->wsa_event);
#else
- read_fds[*read_count] = (void *)(long) (rdp->sec->mcs->iso->tcp->sock);
+ read_fds[*read_count] = (void *)(long) (rdp->net->tcp->sockfd);
#endif
(*read_count)++;
return 0;
@@ -495,10 +468,10 @@ l_rdp_check_fds(rdpInst * inst)
rdp = RDP_FROM_INST(inst);
#ifdef _WIN32
- WSAResetEvent(rdp->sec->mcs->iso->tcp->wsa_event);
+ WSAResetEvent(rdp->net->tcp->wsa_event);
#endif
rv = 0;
- if (tcp_can_recv(rdp->sec->mcs->iso->tcp->sock, 0))
+ if (tcp_can_recv(rdp->net->tcp->sockfd, 0))
{
if (!rdp_loop(rdp, &deactivated))
{
@@ -559,7 +532,7 @@ l_rdp_channel_data(rdpInst * inst, int chan_id, char * data, int data_size)
rdpChannels * chan;
rdp = RDP_FROM_INST(inst);
- chan = rdp->sec->mcs->chan;
+ chan = rdp->net->mcs->chan;
return vchan_send(chan, chan_id, data, data_size);
}
diff --git a/libfreerdp-core/iso.c b/libfreerdp-core/iso.c
index 238b80c..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>
@@ -69,7 +69,7 @@ x224_send_dst_src_class(rdpIso * iso, uint8 code)
{
STREAM s;
- s = tcp_init(iso->tcp, 11);
+ s = network_stream_init(iso->net, 11);
tpkt_output_header(s, 11);
@@ -80,7 +80,7 @@ x224_send_dst_src_class(rdpIso * iso, uint8 code)
out_uint8(s, 0); /* class */
s_mark_end(s);
- tcp_send(iso->tcp, s);
+ network_send(iso->net, s);
}
/* Output and send X.224 Connection Request TPDU with routing for username */
@@ -93,9 +93,9 @@ x224_send_connection_request(rdpIso * iso)
cookie_length = strlen(iso->cookie);
- if (iso->mcs->sec->rdp->redirect_routingtoken)
+ if (iso->net->rdp->redirect_routingtoken)
/* routingToken */
- length += iso->mcs->sec->rdp->redirect_routingtoken_len;
+ length += iso->net->rdp->redirect_routingtoken_len;
else
/* cookie */
length += 19 + cookie_length;
@@ -104,7 +104,7 @@ x224_send_connection_request(rdpIso * iso)
length += 8;
/* FIXME: Use x224_send_dst_src_class */
- s = tcp_init(iso->tcp, length);
+ s = network_stream_init(iso->net, length);
tpkt_output_header(s, length);
@@ -115,10 +115,10 @@ x224_send_connection_request(rdpIso * iso)
out_uint16_le(s, 0); /* src_ref */
out_uint8(s, 0); /* class */
- if (iso->mcs->sec->rdp->redirect_routingtoken)
+ if (iso->net->rdp->redirect_routingtoken)
{
/* routingToken */
- out_uint8p(s, iso->mcs->sec->rdp->redirect_routingtoken, iso->mcs->sec->rdp->redirect_routingtoken_len);
+ out_uint8p(s, iso->net->rdp->redirect_routingtoken, iso->net->rdp->redirect_routingtoken_len);
}
else
{
@@ -138,7 +138,7 @@ x224_send_connection_request(rdpIso * iso)
}
s_mark_end(s);
- tcp_send(iso->tcp, s);
+ network_send(iso->net, s);
}
/* Receive an X.224 TPDU */
@@ -149,7 +149,7 @@ x224_recv(rdpIso * iso, STREAM s, int length, uint8 * pcode)
uint8 code;
uint8 subcode;
- s = tcp_recv(iso->tcp, s, length - 4);
+ s = network_recv(iso->net, s, length - 4);
if (s == NULL)
return NULL;
@@ -217,7 +217,7 @@ tpkt_recv(rdpIso * iso, uint8 * pcode, isoRecvType * ptype)
STREAM s;
int length;
- s = tcp_recv(iso->tcp, NULL, 4);
+ s = network_recv(iso->net, NULL, 4);
if (s == NULL)
return NULL;
@@ -250,7 +250,7 @@ tpkt_recv(rdpIso * iso, uint8 * pcode, isoRecvType * ptype)
next_be(s, length);
}
- s = tcp_recv(iso->tcp, s, length - 4);
+ s = network_recv(iso->net, s, length - 4);
return s;
}
return NULL; /* Fast-Path not allowed */
@@ -268,7 +268,7 @@ STREAM
iso_init(rdpIso * iso, int length)
{
STREAM s;
- s = tcp_init(iso->tcp, length + 7);
+ s = network_stream_init(iso->net, length + 7);
s_push_layer(s, iso_hdr, 7);
return s;
}
@@ -278,7 +278,7 @@ STREAM
iso_fp_init(rdpIso * iso, int length)
{
STREAM s;
- s = tcp_init(iso->tcp, length + 3);
+ s = network_stream_init(iso->net, length + 3);
s_push_layer(s, iso_hdr, 3);
return s;
}
@@ -300,7 +300,7 @@ iso_send(rdpIso * iso, STREAM s)
out_uint8(s, X224_TPDU_DATA); /* code */
out_uint8(s, 0x80); /* eot */
- tcp_send(iso->tcp, s);
+ network_send(iso->net, s);
}
/* Send an fast path data PDU */
@@ -335,7 +335,7 @@ iso_fp_send(rdpIso * iso, STREAM s, uint32 flags)
out_uint8(s, len);
}
- tcp_send(iso->tcp, s);
+ network_send(iso->net, s);
}
/* Receive ISO transport data packet
@@ -355,7 +355,7 @@ iso_recv(rdpIso * iso, isoRecvType * ptype)
(*ptype == ISO_RECV_X224) &&
(code != X224_TPDU_DATA))
{
- ui_error(iso->mcs->sec->rdp->inst, "expected X224_TPDU_DATA, got 0x%x\n", code);
+ ui_error(iso->net->rdp->inst, "expected X224_TPDU_DATA, got 0x%x\n", code);
return NULL;
}
@@ -366,8 +366,14 @@ iso_recv(rdpIso * iso, isoRecvType * ptype)
RD_BOOL
iso_connect(rdpIso * iso, char *server, char *username, int port)
{
- if (strlen(iso->mcs->sec->rdp->settings->domain) > 0)
- iso->cookie = iso->mcs->sec->rdp->settings->domain;
+ if (iso->net == NULL)
+ printf("iso->net\n");
+
+ if (iso->net->rdp == NULL)
+ printf("iso->net->rdp\n");
+
+ if (strlen(iso->net->rdp->settings->domain) > 0)
+ iso->cookie = iso->net->rdp->settings->domain;
else
iso->cookie = username;
@@ -376,6 +382,7 @@ iso_connect(rdpIso * iso, char *server, char *username, int port)
iso->nego->tcp_connected = 0;
nego_init(iso->nego);
+
if (nego_connect(iso->nego) > 0)
{
return True;
@@ -392,15 +399,11 @@ void
iso_disconnect(rdpIso * iso)
{
x224_send_dst_src_class(iso, X224_TPDU_DISCONNECT_REQUEST);
-#ifndef DISABLE_TLS
- if (iso->mcs->sec->tls)
- tls_disconnect(iso->mcs->sec->tls);
-#endif
- tcp_disconnect(iso->tcp);
+ network_disconnect(iso->net);
}
rdpIso *
-iso_new(struct rdp_mcs *mcs)
+iso_new(struct rdp_network * net)
{
rdpIso *self;
@@ -409,9 +412,9 @@ iso_new(struct rdp_mcs *mcs)
if (self != NULL)
{
memset(self, 0, sizeof(rdpIso));
- self->mcs = mcs;
- self->tcp = tcp_new(self);
- self->nego = nego_new(self);
+ self->net = net;
+ self->mcs = net->mcs;
+ self->nego = net->nego;
}
return self;
@@ -422,9 +425,6 @@ iso_free(rdpIso * iso)
{
if (iso != NULL)
{
- tcp_free(iso->tcp);
- if (iso->nego != NULL)
- nego_free(iso->nego);
xfree(iso);
}
}
diff --git a/libfreerdp-core/iso.h b/libfreerdp-core/iso.h
index 148b687..f9e3669 100644
--- a/libfreerdp-core/iso.h
+++ b/libfreerdp-core/iso.h
@@ -18,6 +18,8 @@
*/
#include <freerdp/types/ui.h>
+
+#include "network.h"
#include "stream.h"
#include "nego.h"
@@ -29,7 +31,7 @@ struct rdp_iso
char* cookie;
struct _NEGO * nego;
struct rdp_mcs * mcs;
- struct rdp_tcp * tcp;
+ struct rdp_network * net;
};
typedef struct rdp_iso rdpIso;
@@ -60,7 +62,7 @@ iso_connect(rdpIso * iso, char * server, char * username, int port);
void
iso_disconnect(rdpIso * iso);
rdpIso *
-iso_new(struct rdp_mcs * mcs);
+iso_new(struct rdp_network * net);
void
iso_free(rdpIso * iso);
diff --git a/libfreerdp-core/license.c b/libfreerdp-core/license.c
index 2863757..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>
@@ -49,7 +49,7 @@ static void
license_generate_hwid(rdpLicense * license, uint8 * hwid)
{
buf_out_uint32(hwid, 2);
- strncpy((char *) (hwid + 4), license->sec->rdp->settings->hostname, LICENSE_HWID_SIZE - 4);
+ strncpy((char *) (hwid + 4), license->net->rdp->settings->hostname, LICENSE_HWID_SIZE - 4);
}
/* Send a Licensing packet with Client License Information */
@@ -63,7 +63,7 @@ license_present(rdpLicense * license, uint8 * client_random, uint8 * rsa_data,
license_size + LICENSE_HWID_SIZE + LICENSE_SIGNATURE_SIZE;
STREAM s;
- s = sec_init(license->sec, sec_flags, length + 4);
+ s = sec_init(license->net->sec, sec_flags, length + 4);
/* Licensing Preamble (LICENSE_PREAMBLE) */
out_uint8(s, LICENSE_INFO); /* bMsgType LICENSE_INFO */
@@ -96,7 +96,7 @@ license_present(rdpLicense * license, uint8 * client_random, uint8 * rsa_data,
out_uint8p(s, signature, LICENSE_SIGNATURE_SIZE); /* MACData */
s_mark_end(s);
- sec_send(license->sec, s, sec_flags);
+ sec_send(license->net->sec, s, sec_flags);
}
/* Send a Licensing packet with Client New License Request */
@@ -109,7 +109,7 @@ license_send_request(rdpLicense * license, uint8 * client_random, uint8 * rsa_da
uint16 length = 128 + userlen + hostlen;
STREAM s;
- s = sec_init(license->sec, sec_flags, length + 2);
+ s = sec_init(license->net->sec, sec_flags, length + 2);
/* Licensing Preamble (LICENSE_PREAMBLE) */
out_uint8(s, NEW_LICENSE_REQUEST); /* NEW_LICENSE_REQUEST */
@@ -139,7 +139,7 @@ license_send_request(rdpLicense * license, uint8 * client_random, uint8 * rsa_da
out_uint8p(s, host, hostlen);
s_mark_end(s);
- sec_send(license->sec, s, sec_flags);
+ sec_send(license->net->sec, s, sec_flags);
}
/* Process a Server License Request packet */
@@ -208,8 +208,8 @@ license_process_request(rdpLicense * license, STREAM s)
}
license_send_request(license, null_data, null_data,
- license->sec->rdp->settings->username,
- license->sec->rdp->settings->hostname);
+ license->net->rdp->settings->username,
+ license->net->rdp->settings->hostname);
}
/* Send a Licensing packet with Platform Challenge Response */
@@ -220,7 +220,7 @@ license_send_authresp(rdpLicense * license, uint8 * token, uint8 * crypt_hwid, u
uint16 length = 58;
STREAM s;
- s = sec_init(license->sec, sec_flags, length + 2);
+ s = sec_init(license->net->sec, sec_flags, length + 2);
/* Licensing Preamble (LICENSE_PREAMBLE) */
out_uint8(s, PLATFORM_CHALLENGE_RESPONSE); /* PLATFORM_CHALLENGE_RESPONSE */
@@ -240,7 +240,7 @@ license_send_authresp(rdpLicense * license, uint8 * token, uint8 * crypt_hwid, u
out_uint8p(s, signature, LICENSE_SIGNATURE_SIZE); /* MACData */
s_mark_end(s);
- sec_send(license->sec, s, sec_flags);
+ sec_send(license->net->sec, s, sec_flags);
}
/* Parse a Server Platform Challenge packet */
@@ -256,7 +256,7 @@ license_parse_authreq(rdpLicense * license, STREAM s, uint8 ** token, uint8 ** s
in_uint16_le(s, tokenlen); /* wBlobLen */
if (tokenlen != LICENSE_TOKEN_SIZE)
{
- ui_error(license->sec->rdp->inst, "token len %d\n", tokenlen);
+ ui_error(license->net->rdp->inst, "token len %d\n", tokenlen);
return False;
}
in_uint8p(s, *token, tokenlen); /* RC4-encrypted challenge data */
@@ -396,14 +396,15 @@ license_process(rdpLicense * license, STREAM s)
break;
default:
- ui_unimpl(license->sec->rdp->inst, "Unknown license tag 0x%x", tag);
+ ui_unimpl(license->net->rdp->inst, "Unknown license tag 0x%x", tag);
+ break;
}
s->p = license_start + wMsgSize; /* FIXME: Shouldn't be necessary if parsed properly */
ASSERT(s->p <= s->end);
}
rdpLicense *
-license_new(struct rdp_sec *sec)
+license_new(struct rdp_network * net)
{
rdpLicense *self;
@@ -411,7 +412,7 @@ license_new(struct rdp_sec *sec)
if (self != NULL)
{
memset(self, 0, sizeof(rdpLicense));
- self->sec = sec;
+ self->net = net;
}
return self;
}
diff --git a/libfreerdp-core/license.h b/libfreerdp-core/license.h
index 3b2e525..35df3f0 100644
--- a/libfreerdp-core/license.h
+++ b/libfreerdp-core/license.h
@@ -21,12 +21,13 @@
#define __LICENSE_H
#include "stream.h"
+#include "network.h"
#include <freerdp/types/ui.h>
#include <freerdp/utils/debug.h>
struct rdp_license
{
- struct rdp_sec * sec;
+ struct rdp_network * net;
uint8 license_key[16];
uint8 license_sign_key[16];
RD_BOOL license_issued;
@@ -36,7 +37,7 @@ typedef struct rdp_license rdpLicense;
void
license_process(rdpLicense * license, STREAM s);
rdpLicense *
-license_new(struct rdp_sec * secure);
+license_new(struct rdp_network * net);
void
license_free(rdpLicense * license);
diff --git a/libfreerdp-core/mcs.c b/libfreerdp-core/mcs.c
index f1a2715..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->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;
@@ -115,7 +116,7 @@ mcs_recv_connect_response(rdpMcs * mcs)
in_uint8(s, result);
if (result != 0)
{
- ui_error(mcs->sec->rdp->inst, "MCS connect: %d\n", result);
+ ui_error(mcs->net->rdp->inst, "MCS connect: %d\n", result);
return False;
}
@@ -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->sec, s);
+ connect_process_mcs_data(mcs->net->sec, s);
return s_check_end(s);
}
@@ -173,14 +174,14 @@ mcs_recv_aucf(rdpMcs * mcs, uint16 * mcs_userid)
in_uint8(s, opcode);
if ((opcode >> 2) != T125_DOMAINMCSPDU_AttachUserConfirm)
{
- ui_error(mcs->sec->rdp->inst, "expected AUcf, got %d\n", opcode);
+ ui_error(mcs->net->rdp->inst, "expected AUcf, got %d\n", opcode);
return False;
}
in_uint8(s, result);
if (result != 0)
{
- ui_error(mcs->sec->rdp->inst, "AUrq: %d\n", result);
+ ui_error(mcs->net->rdp->inst, "AUrq: %d\n", result);
return False;
}
@@ -222,14 +223,14 @@ mcs_recv_cjcf(rdpMcs * mcs)
in_uint8(s, opcode);
if ((opcode >> 2) != T125_DOMAINMCSPDU_ChannelJoinConfirm)
{
- ui_error(mcs->sec->rdp->inst, "expected CJcf, got %d\n", opcode);
+ ui_error(mcs->net->rdp->inst, "expected CJcf, got %d\n", opcode);
return False;
}
in_uint8(s, result);
if (result != 0)
{
- ui_error(mcs->sec->rdp->inst, "CJrq: %d\n", result);
+ ui_error(mcs->net->rdp->inst, "CJrq: %d\n", result);
return False;
}
@@ -321,7 +322,7 @@ mcs_recv(rdpMcs * mcs, isoRecvType * ptype, uint16 * channel)
{
if (pduType != T125_DOMAINMCSPDU_DisconnectProviderUltimatum)
{
- ui_error(mcs->sec->rdp->inst, "expected data, got %d\n", pduType);
+ ui_error(mcs->net->rdp->inst, "expected data, got %d\n", pduType);
}
return NULL;
}
@@ -356,7 +357,7 @@ mcs_connect(rdpMcs * mcs)
mcs_send_connect_initial(mcs);
if (!mcs_recv_connect_response(mcs))
{
- ui_error(mcs->sec->rdp->inst, "invalid mcs_recv_connect_response\n");
+ ui_error(mcs->net->rdp->inst, "invalid mcs_recv_connect_response\n");
goto error;
}
@@ -365,7 +366,7 @@ mcs_connect(rdpMcs * mcs)
mcs_send_aurq(mcs);
if (!mcs_recv_aucf(mcs, &(mcs->mcs_userid)))
{
- ui_error(mcs->sec->rdp->inst, "invalid mcs_recv_aucf\n");
+ ui_error(mcs->net->rdp->inst, "invalid mcs_recv_aucf\n");
goto error;
}
@@ -373,29 +374,29 @@ mcs_connect(rdpMcs * mcs)
if (!mcs_recv_cjcf(mcs))
{
- ui_error(mcs->sec->rdp->inst, "invalid mcs_recv_cjcf\n");
+ ui_error(mcs->net->rdp->inst, "invalid mcs_recv_cjcf\n");
goto error;
}
mcs_send_cjrq(mcs, MCS_GLOBAL_CHANNEL);
if (!mcs_recv_cjcf(mcs))
{
- ui_error(mcs->sec->rdp->inst, "invalid mcs_recv_cjcf\n");
+ ui_error(mcs->net->rdp->inst, "invalid mcs_recv_cjcf\n");
goto error;
}
- settings = mcs->sec->rdp->settings;
+ settings = mcs->net->rdp->settings;
for (i = 0; i < settings->num_channels; i++)
{
mcs_id = settings->channels[i].chan_id;
if (mcs_id >= mcs->mcs_userid + MCS_USERCHANNEL_BASE)
{
- ui_warning(mcs->sec->rdp->inst, "channel %d got id %d >= %d\n", i, mcs_id, mcs->mcs_userid + MCS_USERCHANNEL_BASE);
+ ui_warning(mcs->net->rdp->inst, "channel %d got id %d >= %d\n", i, mcs_id, mcs->mcs_userid + MCS_USERCHANNEL_BASE);
}
mcs_send_cjrq(mcs, mcs_id);
if (!mcs_recv_cjcf(mcs))
{
- ui_error(mcs->sec->rdp->inst, "channel %d id %d invalid mcs_recv_cjcf\n", i, mcs_id);
+ ui_error(mcs->net->rdp->inst, "channel %d id %d invalid mcs_recv_cjcf\n", i, mcs_id);
goto error;
}
}
@@ -414,18 +415,21 @@ mcs_disconnect(rdpMcs * mcs)
}
rdpMcs *
-mcs_new(struct rdp_sec * sec)
+mcs_new(struct rdp_network * net)
{
rdpMcs * self;
self = (rdpMcs *) xmalloc(sizeof(rdpMcs));
+
if (self != NULL)
{
memset(self, 0, sizeof(rdpMcs));
- self->sec = sec;
- self->iso = iso_new(self);
+ self->net = net;
+ self->iso = iso_new(net);
self->chan = vchan_new(self);
+ self->net->iso = self->iso;
}
+
return self;
}
diff --git a/libfreerdp-core/mcs.h b/libfreerdp-core/mcs.h
index 79dc6f5..8313035 100644
--- a/libfreerdp-core/mcs.h
+++ b/libfreerdp-core/mcs.h
@@ -21,13 +21,14 @@
#define __MCS_H
#include "iso.h"
+#include "network.h"
#include <freerdp/utils/debug.h>
struct rdp_mcs
{
- struct rdp_sec * sec;
uint16 mcs_userid;
struct rdp_iso * iso;
+ struct rdp_network * net;
struct rdp_channels * chan;
};
typedef struct rdp_mcs rdpMcs;
@@ -49,7 +50,7 @@ mcs_connect(rdpMcs * mcs);
void
mcs_disconnect(rdpMcs * mcs);
rdpMcs *
-mcs_new(struct rdp_sec * secure);
+mcs_new(struct rdp_network * net);
void
mcs_free(rdpMcs * mcs);
diff --git a/libfreerdp-core/nego.c b/libfreerdp-core/nego.c
index 31698f9..0d960bd 100644
--- a/libfreerdp-core/nego.c
+++ b/libfreerdp-core/nego.c
@@ -69,7 +69,7 @@ int nego_tcp_connect(NEGO *nego)
{
if (nego->tcp_connected == 0)
{
- if (tcp_connect(nego->iso->tcp, nego->hostname, nego->port) == False)
+ if (tcp_connect(nego->net->tcp, nego->hostname, nego->port) == False)
{
nego->tcp_connected = 0;
return 0;
@@ -93,7 +93,7 @@ int nego_tcp_connect(NEGO *nego)
int nego_tcp_disconnect(NEGO *nego)
{
if (nego->tcp_connected)
- tcp_disconnect(nego->iso->tcp);
+ tcp_disconnect(nego->net->tcp);
nego->tcp_connected = 0;
return 1;
@@ -110,8 +110,8 @@ void nego_attempt_nla(NEGO *nego)
nego->requested_protocols = PROTOCOL_NLA | PROTOCOL_TLS;
nego_tcp_connect(nego);
- x224_send_connection_request(nego->iso);
- tpkt_recv(nego->iso, &code, NULL);
+ x224_send_connection_request(nego->net->iso);
+ tpkt_recv(nego->net->iso, &code, NULL);
if (nego->state != NEGO_STATE_FINAL)
{
@@ -137,8 +137,8 @@ void nego_attempt_tls(NEGO *nego)
nego->requested_protocols = PROTOCOL_TLS;
nego_tcp_connect(nego);
- x224_send_connection_request(nego->iso);
- tpkt_recv(nego->iso, &code, NULL);
+ x224_send_connection_request(nego->net->iso);
+ tpkt_recv(nego->net->iso, &code, NULL);
if (nego->state != NEGO_STATE_FINAL)
{
@@ -162,9 +162,9 @@ void nego_attempt_rdp(NEGO *nego)
nego->requested_protocols = PROTOCOL_RDP;
nego_tcp_connect(nego);
- x224_send_connection_request(nego->iso);
+ x224_send_connection_request(nego->net->iso);
- if (tpkt_recv(nego->iso, &code, NULL) == NULL)
+ if (tpkt_recv(nego->net->iso, &code, NULL) == NULL)
nego->state = NEGO_STATE_FAIL;
else
nego->state = NEGO_STATE_FINAL;
@@ -278,14 +278,14 @@ void nego_process_negotiation_failure(NEGO *nego, STREAM s)
* @return
*/
-NEGO* nego_new(struct rdp_iso * iso)
+NEGO* nego_new(struct rdp_network * net)
{
NEGO *nego = (NEGO*) xmalloc(sizeof(NEGO));
if (nego != NULL)
{
memset(nego, '\0', sizeof(NEGO));
- nego->iso = iso;
+ nego->net = net;
nego_init(nego);
}
diff --git a/libfreerdp-core/nego.h b/libfreerdp-core/nego.h
index e1a5bfc..a179e19 100644
--- a/libfreerdp-core/nego.h
+++ b/libfreerdp-core/nego.h
@@ -22,7 +22,7 @@
#include "frdp.h"
#include "stream.h"
-#include "iso.h"
+#include "network.h"
enum _NEGO_STATE
{
@@ -41,7 +41,7 @@ struct _NEGO
char *hostname;
NEGO_STATE state;
int tcp_connected;
- struct rdp_iso * iso;
+ struct rdp_network * net;
uint32 selected_protocol;
uint32 requested_protocols;
uint8 enabled_protocols[3];
@@ -60,7 +60,7 @@ void nego_recv(NEGO *nego, STREAM s);
void nego_process_negotiation_response(NEGO *nego, STREAM s);
void nego_process_negotiation_failure(NEGO *nego, STREAM s);
-NEGO* nego_new(rdpIso * iso);
+NEGO* nego_new(struct rdp_network * net);
void nego_init(NEGO *nego);
void nego_free(NEGO *nego);
diff --git a/libfreerdp-core/network.c b/libfreerdp-core/network.c
new file mode 100644
index 0000000..5d9904d
--- /dev/null
+++ b/libfreerdp-core/network.c
@@ -0,0 +1,346 @@
+/*
+ FreeRDP: A Remote Desktop Protocol client.
+ Network Transport Abstraction Layer
+
+ 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.
+*/
+
+#include <freerdp/types/base.h>
+#include <freerdp/utils/memory.h>
+
+#include "network.h"
+
+/* Initialize and return STREAM.
+ * The stream will have room for at least min_size.
+ * The tcp layers out stream will be used. */
+
+STREAM
+network_stream_init(rdpNetwork * net, uint32 min_size)
+{
+ STREAM result = &(net->out);
+
+ if (min_size > result->size)
+ {
+ result->data = (uint8 *) xrealloc(result->data, min_size);
+ result->size = min_size;
+ }
+
+ result->p = result->data;
+ result->end = result->data + result->size;
+
+ return result;
+}
+
+#ifndef DISABLE_TLS
+
+/* verify SSL/TLS connection integrity. 2 checks are carried out. First make sure that the
+ * certificate is assigned to the server we're connected to, and second make sure that the
+ * certificate is signed by a trusted certification authority
+ */
+
+RD_BOOL
+network_verify_tls(rdpNetwork * net)
+{
+ char * issuer;
+ char * subject;
+ char * fingerprint;
+ CryptoCert cert;
+ RD_BOOL verified = False;
+
+ cert = tls_get_certificate(net->tls);
+
+ if (!cert)
+ {
+ goto exit;
+ }
+
+ subject = crypto_cert_get_subject(cert);
+ issuer = crypto_cert_get_issuer(cert);
+ fingerprint = crypto_cert_get_fingerprint(cert);
+
+ verified = tls_verify(net->tls, net->server);
+
+ if (verified != False)
+ verified = crypto_cert_verify_peer_identity(cert, net->server);
+
+ verified = ui_check_certificate(net->rdp->inst, fingerprint, subject, issuer, verified);
+
+ xfree(fingerprint);
+ xfree(subject);
+ xfree(issuer);
+
+exit:
+ if (cert)
+ {
+ crypto_cert_free(cert);
+ cert = NULL;
+ }
+
+ return verified;
+}
+#endif
+
+RD_BOOL
+network_connect_rdp(rdpNetwork * net)
+{
+ RD_BOOL status = False;
+
+ printf("Standard RDP encryption negotiated\n");
+
+ status = mcs_connect(net->mcs);
+
+ if (status && net->rdp->settings->encryption)
+ sec_establish_key(net->sec);
+
+ return status;
+}
+
+RD_BOOL
+network_connect_tls(rdpNetwork * net)
+{
+ RD_BOOL status = False;
+ net->tls = tls_new();
+
+ if (!tls_connect(net->tls, net->tcp->sockfd))
+ return False;
+
+ if (!network_verify_tls(net))
+ return False;
+
+ net->tls_connected = 1;
+ net->rdp->settings->encryption = 0;
+
+ status = mcs_connect(net->mcs);
+
+ return status;
+}
+
+RD_BOOL
+network_connect_nla(rdpNetwork * net)
+{
+ /* TLS with NLA was successfully negotiated */
+
+ RD_BOOL status = 1;
+ net->tls = tls_new();
+
+ if (!tls_connect(net->tls, net->tcp->sockfd))
+ return False;
+
+ if (!network_verify_tls(net))
+ return False;
+
+ net->tls_connected = 1;
+ net->rdp->settings->encryption = 0;
+
+ if (!net->rdp->settings->autologin)
+ if (!ui_authenticate(net->rdp->inst))
+ return False;
+
+ net->credssp = credssp_new(net);
+
+ if (credssp_authenticate(net->credssp) < 0)
+ {
+ printf("Authentication failure, check credentials.\n"
+ "If credentials are valid, the NTLMSSP implementation may be to blame.\n");
+ credssp_free(net->credssp);
+ return 0;
+ }
+
+ credssp_free(net->credssp);
+ status = mcs_connect(net->mcs);
+
+ return status;
+}
+
+RD_BOOL
+network_connect(rdpNetwork * net, char* server, char* username, int port)
+{
+ NEGO *nego = net->iso->nego;
+
+ net->port = port;
+ net->server = server;
+ net->username = username;
+ net->license->license_issued = 0;
+
+ if (net->rdp->settings->nla_security)
+ nego->enabled_protocols[PROTOCOL_NLA] = 1;
+ if (net->rdp->settings->tls_security)
+ nego->enabled_protocols[PROTOCOL_TLS] = 1;
+ if (net->rdp->settings->rdp_security)
+ nego->enabled_protocols[PROTOCOL_RDP] = 1;
+
+ if (!iso_connect(net->iso, net->server, net->username, net->port))
+ return False;
+
+#ifndef DISABLE_TLS
+ if(nego->selected_protocol & PROTOCOL_NLA)
+ {
+ /* TLS with NLA was successfully negotiated */
+ printf("TLS encryption with NLA negotiated\n");
+ return network_connect_nla(net);
+ }
+ else if(nego->selected_protocol & PROTOCOL_TLS)
+ {
+ /* TLS without NLA was successfully negotiated */
+ printf("TLS encryption negotiated\n");
+ return network_connect_tls(net);
+ }
+ else
+#endif
+ {
+ return network_connect_rdp(net);
+ }
+
+ return False;
+}
+
+void
+network_disconnect(rdpNetwork * net)
+{
+#ifndef DISABLE_TLS
+ if (net->tls)
+ tls_disconnect(net->tls);
+#endif
+ tcp_disconnect(net->tcp);
+}
+
+void
+network_send(rdpNetwork * net, STREAM s)
+{
+#ifndef DISABLE_TLS
+ if (net->tls_connected)
+ {
+ tls_write(net->tls, (char*) s->data, s->end - s->data);
+ }
+ else
+#endif
+ {
+ tcp_write(net->tcp, (char*) s->data, s->end - s->data);
+ }
+}
+
+STREAM
+network_recv(rdpNetwork * net, STREAM s, uint32 length)
+{
+ int rcvd = 0;
+ uint32 p_offset;
+ uint32 new_length;
+ uint32 end_offset;
+
+ if (s == NULL)
+ {
+ /* read into "new" stream */
+ if (length > net->in.size)
+ {
+ net->in.data = (uint8 *) xrealloc(net->in.data, length);
+ net->in.size = length;
+ }
+
+ net->in.end = net->in.p = net->in.data;
+ s = &(net->in);
+ }
+ else
+ {
+ /* append to existing stream */
+ new_length = (s->end - s->data) + length;
+ if (new_length > s->size)
+ {
+ p_offset = s->p - s->data;
+ end_offset = s->end - s->data;
+ s->data = (uint8 *) xrealloc(s->data, new_length);
+ s->size = new_length;
+ s->p = s->data + p_offset;
+ s->end = s->data + end_offset;
+ }
+ }
+
+ while (length > 0)
+ {
+#ifndef DISABLE_TLS
+ if (net->tls_connected)
+ {
+ rcvd = tls_read(net->tls, (char*) s->end, length);
+
+ if (rcvd < 0)
+ return NULL;
+ }
+ else
+#endif
+ {
+ rcvd = tcp_read(net->tcp, (char*) s->end, length);
+ }
+
+ s->end += rcvd;
+ length -= rcvd;
+ }
+
+ return s;
+}
+
+rdpNetwork*
+network_new(rdpRdp * rdp)
+{
+ rdpNetwork * self;
+
+ self = (rdpNetwork *) xmalloc(sizeof(rdpNetwork));
+
+ if (self != NULL)
+ {
+ memset(self, 0, sizeof(rdpNetwork));
+ self->rdp = rdp;
+ self->sec = rdp->sec;
+ self->mcs = mcs_new(self);
+ self->tcp = tcp_new(self);
+ self->nego = nego_new(self);
+ self->iso = iso_new(self);
+ self->license = license_new(self);
+ self->sec->net = self;
+
+ self->in.size = 4096;
+ self->in.data = (uint8 *) xmalloc(self->in.size);
+
+ self->out.size = 4096;
+ self->out.data = (uint8 *) xmalloc(self->out.size);
+ }
+
+ return self;
+}
+
+void
+network_free(rdpNetwork * net)
+{
+ if (net != NULL)
+ {
+ xfree(net->in.data);
+ xfree(net->out.data);
+
+ if (net->tcp != NULL)
+ tcp_free(net->tcp);
+
+ if (net->iso != NULL)
+ iso_free(net->iso);
+
+ if (net->mcs != NULL)
+ mcs_free(net->mcs);
+
+ if (net->nego != NULL)
+ nego_free(net->nego);
+
+ if (net->license != NULL)
+ license_free(net->license);
+
+ xfree(net);
+ }
+}
diff --git a/libfreerdp-core/network.h b/libfreerdp-core/network.h
new file mode 100644
index 0000000..01a1796
--- /dev/null
+++ b/libfreerdp-core/network.h
@@ -0,0 +1,73 @@
+/*
+ FreeRDP: A Remote Desktop Protocol client.
+ Network Transport Abstraction Layer
+
+ 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 __NETWORK_H
+#define __NETWORK_H
+
+#include <freerdp/freerdp.h>
+#include <freerdp/types/ui.h>
+
+#include "tcp.h"
+#include "tls.h"
+#include "iso.h"
+#include "mcs.h"
+#include "rdp.h"
+#include "security.h"
+#include "stream.h"
+#include "credssp.h"
+#include "license.h"
+
+struct rdp_network
+{
+ int port;
+ char* server;
+ char* username;
+ struct stream in;
+ struct stream out;
+ int tls_connected;
+ struct _NEGO * nego;
+ struct rdp_rdp * rdp;
+ struct rdp_tcp * tcp;
+ struct rdp_sec * sec;
+ struct rdp_tls * tls;
+ struct rdp_iso * iso;
+ struct rdp_mcs * mcs;
+ struct rdp_credssp * credssp;
+ struct rdp_license * license;
+};
+typedef struct rdp_network rdpNetwork;
+
+STREAM
+network_stream_init(rdpNetwork * net, uint32 min_size);
+RD_BOOL
+network_connect(rdpNetwork * net, char* server, char* username, int port);
+void
+network_disconnect(rdpNetwork * net);
+
+void
+network_send(rdpNetwork * net, STREAM s);
+STREAM
+network_recv(rdpNetwork * net, STREAM s, uint32 length);
+
+rdpNetwork*
+network_new(rdpRdp * rdp);
+void
+network_free(rdpNetwork * net);
+
+#endif /* __NETWORK_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 701fddf..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"
@@ -35,7 +35,9 @@
#include "bitmap.h"
#include "ext.h"
#include "surface.h"
+#include "network.h"
#include <freerdp/freerdp.h>
+#include <freerdp/utils/hexdump.h>
#include "rdp.h"
@@ -152,7 +154,7 @@ rdp_init_data(rdpRdp * rdp, int maxlen)
uint32 sec_flags;
- if (rdp->sec->tls_connected)
+ if (rdp->net->tls_connected)
sec_flags = 0;
else
sec_flags = rdp->settings->encryption ? SEC_ENCRYPT : 0;
@@ -185,7 +187,7 @@ rdp_send_data(rdpRdp * rdp, STREAM s, uint8 data_pdu_type)
/* Share Control Header */
out_uint16_le(s, length); /* totalLength */
out_uint16_le(s, (RDP_PDU_DATA | 0x10)); /* pduType */
- out_uint16_le(s, (rdp->sec->mcs->mcs_userid + 1001)); /* PDUSource */
+ out_uint16_le(s, (rdp->net->mcs->mcs_userid + 1001)); /* PDUSource */
/* Share Data Header */
out_uint32_le(s, rdp->rdp_shareid); /* shareId */
@@ -351,7 +353,7 @@ rdp_send_client_info(rdpRdp * rdp, uint32 flags, char *domain_name,
userName = freerdp_uniconv_out(rdp->uniconv, username, &cbUserName);
alternateShell = freerdp_uniconv_out(rdp->uniconv, shell, &cbAlternateShell);
workingDir = freerdp_uniconv_out(rdp->uniconv, dir, &cbWorkingDir);
- clientAddress = freerdp_uniconv_out(rdp->uniconv, tcp_get_address(rdp->sec->mcs->iso->tcp), &cbClientAddress);
+ clientAddress = freerdp_uniconv_out(rdp->uniconv, tcp_get_address(rdp->net->tcp), &cbClientAddress);
clientDir = freerdp_uniconv_out(rdp->uniconv, dll, &cbClientDir); /* client working directory OR binary name */
length = 8 + (5 * 4) + cbDomain + cbUserName + cbPassword + cbAlternateShell + cbWorkingDir;
@@ -763,7 +765,7 @@ rdp_send_confirm_active(rdpRdp * rdp)
s_mark_end(caps);
caplen = (int) (caps->end - caps->data);
- if (rdp->sec->tls_connected)
+ if (rdp->net->tls_connected)
sec_flags = 0;
else
sec_flags = rdp->settings->encryption ? SEC_ENCRYPT : 0;
@@ -774,7 +776,7 @@ rdp_send_confirm_active(rdpRdp * rdp)
/* share control header */
out_uint16_le(s, length);
out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */
- out_uint16_le(s, (rdp->sec->mcs->mcs_userid + 1001));
+ out_uint16_le(s, (rdp->net->mcs->mcs_userid + 1001));
out_uint32_le(s, rdp->rdp_shareid); /* sharedId */
/* originatorId must be set to the server channel ID
@@ -1041,6 +1043,7 @@ process_system_pointer_pdu(rdpRdp * rdp, STREAM s)
default:
ui_unimpl(rdp->inst, "Unknown System Pointer message 0x%x\n", system_pointer_type);
+ break;
}
}
@@ -1090,6 +1093,7 @@ process_pointer_pdu(rdpRdp * rdp, STREAM s)
default:
ui_unimpl(rdp->inst, "Unknown Pointer message 0x%x\n", message_type);
+ break;
}
}
@@ -1262,6 +1266,7 @@ process_update_pdu(rdpRdp * rdp, STREAM s)
default:
ui_unimpl(rdp->inst, "Unknown update pdu type 0x%x\n", update_type);
+ break;
}
ui_end_update(rdp->inst);
}
@@ -1359,6 +1364,7 @@ process_data_pdu(rdpRdp * rdp, STREAM s)
default:
ui_unimpl(rdp->inst, "Unknown data PDU type 0x%x\n", pduType2);
+ break;
}
return False;
}
@@ -1410,7 +1416,7 @@ process_redirect_pdu(rdpRdp * rdp, STREAM s)
rdp->redirect_routingtoken = xmalloc_in_len32_data(rdp, s,
&rdp->redirect_routingtoken_len);
printf("redirect_cookie_len: %d\n", rdp->redirect_routingtoken_len);
- hexdump((void*)rdp->redirect_routingtoken, rdp->redirect_routingtoken_len);
+ freerdp_hexdump((uint8*)rdp->redirect_routingtoken, rdp->redirect_routingtoken_len);
}
if (redirFlags & LB_USERNAME)
{
@@ -1444,7 +1450,7 @@ process_redirect_pdu(rdpRdp * rdp, STREAM s)
rdp->redirect_target_net_addresses = xmalloc_in_len32_data(rdp, s,
&rdp->redirect_target_net_addresses_len);
printf("redirect_target_net_addresses_len: %d\n", rdp->redirect_target_net_addresses_len);
- hexdump((void*)rdp->redirect_target_net_addresses, rdp->redirect_target_net_addresses_len);
+ freerdp_hexdump((uint8*)rdp->redirect_target_net_addresses, rdp->redirect_target_net_addresses_len);
}
if (redirFlags & LB_NOREDIRECT)
{
@@ -1641,6 +1647,7 @@ rdp_loop(rdpRdp * rdp, RD_BOOL * deactivated)
break;
default:
ui_unimpl(rdp->inst, "Unknown PDU type 0x%x", type);
+ break;
}
if (disc)
return False;
@@ -1671,7 +1678,7 @@ rdp_connect(rdpRdp * rdp)
connect_flags |= INFO_REMOTECONSOLEAUDIO;
}
- if (!sec_connect(rdp->sec, rdp->settings->server, rdp->settings->username, rdp->settings->tcp_port_rdp))
+ if (!network_connect(rdp->net, rdp->settings->server, rdp->settings->username, rdp->settings->tcp_port_rdp))
return False;
password_encoded = freerdp_uniconv_out(rdp->uniconv, rdp->settings->password, &password_encoded_len);
@@ -1679,7 +1686,7 @@ rdp_connect(rdpRdp * rdp)
xfree(password_encoded);
/* by setting encryption to False here, we have an encrypted login packet but unencrypted transfer of other packets */
- if (rdp->sec->tls_connected)
+ if (rdp->net->tls_connected)
rdp->settings->encryption = 0;
return True;
@@ -1701,7 +1708,8 @@ rdp_reconnect(rdpRdp * rdp)
sec_disconnect(rdp->sec);
sec_free(rdp->sec);
rdp->sec = sec_new(rdp);
- if (!sec_connect(rdp->sec, server, username, rdp->settings->tcp_port_rdp))
+
+ if (!network_connect(rdp->net, server, username, rdp->settings->tcp_port_rdp))
return False;
domain = rdp->redirect_domain ? rdp->redirect_domain : rdp->settings->domain;
@@ -1713,11 +1721,14 @@ rdp_reconnect(rdpRdp * rdp)
}
else
password = freerdp_uniconv_out(rdp->uniconv, rdp->settings->password, &password_len);
+
rdp_send_client_info(rdp, INFO_NORMALLOGON | INFO_AUTOLOGON,
domain, username, password, password_len,
rdp->settings->shell, rdp->settings->directory);
+
if (!rdp->redirect_password)
xfree(password);
+
return True;
}
@@ -1745,6 +1756,7 @@ rdp_new(struct rdp_set *settings, struct rdp_inst *inst)
self->buffer = xmalloc(self->buffer_size);
memset(self->buffer, 0, self->buffer_size);
self->sec = sec_new(self);
+ self->net = network_new(self);
self->orders = orders_new(self);
self->pcache = pcache_new(self);
self->cache = cache_new(self);
diff --git a/libfreerdp-core/rdp.h b/libfreerdp-core/rdp.h
index 6ce5cad..1596776 100644
--- a/libfreerdp-core/rdp.h
+++ b/libfreerdp-core/rdp.h
@@ -65,11 +65,12 @@ struct rdp_rdp
UNICONV *uniconv;
RDPCOMP mppc_dict;
struct rdp_sec * sec;
- struct rdp_set * settings; // RDP settings
+ struct rdp_network * net;
+ struct rdp_set * settings;
struct rdp_orders * orders;
struct rdp_pcache * pcache;
struct rdp_cache * cache;
- struct rdp_app * app; // RemoteApp
+ struct rdp_app * app;
struct rdp_ext * ext;
/* Session Directory redirection */
int redirect;
diff --git a/libfreerdp-core/secure.c b/libfreerdp-core/secure.c
deleted file mode 100644
index 7be5cdc..0000000
--- a/libfreerdp-core/secure.c
+++ /dev/null
@@ -1,1200 +0,0 @@
-/*
- FreeRDP: A Remote Desktop Protocol client.
- RDP encryption and licensing
-
- 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 "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;
-}
-
-/* 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->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->license->license_issued))
- hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4;
- else
- hdrlen = (flags & SEC_ENCRYPT) ? 12 : 0;
- }
- else
- hdrlen = 0;
-
- s = mcs_init(sec->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->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->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->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->mcs, s, flags);
-}
-
-/* Transfer the client random to the server */
-static 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)
-{
- char * p;
- size_t len;
- 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 */
-
- out_uint32_le(s, settings->rdp_version >= 5 ? 0x00080004 : 0x00080001); /* client version */
- out_uint16_le(s, settings->width); /* desktopWidth */
- out_uint16_le(s, settings->height); /* desktopHeight */
- out_uint16_le(s, RNS_UD_COLOR_8BPP); /* colorDepth, ignored because of postBeta2ColorDepth */
- out_uint16_le(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
- out_uint32_le(s, settings->keyboard_layout); /* keyboardLayout */
- out_uint32_le(s, 2600); /* clientBuild */
-
- /* Unicode name of client, truncated to 15 characters */
- p = freerdp_uniconv_out(sec->rdp->uniconv, settings->hostname, &len);
- if (len > 30)
- {
- len = 30;
- p[len] = 0;
- p[len + 1] = 0;
- }
- out_uint8a(s, p, len + 2);
- out_uint8s(s, 32 - len - 2);
- xfree(p);
-
- out_uint32_le(s, settings->keyboard_type); /* keyboardType */
- out_uint32_le(s, settings->keyboard_subtype); /* keyboardSubType */
- out_uint32_le(s, settings->keyboard_functionkeys); /* keyboardFunctionKey */
-
- /* Input Method Editor (IME) file name associated with the input locale.
- Up to 31 Unicode characters plus a NULL terminator */
- /* FIXME: populate this field with real data */
- out_uint8s(s, 64); /* imeFileName */
-
- out_uint16_le(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
- out_uint16_le(s, 1); /* clientProductID */
- out_uint32_le(s, 0); /* serialNumber (should be initialized to 0) */
-
- highColorDepth = MIN(settings->server_depth, 24); /* 32 must be reported as 24 and RNS_UD_CS_WANT_32BPP_SESSION */
- out_uint16_le(s, highColorDepth); /* (requested) highColorDepth */
-
- supportedColorDepths = RNS_UD_32BPP_SUPPORT | RNS_UD_24BPP_SUPPORT | RNS_UD_16BPP_SUPPORT | RNS_UD_15BPP_SUPPORT;
- out_uint16_le(s, supportedColorDepths); /* supportedColorDepths */
-
- con_type = 0;
- earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
- if (sec->rdp->settings->performanceflags == PERF_FLAG_NONE)
- {
- earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
- con_type = CONNECTION_TYPE_LAN;
- }
- if (settings->server_depth == 32)
- earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
-
- out_uint16_le(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
- out_uint8s(s, 64); /* clientDigProductId (64 bytes) */
- /* connectionType, only valid when RNS_UD_CS_VALID_CONNECTION_TYPE
- is set in earlyCapabilityFlags */
- out_uint8(s, con_type);
- out_uint8(s, 0); /* pad1octet */
- out_uint32_le(s, sec->mcs->iso->nego->selected_protocol); /* serverSelectedProtocol */
-}
-
-static void
-sec_out_client_security_data(rdpSec * sec, rdpSet * settings, STREAM s)
-{
- uint16 encryptionMethods = 0;
-
- out_uint16_le(s, UDH_CS_SECURITY); /* User Data Header type */
- out_uint16_le(s, 12); /* total length */
-
- if (settings->encryption || sec->tls_connected)
- encryptionMethods = ENCRYPTION_40BIT_FLAG | ENCRYPTION_128BIT_FLAG;
-
- out_uint32_le(s, encryptionMethods); /* encryptionMethods */
- out_uint32_le(s, 0); /* extEncryptionMethods */
-}
-
-static void
-sec_out_client_network_data(rdpSec * sec, rdpSet * settings, STREAM s)
-{
- int i;
-
- DEBUG_SEC("num_channels is %d", settings->num_channels);
- if (settings->num_channels > 0)
- {
- out_uint16_le(s, UDH_CS_NET); /* User Data Header type */
- out_uint16_le(s, settings->num_channels * 12 + 8); /* total length */
-
- out_uint32_le(s, settings->num_channels); /* channelCount */
- for (i = 0; i < settings->num_channels; i++)
- {
- DEBUG_SEC("Requesting channel %s", settings->channels[i].name);
- out_uint8a(s, settings->channels[i].name, 8); /* name (8 bytes) 7 characters with null terminator */
- out_uint32_le(s, settings->channels[i].flags); /* options (4 bytes) */
- }
- }
-}
-
-static void
-sec_out_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 */
-
- out_uint32_le(s, (settings->console_session || sec->rdp->redirect_session_id) ?
- REDIRECTED_SESSIONID_FIELD_VALID | REDIRECTION_SUPPORTED | REDIRECTION_VERSION4 :
- REDIRECTION_SUPPORTED | REDIRECTION_VERSION4); /* flags */
-
- out_uint32_le(s, sec->rdp->redirect_session_id); /* RedirectedSessionID */
-}
-
-static void
-sec_out_client_monitor_data(rdpSec * sec, rdpSet * settings, STREAM s)
-{
- int length, n;
- DEBUG_SEC("Setting monitor data... num_monitors: %d", settings->num_monitors);
- if (settings->num_monitors <= 1)
- return;
-
- DEBUG_SEC("Setting monitor data...");
- out_uint16_le(s, UDH_CS_MONITOR); /* User Data Header type */
-
- length = 12 + (20 * settings->num_monitors);
- out_uint16_le(s, length);
- out_uint32_le(s, 0); /* flags (unused) */
- out_uint32_le(s, settings->num_monitors); /* monitorCount */
- for (n = 0; n < settings->num_monitors; n++)
- {
- 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 +
- settings->monitors[n].width-1); /* right */
- out_uint32_le(s, settings->monitors[n].y +
- settings->monitors[n].height-1); /* bottom */
- out_uint32_le(s, settings->monitors[n].is_primary ? 1 : 0); /* isPrimary */
- }
-}
-
-void
-sec_out_gcc_conference_create_request(rdpSec * sec, STREAM s)
-{
- int length;
- rdpSet * settings = sec->rdp->settings;
-
- /* See ITU-T Rec. T.124 (02/98) Generic Conference Control */
-
- /* 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);
- length = (s->p - s->data) - 23;
- s->p = s->data;
-
- /* t124Identifier = 0.0.20.124.0.1 */
- out_uint16_be(s, 5);
- out_uint16_be(s, 0x14);
- out_uint8(s, 0x7c);
- out_uint16_be(s, 1);
-
- /* connectPDU octet string */
- out_uint16_be(s, ((length + 14) | 0x8000)); /* connectPDU length in two bytes*/
-
- /* connectPDU content is ConnectGCCPDU PER encoded: */
- out_uint16_be(s, 8); /* ConferenceCreateRequest ... */
- out_uint16_be(s, 16);
- out_uint8(s, 0);
- out_uint16_le(s, 0xC001); /* userData key is h221NonStandard */
- out_uint8(s, 0); /* 4 bytes: */
- out_uint32_le(s, 0x61637544); /* "Duca" */
- out_uint16_be(s, (length | 0x8000)); /* userData value length in two bytes */
- s->p = s->data + length + 23; /* userData (outputted earlier) */
-
- 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)
-{
- uint32 encryptionLevel;
- uint32 serverRandomLen;
- uint32 serverCertLen;
- uint32 certChainVersion;
- uint32 dwVersion;
-
- in_uint32_le(s, *encryptionMethod); /* 1 = 40-bit, 2 = 128-bit, 0 for TLS/CredSSP */
- in_uint32_le(s, encryptionLevel); /* 1 = low, 2 = client compatible, 3 = high */
- if (encryptionLevel == 0) /* no encryption */
- return False;
- in_uint32_le(s, serverRandomLen);
- in_uint32_le(s, serverCertLen);
-
- if (serverRandomLen != SEC_RANDOM_SIZE)
- {
- ui_error(sec->rdp->inst, "random len %d, expected %d\n", serverRandomLen, SEC_RANDOM_SIZE);
- return False;
- }
-
- in_uint8a(s, server_random, SEC_RANDOM_SIZE);
-
- /* Server Certificate: */
- in_uint32_le(s, dwVersion); /* bit 0x80000000 = temporary certificate */
- certChainVersion = dwVersion & 0x7FFFFFFF;
-
- if (certChainVersion == 1) /* Server Proprietary Certificate */
- {
- uint16 wPublicKeyBlobType, wPublicKeyBlobLen;
- uint16 wSignatureBlobType, wSignatureBlobLen;
-
- DEBUG_SEC("We're going for a Server Proprietary Certificate (no TS license)");
- in_uint8s(s, 4); /* dwSigAlgId must be 1 (SIGNATURE_ALG_RSA) */
- in_uint8s(s, 4); /* dwKeyAlgId must be 1 (KEY_EXCHANGE_ALG_RSA ) */
-
- in_uint16_le(s, wPublicKeyBlobType);
- if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
- return False;
-
- in_uint16_le(s, wPublicKeyBlobLen);
-
- if (!sec_parse_public_key(sec, s, wPublicKeyBlobLen, modulus, exponent))
- return False;
-
- in_uint16_le(s, wSignatureBlobType);
- if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB)
- return False;
-
- in_uint16_le(s, wSignatureBlobLen);
- if (!sec_parse_public_sig(s, wSignatureBlobLen))
- return False;
- }
- else if (certChainVersion == 2) /* X.509 */
- {
- uint32 cert_total_count, cert_counter;
- uint32 license_cert_len, ts_cert_len;
- CryptoCert license_cert, ts_cert;
-
- DEBUG_SEC("We're going for a X.509 Certificate (TS license)");
- in_uint32_le(s, cert_total_count); /* Number of certificates */
- DEBUG_SEC("Cert chain length: %d", cert_total_count);
- if (cert_total_count < 2)
- {
- ui_error(sec->rdp->inst, "Server didn't send enough X509 certificates\n");
- return False;
- }
- /* X.509 Certificate Chain: */
- /* Only the 2 last certificates in chain are _really_ interesting */
- for (cert_counter=0; cert_counter < cert_total_count - 2; cert_counter++)
- {
- uint32 ignorelen;
- CryptoCert ignorecert;
-
- DEBUG_SEC("Ignoring cert: %d", cert_counter);
- in_uint32_le(s, ignorelen);
- DEBUG_SEC("Ignored Certificate length is %d", ignorelen);
- ignorecert = crypto_cert_read(s->p, ignorelen);
- in_uint8s(s, ignorelen);
- if (ignorecert == NULL)
- {
- ui_error(sec->rdp->inst, "Couldn't read certificate %d from server certificate chain\n", cert_counter);
- return False;
- }
-
-#ifdef WITH_DEBUG_SEC
- DEBUG_SEC("cert #%d (ignored):", cert_counter);
- crypto_cert_print_fp(stdout, ignorecert);
-#endif
- /* TODO: Verify the certificate chain all the way from CA root to prevent MITM attacks */
- crypto_cert_free(ignorecert);
- }
- /* The second to last certificate is the license server */
- in_uint32_le(s, license_cert_len);
- DEBUG_SEC("License Server Certificate length is %d", license_cert_len);
- license_cert = crypto_cert_read(s->p, license_cert_len);
- in_uint8s(s, license_cert_len);
- if (NULL == license_cert)
- {
- ui_error(sec->rdp->inst, "Couldn't load License Server Certificate from server\n");
- return False;
- }
-#ifdef WITH_DEBUG_SEC
- crypto_cert_print_fp(stdout, license_cert);
-#endif
- /* The last certificate is the Terminal Server */
- in_uint32_le(s, ts_cert_len);
- DEBUG_SEC("TS Certificate length is %d", ts_cert_len);
- ts_cert = crypto_cert_read(s->p, ts_cert_len);
- in_uint8s(s, ts_cert_len);
- if (NULL == ts_cert)
- {
- crypto_cert_free(license_cert);
- ui_error(sec->rdp->inst, "Couldn't load TS Certificate from server\n");
- return False;
- }
-#ifdef WITH_DEBUG_SEC
- crypto_cert_print_fp(stdout, ts_cert);
-#endif
- if (!crypto_cert_verify(ts_cert, license_cert))
- {
- crypto_cert_free(ts_cert);
- crypto_cert_free(license_cert);
- ui_error(sec->rdp->inst, "TS Certificate not signed with License Certificate\n");
- return False;
- }
- crypto_cert_free(license_cert);
-
- if (crypto_cert_get_pub_exp_mod(ts_cert, &(sec->server_public_key_len),
- exponent, SEC_EXPONENT_SIZE, modulus, SEC_MAX_MODULUS_SIZE) != 0)
- {
- ui_error(sec->rdp->inst, "Problem extracting RSA key from TS Certificate\n");
- crypto_cert_free(ts_cert);
- return False;
- }
- crypto_cert_free(ts_cert);
- if ((sec->server_public_key_len < SEC_MODULUS_SIZE) ||
- (sec->server_public_key_len > SEC_MAX_MODULUS_SIZE))
- {
- ui_error(sec->rdp->inst, "Bad TS Certificate public key size (%u bits)\n",
- sec->server_public_key_len * 8);
- return False;
- }
- in_uint8s(s, 8 + 4 * cert_total_count); /* Padding */
- }
- else
- {
- ui_error(sec->rdp->inst, "Invalid cert chain version\n");
- return False;
- }
-
- return s_check_end(s);
-}
-
-/* Process Server Security Data */
-static void
-sec_process_server_security_data(rdpSec * sec, STREAM s)
-{
- uint32 rc4_key_size;
- uint8 server_random[SEC_RANDOM_SIZE];
- uint8 client_random[SEC_RANDOM_SIZE];
- uint8 modulus[SEC_MAX_MODULUS_SIZE];
- uint8 exponent[SEC_EXPONENT_SIZE];
- uint8 client_random_rev[SEC_RANDOM_SIZE];
- uint8 crypted_random_rev[SEC_MAX_MODULUS_SIZE];
-
- 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))
- {
- /* encryptionMethod (rc4_key_size) = 0 means TLS */
- if (rc4_key_size > 0)
- {
- DEBUG_SEC("Failed to parse crypt info");
- }
- return;
- }
-
- DEBUG_SEC("Generating client random");
- generate_random(client_random);
- revcpy(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_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)
-{
- uint32 server_rdp_version, clientRequestedProtocols;
- in_uint32_le(s, server_rdp_version);
-
- if(server_rdp_version == 0x00080001)
- {
- sec->rdp->settings->rdp_version = 4;
- sec->rdp->settings->server_depth = 8;
- }
- else if(server_rdp_version == 0x00080004)
- {
- sec->rdp->settings->rdp_version = 5; /* FIXME: We can't just upgrade the RDP version! */
- }
- else
- {
- ui_error(sec->rdp->inst, "Invalid server rdp version %ul\n", server_rdp_version);
- }
-
- DEBUG_SEC("Server RDP version is %d", sec->rdp->settings->rdp_version);
- if (length >= 12)
- {
- in_uint32_le(s, clientRequestedProtocols);
- }
-}
-
-/* Process Server Network Data */
-static void
-sec_process_server_network_data(rdpSec * sec, STREAM s)
-{
- int i;
- uint16 MCSChannelId;
- uint16 channelCount;
-
- in_uint16_le(s, MCSChannelId); /* MCSChannelId */
- if (MCSChannelId != MCS_GLOBAL_CHANNEL)
- ui_error(sec->rdp->inst, "expected IO channel 0x%x=%d but got 0x%x=%d\n",
- MCS_GLOBAL_CHANNEL, MCS_GLOBAL_CHANNEL, MCSChannelId, MCSChannelId);
- in_uint16_le(s, channelCount); /* channelCount */
-
- /* TODO: Check that it matches rdp->settings->num_channels */
- if (channelCount != sec->rdp->settings->num_channels)
- {
- ui_error(sec->rdp->inst, "client requested %d channels, server replied with %d channels",
- sec->rdp->settings->num_channels, channelCount);
- }
-
- /* channelIdArray */
- for (i = 0; i < channelCount; i++)
- {
- uint16 channelId;
- in_uint16_le(s, channelId); /* Channel ID allocated to requested channel number i */
-
- /* TODO: Assign channel ids here instead of in freerdp.c l_rdp_connect */
- if (channelId != sec->rdp->settings->channels[i].chan_id)
- {
- ui_error(sec->rdp->inst, "channel %d is %d but should have been %d\n",
- i, channelId, sec->rdp->settings->channels[i].chan_id);
- }
- }
-
- if (channelCount % 2 == 1)
- in_uint8s(s, 2); /* Padding */
-}
-
-/* Process connect response data blob */
-void
-sec_process_mcs_data(rdpSec * sec, STREAM s)
-{
- uint8 byte;
- uint16 type;
- uint16 length;
- uint16 totalLength;
- uint8 *next_tag;
-
- in_uint8s(s, 21); /* TODO: T.124 ConferenceCreateResponse userData with key h221NonStandard McDn */
-
- in_uint8(s, byte);
- totalLength = (uint16) byte;
-
- if (byte & 0x80)
- {
- totalLength &= ~0x80;
- totalLength <<= 8;
- in_uint8(s, byte);
- totalLength += (uint16) byte;
- }
-
- while (s->p < s->end)
- {
- in_uint16_le(s, type);
- in_uint16_le(s, length);
-
- if (length <= 4)
- return;
-
- next_tag = s->p + length - 4;
-
- switch (type)
- {
- case UDH_SC_CORE: /* Server Core Data */
- sec_process_server_core_data(sec, s, length);
- break;
-
- case UDH_SC_NET: /* Server Network Data */
- sec_process_server_network_data(sec, s);
- break;
-
- case UDH_SC_SECURITY: /* Server Security Data */
- sec_process_server_security_data(sec, s);
- break;
- }
-
- s->p = next_tag;
- }
-}
-
-/* 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->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->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->license, s);
- continue;
- }
-
- if (sec_flags & SEC_REDIRECTION_PKT)
- {
- *type = SEC_RECV_REDIRECT;
- return s;
- }
- }
-
- if (channel != MCS_GLOBAL_CHANNEL)
- {
- vchan_process(sec->mcs->chan, s, channel);
- *type = SEC_RECV_IOCHANNEL;
- return s;
- }
- *type = SEC_RECV_SHARE_CONTROL;
- return s;
- }
-
- return NULL;
-}
-
-#ifndef DISABLE_TLS
-
-/* verify SSL/TLS connection integrity. 2 checks are carried out. First make sure that the
- * certificate is assigned to the server we're connected to, and second make sure that the
- * certificate is signed by a trusted certification authority
- */
-
-static RD_BOOL
-sec_verify_tls(rdpSec * sec, const char * server)
-{
- char * issuer;
- char * subject;
- char * fingerprint;
- CryptoCert cert;
- RD_BOOL verified = False;
-
-#ifdef _WIN32
- /*
- * TODO: FIX ME! This is really bad, I know...
- * There appears to be a buffer overflow only
- * on Windows that affects this part of the code.
- * Skipping it is a workaround, but it's obviously
- * not a permanent "solution".
- */
- return True;
-#endif
-
- cert = tls_get_certificate(sec->tls);
-
- if (!cert)
- {
- goto exit;
- }
-
- subject = crypto_cert_get_subject(cert);
- issuer = crypto_cert_get_issuer(cert);
- fingerprint = crypto_cert_get_fingerprint(cert);
-
- verified = tls_verify(sec->tls, server);
-
- if (verified != False)
- verified = crypto_cert_verify_peer_identity(cert, server);
-
- verified = ui_check_certificate(sec->rdp->inst, fingerprint, subject, issuer, verified);
-
- xfree(fingerprint);
- xfree(subject);
- xfree(issuer);
-
-exit:
- if (cert)
- {
- crypto_cert_free(cert);
- cert = NULL;
- }
-
- return verified;
-}
-#endif
-
-/* Establish a secure connection */
-RD_BOOL
-sec_connect(rdpSec * sec, char *server, char *username, int port)
-{
- NEGO *nego = sec->mcs->iso->nego;
-
- sec->license->license_issued = 0;
- if (sec->rdp->settings->nla_security)
- nego->enabled_protocols[PROTOCOL_NLA] = 1;
- if (sec->rdp->settings->tls_security)
- nego->enabled_protocols[PROTOCOL_TLS] = 1;
- if (sec->rdp->settings->rdp_security)
- nego->enabled_protocols[PROTOCOL_RDP] = 1;
-
- if (!iso_connect(sec->mcs->iso, server, username, port))
- return False;
-
-#ifndef DISABLE_TLS
- if(nego->selected_protocol & PROTOCOL_NLA)
- {
- /* TLS with NLA was successfully negotiated */
- RD_BOOL status = 1;
- printf("TLS encryption with NLA negotiated\n");
- sec->tls = tls_new();
- if (!tls_connect(sec->tls, sec->mcs->iso->tcp->sock))
- return False;
- if (!sec_verify_tls(sec, server))
- return False;
- sec->tls_connected = 1;
- sec->rdp->settings->encryption = 0;
-
- if (!sec->rdp->settings->autologin)
- if (!ui_authenticate(sec->rdp->inst))
- return False;
-
- sec->credssp = credssp_new(sec);
-
- if (credssp_authenticate(sec->credssp) < 0)
- {
- printf("Authentication failure, check credentials.\n"
- "If credentials are valid, the NTLMSSP implementation may be to blame.\n");
- credssp_free(sec->credssp);
- return 0;
- }
-
- credssp_free(sec->credssp);
-
- status = mcs_connect(sec->mcs);
- return status;
- }
- else if(nego->selected_protocol & PROTOCOL_TLS)
- {
- /* TLS without NLA was successfully negotiated */
- RD_BOOL success;
- printf("TLS encryption negotiated\n");
- sec->tls = tls_new();
- if (!tls_connect(sec->tls, sec->mcs->iso->tcp->sock))
- return False;
- if (!sec_verify_tls(sec, server))
- return False;
- sec->tls_connected = 1;
- sec->rdp->settings->encryption = 0;
- success = mcs_connect(sec->mcs);
- return success;
- }
- else
-#endif
- {
- RD_BOOL success;
-
- printf("Standard RDP encryption negotiated\n");
-
- success = mcs_connect(sec->mcs);
-
- if (success && sec->rdp->settings->encryption)
- sec_establish_key(sec);
-
- return success;
- }
-
- return 0;
-}
-
-/* Disconnect a connection */
-void
-sec_disconnect(rdpSec * sec)
-{
- mcs_disconnect(sec->mcs);
-
-#ifndef DISABLE_TLS
- if (sec->tls)
- tls_free(sec->tls);
- sec->tls = NULL;
- sec->tls_connected = 0;
-#endif
-
- 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->mcs = mcs_new(self);
- self->license = license_new(self);
- self->rc4_decrypt_key = NULL;
- self->rc4_encrypt_key = NULL;
- }
- return self;
-}
-
-void
-sec_free(rdpSec * sec)
-{
- if (sec != NULL)
- {
- license_free(sec->license);
- mcs_free(sec->mcs);
- xfree(sec);
- }
-}
diff --git a/libfreerdp-core/security.c b/libfreerdp-core/security.c
new file mode 100644
index 0000000..ded9472
--- /dev/null
+++ b/libfreerdp-core/security.c
@@ -0,0 +1,681 @@
+/*
+ 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;
+}
+
+RD_BOOL
+sec_parse_cert_chain_v1(rdpSec * sec, STREAM s, uint8 * modulus, uint8 * exponent)
+{
+ uint16 wPublicKeyBlobType, wPublicKeyBlobLen;
+ uint16 wSignatureBlobType, wSignatureBlobLen;
+
+ DEBUG_SEC("We're going for a Server Proprietary Certificate (no TS license)");
+ in_uint8s(s, 4); /* dwSigAlgId must be 1 (SIGNATURE_ALG_RSA) */
+ in_uint8s(s, 4); /* dwKeyAlgId must be 1 (KEY_EXCHANGE_ALG_RSA ) */
+
+ in_uint16_le(s, wPublicKeyBlobType);
+ if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
+ return False;
+
+ in_uint16_le(s, wPublicKeyBlobLen);
+
+ if (!sec_parse_public_key(sec, s, wPublicKeyBlobLen, modulus, exponent))
+ return False;
+
+ in_uint16_le(s, wSignatureBlobType);
+ if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB)
+ return False;
+
+ in_uint16_le(s, wSignatureBlobLen);
+ if (!sec_parse_public_sig(s, wSignatureBlobLen))
+ return False;
+
+ return True;
+}
+
+RD_BOOL
+sec_parse_cert_chain_v2(rdpSec * sec, STREAM s, uint8 * modulus, uint8 * exponent)
+{
+ uint32 cert_total_count, cert_counter;
+ uint32 license_cert_len, ts_cert_len;
+ CryptoCert license_cert, ts_cert;
+
+ DEBUG_SEC("We're going for a X.509 Certificate (TS license)");
+ in_uint32_le(s, cert_total_count); /* Number of certificates */
+ DEBUG_SEC("Cert chain length: %d", cert_total_count);
+
+ if (cert_total_count < 2)
+ {
+ ui_error(sec->rdp->inst, "Server didn't send enough X509 certificates\n");
+ return False;
+ }
+
+ /* X.509 Certificate Chain: */
+ /* Only the 2 last certificates in chain are _really_ interesting */
+ for (cert_counter=0; cert_counter < cert_total_count - 2; cert_counter++)
+ {
+ uint32 ignorelen;
+ CryptoCert ignorecert;
+
+ DEBUG_SEC("Ignoring cert: %d", cert_counter);
+ in_uint32_le(s, ignorelen);
+ DEBUG_SEC("Ignored Certificate length is %d", ignorelen);
+ ignorecert = crypto_cert_read(s->p, ignorelen);
+ in_uint8s(s, ignorelen);
+ if (ignorecert == NULL)
+ {
+ ui_error(sec->rdp->inst, "Couldn't read certificate %d from server certificate chain\n", cert_counter);
+ return False;
+ }
+
+#ifdef WITH_DEBUG_SEC
+ DEBUG_SEC("cert #%d (ignored):", cert_counter);
+ crypto_cert_print_fp(stdout, ignorecert);
+#endif
+ /* TODO: Verify the certificate chain all the way from CA root to prevent MITM attacks */
+ crypto_cert_free(ignorecert);
+ }
+
+ /* The second to last certificate is the license server */
+ in_uint32_le(s, license_cert_len);
+ DEBUG_SEC("License Server Certificate length is %d", license_cert_len);
+ license_cert = crypto_cert_read(s->p, license_cert_len);
+ in_uint8s(s, license_cert_len);
+ if (NULL == license_cert)
+ {
+ ui_error(sec->rdp->inst, "Couldn't load License Server Certificate from server\n");
+ return False;
+ }
+#ifdef WITH_DEBUG_SEC
+ crypto_cert_print_fp(stdout, license_cert);
+#endif
+
+ /* The last certificate is the Terminal Server */
+ in_uint32_le(s, ts_cert_len);
+ DEBUG_SEC("TS Certificate length is %d", ts_cert_len);
+ ts_cert = crypto_cert_read(s->p, ts_cert_len);
+ in_uint8s(s, ts_cert_len);
+ if (NULL == ts_cert)
+ {
+ crypto_cert_free(license_cert);
+ ui_error(sec->rdp->inst, "Couldn't load TS Certificate from server\n");
+ return False;
+ }
+
+#ifdef WITH_DEBUG_SEC
+ crypto_cert_print_fp(stdout, ts_cert);
+#endif
+ if (!crypto_cert_verify(ts_cert, license_cert))
+ {
+ crypto_cert_free(ts_cert);
+ crypto_cert_free(license_cert);
+ ui_error(sec->rdp->inst, "TS Certificate not signed with License Certificate\n");
+ return False;
+ }
+ crypto_cert_free(license_cert);
+
+ if (crypto_cert_get_pub_exp_mod(ts_cert, &(sec->server_public_key_len),
+ exponent, SEC_EXPONENT_SIZE, modulus, SEC_MAX_MODULUS_SIZE) != 0)
+ {
+ ui_error(sec->rdp->inst, "Problem extracting RSA key from TS Certificate\n");
+ crypto_cert_free(ts_cert);
+ return False;
+ }
+ crypto_cert_free(ts_cert);
+
+ if ((sec->server_public_key_len < SEC_MODULUS_SIZE) ||
+ (sec->server_public_key_len > SEC_MAX_MODULUS_SIZE))
+ {
+ ui_error(sec->rdp->inst, "Bad TS Certificate public key size (%u bits)\n",
+ sec->server_public_key_len * 8);
+ return False;
+ }
+ in_uint8s(s, 8 + 4 * cert_total_count); /* Padding */
+
+ return True;
+}
+
+/* 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 d5973cf..4e3f05a 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;
@@ -37,8 +37,9 @@ sec_global_finish(void);
struct rdp_sec
{
- struct rdp_rdp * rdp;
int rc4_key_len;
+ struct rdp_rdp * rdp;
+ struct rdp_network * net;
CryptoRc4 rc4_decrypt_key;
CryptoRc4 rc4_encrypt_key;
uint32 server_public_key_len;
@@ -51,13 +52,6 @@ struct rdp_sec
/* These values must be available to reset state - Session Directory */
int sec_encrypt_use_count;
int sec_decrypt_use_count;
- struct rdp_mcs * mcs;
- struct rdp_license * license;
- int tls_connected;
-#ifndef DISABLE_TLS
- struct rdp_tls * tls;
- struct rdp_credssp * credssp;
-#endif
};
enum sec_recv_type
@@ -79,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
@@ -90,13 +90,17 @@ 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);
+RD_BOOL
+sec_parse_cert_chain_v1(rdpSec * sec, STREAM s, uint8 * modulus, uint8 * exponent);
+RD_BOOL
+sec_parse_cert_chain_v2(rdpSec * sec, STREAM s, uint8 * modulus, uint8 * exponent);
+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);
-RD_BOOL
-sec_connect(rdpSec * sec, char *server, char *username, int port);
+sec_establish_key(rdpSec * sec);
void
sec_disconnect(rdpSec * sec);
rdpSec *
diff --git a/libfreerdp-core/surface.c b/libfreerdp-core/surface.c
index c5c4b4c..df69f47 100644
--- a/libfreerdp-core/surface.c
+++ b/libfreerdp-core/surface.c
@@ -21,6 +21,7 @@
#include "rdp.h"
#include "stream.h"
#include <freerdp/freerdp.h>
+#include <freerdp/utils/hexdump.h>
#include "surface.h"
@@ -83,7 +84,7 @@ surface_codec_cap(rdpRdp * rdp, uint8 * codec_guid, int codec_id,
else
{
//printf("unknown guid\n");
- hexdump(codec_guid, 16);
+ freerdp_hexdump(codec_guid, 16);
}
return s;
}
diff --git a/libfreerdp-core/tcp.c b/libfreerdp-core/tcp.c
index 035b2c4..5bfbb27 100644
--- a/libfreerdp-core/tcp.c
+++ b/libfreerdp-core/tcp.c
@@ -32,9 +32,9 @@
#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>
#include "tcp.h"
@@ -79,6 +79,7 @@ tcp_socket_ok(int sck)
return True;
}
}
+
return False;
}
@@ -92,13 +93,16 @@ tcp_can_send(int sck, int millis)
time.tv_sec = millis / 1000;
time.tv_usec = (millis * 1000) % 1000000;
+
FD_ZERO(&wfds);
FD_SET(sck, &wfds);
sel_count = select(sck + 1, 0, &wfds, 0, &time);
+
if (sel_count > 0)
{
return tcp_socket_ok(sck);
}
+
return False;
}
@@ -112,164 +116,85 @@ tcp_can_recv(int sck, int millis)
time.tv_sec = millis / 1000;
time.tv_usec = (millis * 1000) % 1000000;
+
FD_ZERO(&rfds);
FD_SET(sck, &rfds);
sel_count = select(sck + 1, &rfds, 0, 0, &time);
+
if (sel_count > 0)
{
return tcp_socket_ok(sck);
}
- return False;
-}
-
-/* Initialize and return STREAM.
- * The stream will have room for at least minsize.
- * The tcp layers out stream will be used. */
-STREAM
-tcp_init(rdpTcp * tcp, uint32 minsize)
-{
- STREAM result = &(tcp->out);
-
- if (minsize > result->size)
- {
- result->data = (uint8 *) xrealloc(result->data, minsize);
- result->size = minsize;
- }
- result->p = result->data;
- result->end = result->data + result->size;
- return result;
+ return False;
}
-/* Send data from stream to tcp socket.
- * Will block until all data has been sent. */
void
-tcp_send(rdpTcp * tcp, STREAM s)
+tcp_write(rdpTcp * tcp, char* b, int length)
{
int sent = 0;
int total = 0;
- int length = s->end - s->data;
-#ifndef DISABLE_TLS
- if (tcp->iso->mcs->sec->tls_connected)
- {
- tls_write(tcp->iso->mcs->sec->tls, (char*) s->data, length);
- }
- else
-#endif
+ while (total < length)
{
while (total < length)
{
- while (total < length)
+ sent = send(tcp->sockfd, b + total, length - total, MSG_NOSIGNAL);
+ if (sent <= 0)
{
- sent = send(tcp->sock, s->data + total, length - total, MSG_NOSIGNAL);
- if (sent <= 0)
+ if (sent == -1 && TCP_BLOCKS)
+ {
+ tcp_can_send(tcp->sockfd, 100);
+ sent = 0;
+ }
+ else
{
- if (sent == -1 && TCP_BLOCKS)
- {
- tcp_can_send(tcp->sock, 100);
- sent = 0;
- }
- else
- {
- ui_error(tcp->iso->mcs->sec->rdp->inst, "send: %s\n", TCP_STRERROR);
- return;
- }
+ ui_error(tcp->net->rdp->inst, "send: %s\n", TCP_STRERROR);
+ return;
}
- total += sent;
}
+ total += sent;
}
}
}
-/* Read length bytes from tcp socket to stream and return it.
- * Appends to stream s if specified, otherwise it uses stream from tcp layer.
- * Will block until data available.
- * Returns NULL on error. */
-STREAM
-tcp_recv(rdpTcp * tcp, STREAM s, uint32 length)
+int
+tcp_read(rdpTcp * tcp, char* b, int length)
{
int rcvd = 0;
- uint32 p_offset;
- uint32 new_length;
- uint32 end_offset;
- if (s == NULL)
- {
- /* read into "new" stream */
- if (length > tcp->in.size)
- {
- tcp->in.data = (uint8 *) xrealloc(tcp->in.data, length);
- tcp->in.size = length;
- }
+ if (!ui_select(tcp->net->sec->rdp->inst, tcp->sockfd))
+ return -1; /* user quit */
- tcp->in.end = tcp->in.p = tcp->in.data;
- s = &(tcp->in);
- }
- else
- {
- /* append to existing stream */
- new_length = (s->end - s->data) + length;
- if (new_length > s->size)
- {
- p_offset = s->p - s->data;
- end_offset = s->end - s->data;
- s->data = (uint8 *) xrealloc(s->data, new_length);
- s->size = new_length;
- s->p = s->data + p_offset;
- s->end = s->data + end_offset;
- }
- }
+ rcvd = recv(tcp->sockfd, b, length, 0);
- while (length > 0)
+ if (rcvd < 0)
{
-#ifndef DISABLE_TLS
- if (tcp->iso->mcs->sec->tls_connected)
+ if (rcvd == -1 && TCP_BLOCKS)
{
- rcvd = tls_read(tcp->iso->mcs->sec->tls, (char*) s->end, length);
-
- if (rcvd < 0)
- return NULL;
+ tcp_can_recv(tcp->sockfd, 1);
+ rcvd = 0;
}
else
-#endif
{
- if (!ui_select(tcp->iso->mcs->sec->rdp->inst, tcp->sock))
- return NULL; /* user quit */
-
- rcvd = recv(tcp->sock, s->end, length, 0);
- if (rcvd < 0)
- {
- if (rcvd == -1 && TCP_BLOCKS)
- {
- tcp_can_recv(tcp->sock, 1);
- rcvd = 0;
- }
- else
- {
- ui_error(tcp->iso->mcs->sec->rdp->inst, "recv: %s\n", TCP_STRERROR);
- return NULL;
- }
- }
- else if (rcvd == 0)
- {
- ui_error(tcp->iso->mcs->sec->rdp->inst, "Connection closed\n");
- return NULL;
- }
+ ui_error(tcp->net->rdp->inst, "recv: %s\n", TCP_STRERROR);
+ return -1;
}
-
- s->end += rcvd;
- length -= rcvd;
+ }
+ else if (rcvd == 0)
+ {
+ ui_error(tcp->net->rdp->inst, "Connection closed\n");
+ return -1;
}
- return s;
+ return rcvd;
}
/* Establish a connection on the TCP layer */
RD_BOOL
tcp_connect(rdpTcp * tcp, char * server, int port)
{
- int sock;
+ int sockfd;
uint32 option_value;
socklen_t option_len;
@@ -289,29 +214,29 @@ tcp_connect(rdpTcp * tcp, char * server, int port)
if ((n = getaddrinfo(server, tcp_port_rdp_s, &hints, &res)))
{
- ui_error(tcp->iso->mcs->sec->rdp->inst, "getaddrinfo: %s\n", gai_strerror(n));
+ ui_error(tcp->net->rdp->inst, "getaddrinfo: %s\n", gai_strerror(n));
return False;
}
ressave = res;
- sock = -1;
+ sockfd = -1;
while (res)
{
- sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (!(sock < 0))
+ sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (!(sockfd < 0))
{
- if (connect(sock, res->ai_addr, res->ai_addrlen) == 0)
+ if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
break;
- TCP_CLOSE(sock);
- sock = -1;
+ TCP_CLOSE(sockfd);
+ sockfd = -1;
}
res = res->ai_next;
}
freeaddrinfo(ressave);
- if (sock == -1)
+ if (sockfd == -1)
{
- ui_error(tcp->iso->mcs->sec->rdp->inst, "%s: unable to connect\n", server);
+ ui_error(tcp->net->rdp->inst, "%s: unable to connect\n", server);
return False;
}
@@ -328,13 +253,13 @@ tcp_connect(rdpTcp * tcp, char * server, int port)
}
else if ((servaddr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE)
{
- ui_error(tcp->iso->mcs->sec->rdp->inst, "%s: unable to resolve host\n", server);
+ ui_error(tcp->net->rdp->inst, "%s: unable to resolve host\n", server);
return False;
}
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
- ui_error(tcp->iso->mcs->sec->rdp->inst, "socket: %s\n", TCP_STRERROR);
+ ui_error(tcp->net->rdp->inst, "socket: %s\n", TCP_STRERROR);
return False;
}
@@ -343,40 +268,40 @@ tcp_connect(rdpTcp * tcp, char * server, int port)
if (connect(sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0)
{
- ui_error(tcp->iso->mcs->sec->rdp->inst, "connect: %s\n", TCP_STRERROR);
+ ui_error(tcp->net->rdp->inst, "connect: %s\n", TCP_STRERROR);
TCP_CLOSE(sock);
return False;
}
#endif /* IPv6 */
- tcp->sock = sock;
+ tcp->sockfd = sockfd;
/* set socket as non blocking */
#ifdef _WIN32
{
u_long arg = 1;
- ioctlsocket(tcp->sock, FIONBIO, &arg);
+ ioctlsocket(tcp->sockfd, FIONBIO, &arg);
tcp->wsa_event = WSACreateEvent();
- WSAEventSelect(tcp->sock, tcp->wsa_event, FD_READ);
+ WSAEventSelect(tcp->sockfd, tcp->wsa_event, FD_READ);
}
#else
- option_value = fcntl(tcp->sock, F_GETFL);
+ option_value = fcntl(tcp->sockfd, F_GETFL);
option_value = option_value | O_NONBLOCK;
- fcntl(tcp->sock, F_SETFL, option_value);
+ fcntl(tcp->sockfd, F_SETFL, option_value);
#endif
option_value = 1;
option_len = sizeof(option_value);
- setsockopt(tcp->sock, IPPROTO_TCP, TCP_NODELAY, (void *) &option_value, option_len);
+ setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void *) &option_value, option_len);
/* receive buffer must be a least 16 K */
- if (getsockopt(tcp->sock, SOL_SOCKET, SO_RCVBUF, (void *) &option_value, &option_len) == 0)
+ if (getsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void *) &option_value, &option_len) == 0)
{
if (option_value < (1024 * 16))
{
option_value = 1024 * 16;
option_len = sizeof(option_value);
- setsockopt(tcp->sock, SOL_SOCKET, SO_RCVBUF, (void *) &option_value,
+ setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void *) &option_value,
option_len);
}
}
@@ -388,10 +313,10 @@ tcp_connect(rdpTcp * tcp, char * server, int port)
void
tcp_disconnect(rdpTcp * tcp)
{
- if (tcp->sock != -1)
+ if (tcp->sockfd != -1)
{
- TCP_CLOSE(tcp->sock);
- tcp->sock = -1;
+ TCP_CLOSE(tcp->sockfd);
+ tcp->sockfd = -1;
}
#ifdef _WIN32
if (tcp->wsa_event)
@@ -408,7 +333,7 @@ tcp_get_address(rdpTcp * tcp)
{
struct sockaddr_in sockaddr;
socklen_t len = sizeof(sockaddr);
- if (getsockname(tcp->sock, (struct sockaddr *) &sockaddr, &len) == 0)
+ if (getsockname(tcp->sockfd, (struct sockaddr *) &sockaddr, &len) == 0)
{
uint8 *ip = (uint8 *) & sockaddr.sin_addr;
snprintf(tcp->ipaddr, sizeof(tcp->ipaddr), "%d.%d.%d.%d", ip[0], ip[1], ip[2],
@@ -421,24 +346,19 @@ tcp_get_address(rdpTcp * tcp)
}
rdpTcp *
-tcp_new(struct rdp_iso * iso)
+tcp_new(struct rdp_network * net)
{
rdpTcp * self;
self = (rdpTcp *) xmalloc(sizeof(rdpTcp));
+
if (self != NULL)
{
memset(self, 0, sizeof(rdpTcp));
- self->iso = iso;
-
- self->in.size = 4096;
- self->in.data = (uint8 *) xmalloc(self->in.size);
-
- self->out.size = 4096;
- self->out.data = (uint8 *) xmalloc(self->out.size);
-
- self->sock = -1;
+ self->net = net;
+ self->sockfd = -1;
}
+
return self;
}
@@ -447,8 +367,6 @@ tcp_free(rdpTcp * tcp)
{
if (tcp != NULL)
{
- xfree(tcp->in.data);
- xfree(tcp->out.data);
xfree(tcp);
}
}
diff --git a/libfreerdp-core/tcp.h b/libfreerdp-core/tcp.h
index e5f2d69..e71ded2 100644
--- a/libfreerdp-core/tcp.h
+++ b/libfreerdp-core/tcp.h
@@ -26,28 +26,25 @@
struct rdp_tcp
{
- int sock;
- struct rdp_iso * iso;
- struct stream in;
- struct stream out;
- int tcp_port_rdp;
+ int sockfd;
char ipaddr[32];
+ int tcp_port_rdp;
+ struct rdp_network * net;
#ifdef _WIN32
WSAEVENT wsa_event;
#endif
};
typedef struct rdp_tcp rdpTcp;
+void
+tcp_write(rdpTcp * tcp, char* b, int length);
+int
+tcp_read(rdpTcp * tcp, char* b, int length);
+
RD_BOOL
tcp_can_send(int sck, int millis);
RD_BOOL
tcp_can_recv(int sck, int millis);
-STREAM
-tcp_init(rdpTcp * tcp, uint32 minsize);
-void
-tcp_send(rdpTcp * tcp, STREAM s);
-STREAM
-tcp_recv(rdpTcp * tcp, STREAM s, uint32 length);
RD_BOOL
tcp_connect(rdpTcp * tcp, char * server, int port);
void
@@ -55,7 +52,7 @@ tcp_disconnect(rdpTcp * tcp);
char *
tcp_get_address(rdpTcp * tcp);
rdpTcp *
-tcp_new(struct rdp_iso * iso);
+tcp_new(struct rdp_network * net);
void
tcp_free(rdpTcp * tcp);
diff --git a/libfreerdp-utils/Makefile.am b/libfreerdp-utils/Makefile.am
index d6912fd..eda8d01 100644
--- a/libfreerdp-utils/Makefile.am
+++ b/libfreerdp-utils/Makefile.am
@@ -13,7 +13,8 @@ libfreerdp_utils_la_SOURCES = \
wait_obj.c \
chan_plugin.c \
stopwatch.c \
- profiler.c
+ profiler.c \
+ hexdump.c
libfreerdp_utils_la_CFLAGS = \
-I$(top_srcdir) \
diff --git a/libfreerdp-utils/hexdump.c b/libfreerdp-utils/hexdump.c
new file mode 100644
index 0000000..ce02eed
--- /dev/null
+++ b/libfreerdp-utils/hexdump.c
@@ -0,0 +1,56 @@
+/*
+ FreeRDP: A Remote Desktop Protocol client.
+ Hex Dump Utils
+
+ 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.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include <freerdp/types/base.h>
+
+#include <freerdp/utils/hexdump.h>
+
+void freerdp_hexdump(uint8* data, int length)
+{
+ uint8* p = data;
+ int i, line, offset = 0;
+
+ while (offset < length)
+ {
+ printf("%04x ", offset);
+
+ line = length - offset;
+
+ if (line > FREERDP_HEXDUMP_LINE_LENGTH)
+ line = FREERDP_HEXDUMP_LINE_LENGTH;
+
+ for (i = 0; i < line; i++)
+ printf("%02x ", p[i]);
+
+ for (; i < FREERDP_HEXDUMP_LINE_LENGTH; i++)
+ printf(" ");
+
+ for (i = 0; i < line; i++)
+ printf("%c", (p[i] >= 0x20 && p[i] < 0x7F) ? p[i] : '.');
+
+ printf("\n");
+
+ offset += line;
+ p += line;
+ }
+}
+