libfreerdp-core: merging jsorg71's work on old encryption support

This commit is contained in:
Marc-André Moreau 2011-09-14 22:09:33 -04:00
commit 405026575b
23 changed files with 606 additions and 44 deletions

View File

@ -58,7 +58,8 @@ endif()
# Compiler-specific flags
if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-unused-but-set-variable")
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-unused-but-set-variable")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -lncurses")
if(CMAKE_BUILD_TYPE STREQUAL "Release")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
endif()

View File

@ -78,7 +78,7 @@ target_link_libraries(xfreerdp freerdp-kbd)
target_link_libraries(xfreerdp freerdp-rail)
target_link_libraries(xfreerdp freerdp-chanman)
target_link_libraries(xfreerdp freerdp-utils)
target_link_libraries(xfreerdp ${X11_LIBRARIES})
target_link_libraries(xfreerdp ${X11_LIBRARIES} dl)
install(TARGETS xfreerdp DESTINATION bin)

View File

@ -23,4 +23,4 @@ add_executable(freerdp-test
target_link_libraries(freerdp-test freerdp-core)
target_link_libraries(freerdp-test freerdp-gdi)
target_link_libraries(freerdp-test freerdp-utils)
target_link_libraries(freerdp-test freerdp-chanman)
target_link_libraries(freerdp-test freerdp-chanman dl)

View File

@ -205,6 +205,14 @@ struct rdp_settings
rdpBlob server_random;
rdpBlob server_certificate;
struct rdp_certificate* server_cert;
uint8 sign_key[16];
uint8 decrypt_key[16];
uint8 encrypt_key[16];
uint8 decrypt_update_key[16];
uint8 encrypt_update_key[16];
int rc4_key_len;
boolean console_audio;
boolean console_session;

View File

@ -1522,13 +1522,17 @@ boolean rdp_read_capability_sets(STREAM* s, rdpSettings* settings, uint16 number
{
stream_get_mark(s, bm);
freerdp_hexdump(s->p, 4);
rdp_read_capability_set_header(s, &length, &type);
//printf("%s Capability Set (0x%02X), length:%d\n", CAPSET_TYPE_STRINGS[type], type, length);
settings->received_caps[type] = True;
em = bm + length;
if (stream_get_left(s) < length - 4)
{
printf("stream problem\n");
return False;
}
switch (type)
{
@ -1669,18 +1673,46 @@ boolean rdp_recv_demand_active(rdpRdp* rdp, STREAM* s)
uint16 numberCapabilities;
uint16 lengthSourceDescriptor;
uint16 lengthCombinedCapabilities;
uint32 securityHeader;
if (!rdp_read_header(rdp, s, &length, &channelId))
return False;
if (rdp->settings->encryption)
{
stream_read_uint32(s, securityHeader);
if (securityHeader & SEC_SECURE_CHECKSUM)
{
printf("Error: TODO\n");
return False;
}
if (securityHeader & SEC_ENCRYPT)
{
if (!rdp_decrypt(rdp, s, length - 4))
{
printf("rdp_decrypt failed\n");
return False;
}
}
}
if (channelId != MCS_GLOBAL_CHANNEL_ID)
{
printf("channelId bad\n");
return False;
}
if (!rdp_read_share_control_header(s, &pduLength, &pduType, &rdp->settings->pdu_source))
{
printf("rdp_read_share_control_header failed\n");
return False;
}
if (pduType != PDU_TYPE_DEMAND_ACTIVE)
{
printf("pduType bad\n");
return False;
}
stream_read_uint32(s, rdp->settings->share_id); /* shareId (4 bytes) */
stream_read_uint16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
@ -1691,7 +1723,10 @@ boolean rdp_recv_demand_active(rdpRdp* rdp, STREAM* s)
/* capabilitySets */
if (!rdp_read_capability_sets(s, rdp->settings, numberCapabilities))
{
printf("rdp_read_capability_sets failes\n");
return False;
}
rdp->update->glyph_v2 = (rdp->settings->glyphSupportLevel > GLYPH_SUPPORT_FULL) ? True : False;

View File

@ -227,15 +227,92 @@ void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain)
xfree(x509_cert_chain);
}
static boolean certificate_process_server_public_key(rdpCertificate* certificate, STREAM* s, uint32 length)
{
uint8 magic[4];
uint32 keylen;
uint32 bitlen;
uint32 datalen;
uint32 modlen;
memcpy(magic, s->p, 4);
if (memcmp(magic, "RSA1", 4) != 0)
{
printf("gcc_process_server_public_key: magic error\n");
return False;
}
stream_seek(s, 4);
stream_read_uint32(s, keylen);
stream_read_uint32(s, bitlen);
stream_read_uint32(s, datalen);
memcpy(certificate->cert_info.exponent, s->p, 4);
stream_seek(s, 4);
modlen = keylen - 8;
freerdp_blob_alloc(&(certificate->cert_info.modulus), modlen);
memcpy(certificate->cert_info.modulus.data, s->p, modlen);
stream_seek(s, keylen);
return True;
}
static boolean certificate_process_server_public_signature(rdpCertificate* certificate, STREAM* s, uint32 length)
{
stream_seek(s, length);
return True;
}
/**
* Read a Server Proprietary Certificate.\n
* @param certificate certificate module
* @param s stream
*/
void certificate_read_server_proprietary_certificate(rdpCertificate* certificate, STREAM* s)
boolean certificate_read_server_proprietary_certificate(rdpCertificate* certificate, STREAM* s)
{
DEBUG_CERTIFICATE("Server Proprietary Certificate");
uint32 dwSigAlgId;
uint32 dwKeyAlgId;
uint32 wPublicKeyBlobType;
uint32 wPublicKeyBlobLen;
uint32 wSignatureBlobType;
uint32 wSignatureBlobLen;
printf("Server Proprietary Certificate\n");
stream_read_uint32(s, dwSigAlgId);
stream_read_uint32(s, dwKeyAlgId);
if (!(dwSigAlgId == 1 && dwKeyAlgId == 1))
{
printf("certificate_read_server_proprietary_certificate: parse error 1\n");
return False;
}
stream_read_uint16(s, wPublicKeyBlobType);
if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
{
printf("certificate_read_server_proprietary_certificate: parse error 2\n");
return False;
}
stream_read_uint16(s, wPublicKeyBlobLen);
if (!certificate_process_server_public_key(certificate, s, wPublicKeyBlobLen))
{
printf("certificate_read_server_proprietary_certificate: parse error 3\n");
return False;
}
stream_read_uint16(s, wSignatureBlobType);
if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB)
{
printf("certificate_read_server_proprietary_certificate: parse error 4\n");
return False;
}
stream_read_uint16(s, wSignatureBlobLen);
if (!certificate_process_server_public_signature(certificate, s, wSignatureBlobLen))
{
printf("certificate_read_server_proprietary_certificate: parse error 5\n");
return False;
}
return True;
}
/**
@ -244,7 +321,7 @@ void certificate_read_server_proprietary_certificate(rdpCertificate* certificate
* @param s stream
*/
void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, STREAM* s)
boolean certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, STREAM* s)
{
int i;
uint32 certLength;
@ -280,6 +357,8 @@ void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate,
DEBUG_CERTIFICATE("modulus length:%d", certificate->cert_info.modulus.length);
}
}
return True;
}
/**
@ -289,7 +368,7 @@ void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate,
* @param length certificate length
*/
void certificate_read_server_certificate(rdpCertificate* certificate, uint8* server_cert, int length)
boolean certificate_read_server_certificate(rdpCertificate* certificate, uint8* server_cert, int length)
{
STREAM* s;
uint32 dwVersion;
@ -300,7 +379,7 @@ void certificate_read_server_certificate(rdpCertificate* certificate, uint8* ser
if (length < 1)
{
printf("null server certificate\n");
return;
return False;
}
stream_read_uint32(s, dwVersion); /* dwVersion (4 bytes) */
@ -319,6 +398,9 @@ void certificate_read_server_certificate(rdpCertificate* certificate, uint8* ser
printf("invalid certificate chain version:%d\n", dwVersion & CERT_CHAIN_VERSION_MASK);
break;
}
xfree(s);
return True;
}
/**
@ -327,7 +409,7 @@ void certificate_read_server_certificate(rdpCertificate* certificate, uint8* ser
* @return new certificate module
*/
rdpCertificate* certificate_new(rdpRdp* rdp)
rdpCertificate* certificate_new(void)
{
rdpCertificate* certificate;
@ -335,7 +417,6 @@ rdpCertificate* certificate_new(rdpRdp* rdp)
if (certificate != NULL)
{
certificate->rdp = rdp;
certificate->x509_cert_chain = NULL;
}

View File

@ -37,6 +37,9 @@ typedef struct rdp_certificate rdpCertificate;
#define CERT_PERMANENTLY_ISSUED 0x00000000
#define CERT_TEMPORARILY_ISSUED 0x80000000
#define BB_RSA_KEY_BLOB 6
#define BB_RSA_SIGNATURE_BLOB 8
struct rdp_CertBlob
{
uint32 length;
@ -60,7 +63,6 @@ typedef struct rdp_CertInfo rdpCertInfo;
struct rdp_certificate
{
struct rdp_rdp* rdp;
rdpCertInfo cert_info;
rdpX509CertChain* x509_cert_chain;
};
@ -70,11 +72,11 @@ void certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info);
rdpX509CertChain* certificate_new_x509_certificate_chain(uint32 count);
void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain);
void certificate_read_server_proprietary_certificate(rdpCertificate* certificate, STREAM* s);
void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, STREAM* s);
void certificate_read_server_certificate(rdpCertificate* certificate, uint8* server_cert, int length);
boolean certificate_read_server_proprietary_certificate(rdpCertificate* certificate, STREAM* s);
boolean certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, STREAM* s);
boolean certificate_read_server_certificate(rdpCertificate* certificate, uint8* server_cert, int length);
rdpCertificate* certificate_new(rdpRdp* rdp);
rdpCertificate* certificate_new(void);
void certificate_free(rdpCertificate* certificate);
#ifdef WITH_DEBUG_CERTIFICATE

View File

@ -19,6 +19,7 @@
#include "connection.h"
#include "info.h"
#include "per.h"
/**
* Connection Sequence
@ -80,7 +81,7 @@ boolean rdp_client_connect(rdpRdp* rdp)
ret = transport_connect_nla(rdp->transport);
else if (rdp->nego->selected_protocol & PROTOCOL_TLS)
ret = transport_connect_tls(rdp->transport);
else if (rdp->nego->selected_protocol & PROTOCOL_RDP)
else if (rdp->nego->selected_protocol == PROTOCOL_RDP) /* 0 */
ret = transport_connect_rdp(rdp->transport);
if (!ret)
@ -145,11 +146,85 @@ boolean rdp_client_redirect(rdpRdp* rdp)
return rdp_client_connect(rdp);
}
static boolean rdp_establish_keys(rdpRdp* rdp)
{
uint8 client_random[32];
uint8 crypt_client_random[256 + 8];
uint32 key_len;
uint8* mod;
uint8* exp;
uint32 length;
STREAM* s;
printf("rdp_establish_keys:\n");
if (rdp->settings->encryption == False)
{
/* no RDP encryption */
return True;
}
/* encrypt client random */
memset(crypt_client_random, 0, sizeof(crypt_client_random));
memset(client_random, 0x5e, 32);
crypto_nonce(client_random, 32);
printf("client random\n");
freerdp_hexdump(client_random, 32);
key_len = rdp->settings->server_cert->cert_info.modulus.length;
printf("key_len %d %d %d\n", key_len, rdp->mcs->user_id, MCS_BASE_CHANNEL_ID);
mod = rdp->settings->server_cert->cert_info.modulus.data;
exp = rdp->settings->server_cert->cert_info.exponent;
crypto_rsa_encrypt(client_random, 32, key_len, mod, exp, crypt_client_random);
printf("client crypt random\n");
freerdp_hexdump(crypt_client_random, key_len);
/* send crypt client random to server */
length = 7 + 8 + 4 + 4 + key_len + 8;
s = transport_send_stream_init(rdp->mcs->transport, length);
tpkt_write_header(s, length);
tpdu_write_header(s, 2, 0xf0);
per_write_choice(s, DomainMCSPDU_SendDataRequest << 2);
per_write_integer16(s, rdp->mcs->user_id, MCS_BASE_CHANNEL_ID);
per_write_integer16(s, MCS_GLOBAL_CHANNEL_ID, 0);
stream_write_uint8(s, 0x70);
length = (4 + 4 + key_len + 8) | 0x8000;
stream_write_uint16_be(s, length);
stream_write_uint32(s, 1); /* SEC_CLIENT_RANDOM */
length = key_len + 8;
stream_write_uint32(s, length);
memcpy(s->p, crypt_client_random, length);
stream_seek(s, length);
if (transport_write(rdp->mcs->transport, s) < 0)
{
return False;
}
/* now calculate encrypt / decrypt and upate keys */
if (!security_establish_keys(client_random, rdp->settings))
{
return False;
}
rdp->rc4_decrypt_key = crypto_rc4_init(rdp->settings->decrypt_key, rdp->settings->rc4_key_len);
rdp->rc4_encrypt_key = crypto_rc4_init(rdp->settings->encrypt_key, rdp->settings->rc4_key_len);
printf("key_len %d\n", rdp->settings->rc4_key_len);
printf("decrypt_key\n");
freerdp_hexdump(rdp->settings->decrypt_key, rdp->settings->rc4_key_len);
printf("encrypt_key\n");
freerdp_hexdump(rdp->settings->encrypt_key, rdp->settings->rc4_key_len);
rdp->do_crypt = True;
return True;
}
boolean rdp_client_connect_mcs_connect_response(rdpRdp* rdp, STREAM* s)
{
if (!mcs_recv_connect_response(rdp->mcs, s))
{
printf("rdp_client_connect_mcs_connect_response: mcs_recv_connect_response failed\n");
return False;
}
if (!mcs_send_erect_domain_request(rdp->mcs))
return False;
if (!mcs_send_attach_user_request(rdp->mcs))
@ -229,6 +304,8 @@ boolean rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, STREAM* s)
if (rdp->mcs->user_channel_joined && rdp->mcs->global_channel_joined && all_joined)
{
if (!rdp_establish_keys(rdp))
return False;
if (!rdp_send_client_info(rdp))
return False;
rdp->state = CONNECTION_STATE_LICENSE;

View File

@ -40,7 +40,7 @@
#endif
#define EXPONENT_MAX_SIZE 4
#define MODULUS_MAX_SIZE 64
#define MODULUS_MAX_SIZE 256
#include <freerdp/freerdp.h>
#include <freerdp/utils/blob.h>

View File

@ -55,6 +55,7 @@ uint16 fastpath_read_header(rdpFastPath* fastpath, STREAM* s)
uint8 t;
stream_read_uint8(s, header);
if (fastpath != NULL)
{
fastpath->encryptionFlags = (header & 0xC0) >> 6;
@ -94,6 +95,36 @@ INLINE void fastpath_write_update_header(STREAM* s, uint8 updateCode, uint8 frag
stream_write_uint8(s, updateHeader);
}
uint16 fastpath_read_header_rdp(rdpFastPath* fastpath, STREAM* s)
{
uint8 header;
uint16 length;
uint8 t;
uint16 hs;
hs = 2;
stream_read_uint8(s, header);
if (fastpath != NULL)
{
fastpath->encryptionFlags = (header & 0xC0) >> 6;
fastpath->numberEvents = (header & 0x3C) >> 2;
}
stream_read_uint8(s, length); /* length1 */
/* If most significant bit is not set, length2 is not presented. */
if ((length & 0x80))
{
hs++;
length &= 0x7F;
length <<= 8;
stream_read_uint8(s, t);
length += t;
}
return length - hs;
}
boolean fastpath_read_security_header(rdpFastPath* fastpath, STREAM* s)
{
/* TODO: fipsInformation */

View File

@ -91,6 +91,7 @@ struct rdp_fastpath
};
uint16 fastpath_read_header(rdpFastPath* fastpath, STREAM* s);
uint16 fastpath_read_header_rdp(rdpFastPath* fastpath, STREAM* s);
boolean fastpath_read_security_header(rdpFastPath* fastpath, STREAM* s);
boolean fastpath_recv_updates(rdpFastPath* fastpath, STREAM* s);
boolean fastpath_recv_inputs(rdpFastPath* fastpath, STREAM* s);

View File

@ -20,6 +20,7 @@
#include <freerdp/utils/print.h>
#include "gcc.h"
#include "certificate.h"
/**
* T.124 GCC is defined in:
@ -252,12 +253,16 @@ boolean gcc_read_conference_create_response(STREAM* s, rdpSettings* settings)
per_read_choice(s, &choice);
/* h221NonStandard */
per_read_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
if (!per_read_octet_string(s, h221_sc_key, 4, 4)) /* h221NonStandard, server-to-client H.221 key, "McDn" */
return False;
/* userData (OCTET_STRING) */
per_read_length(s, &length);
if (!gcc_read_server_data_blocks(s, settings, length))
{
printf("gcc_read_conference_create_response: gcc_read_server_data_blocks failed\n");
return False;
}
return True;
}
@ -359,34 +364,49 @@ boolean gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length
uint16 type;
uint16 offset = 0;
uint16 blockLength;
uint8* holdp;
while (offset < length)
{
holdp = s->p;
if (!gcc_read_user_data_header(s, &type, &blockLength))
{
printf("gcc_read_server_data_blocks: gcc_read_user_data_header failed\n");
return False;
}
switch (type)
{
case SC_CORE:
if (!gcc_read_server_core_data(s, settings))
{
printf("gcc_read_server_data_blocks: gcc_read_server_core_data failed\n");
return False;
}
break;
case SC_SECURITY:
if (!gcc_read_server_security_data(s, settings))
{
printf("gcc_read_server_data_blocks: gcc_read_server_security_data failed\n");
return False;
}
break;
case SC_NET:
if (!gcc_read_server_network_data(s, settings))
{
printf("gcc_read_server_data_blocks: gcc_read_server_network_data failed\n");
return False;
}
break;
default:
break;
}
offset += blockLength;
s->p = holdp + blockLength;
}
return True;
@ -731,7 +751,7 @@ void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
{
gcc_write_user_data_header(s, CS_SECURITY, 12);
if (settings->encryption > 0)
if (settings->encryption)
{
stream_write_uint32(s, settings->encryption_method); /* encryptionMethods */
stream_write_uint32(s, 0); /* extEncryptionMethods */
@ -746,17 +766,20 @@ void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
boolean gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
{
uint32 encryptionMethod;
uint32 encryptionLevel;
uint32 serverRandomLen;
uint32 serverCertLen;
uint8* data;
uint32 len;
stream_read_uint32(s, encryptionMethod); /* encryptionMethod */
stream_read_uint32(s, encryptionLevel); /* encryptionLevel */
stream_read_uint32(s, settings->encryption_method); /* encryptionMethod */
stream_read_uint32(s, settings->encryption_level); /* encryptionLevel */
if (encryptionMethod == 0 && encryptionLevel == 0)
if (settings->encryption_method == 0 && settings->encryption_level == 0)
{
/* serverRandom and serverRandom must not be present */
settings->encryption = False;
settings->encryption_method = ENCRYPTION_METHOD_NONE;
settings->encryption_level = ENCRYPTION_LEVEL_NONE;
return True;
}
@ -769,6 +792,11 @@ boolean gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
freerdp_blob_alloc(&settings->server_random, serverRandomLen);
memcpy(settings->server_random.data, s->p, serverRandomLen);
stream_seek(s, serverRandomLen);
freerdp_hexdump(settings->server_random.data, settings->server_random.length);
}
else
{
return False;
}
if (serverCertLen > 0)
@ -777,6 +805,18 @@ boolean gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
freerdp_blob_alloc(&settings->server_certificate, serverCertLen);
memcpy(settings->server_certificate.data, s->p, serverCertLen);
stream_seek(s, serverCertLen);
certificate_free(settings->server_cert);
settings->server_cert = certificate_new();
data = settings->server_certificate.data;
len = settings->server_certificate.length;
if (!certificate_read_server_certificate(settings->server_cert, data, len))
{
return False;
}
}
else
{
return False;
}
return True;

View File

@ -584,11 +584,10 @@ boolean rdp_send_client_info(rdpRdp* rdp)
{
STREAM* s;
//rdp->settings->crypt_flags |= SEC_INFO_PKT;
rdp->sec_flags |= SEC_INFO_PKT;
s = rdp_send_stream_init(rdp);
rdp_write_security_header(s, SEC_INFO_PKT);
rdp_write_info_packet(s, rdp->settings);
return rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID);
}

View File

@ -870,7 +870,8 @@ rdpLicense* license_new(rdpRdp* rdp)
{
license->rdp = rdp;
license->state = LICENSE_STATE_AWAIT;
license->certificate = certificate_new(rdp);
//license->certificate = certificate_new(rdp);
license->certificate = certificate_new();
license->product_info = license_new_product_info();
license->error_info = license_new_binary_blob(BB_ERROR_BLOB);
license->key_exchange_list = license_new_binary_blob(BB_KEY_EXCHG_ALG_BLOB);

View File

@ -517,7 +517,10 @@ boolean mcs_recv_connect_response(rdpMcs* mcs, STREAM* s)
ber_read_octet_string(s, &length);
if (!gcc_read_conference_create_response(s, mcs->transport->settings))
{
printf("mcs_recv_connect_response: gcc_read_conference_create_response failed\n");
return False;
}
return True;
}

View File

@ -157,15 +157,20 @@ static boolean peer_recv_fastpath_pdu(rdpPeer* peer, STREAM* s)
{
uint16 length;
length = fastpath_read_header(peer->rdp->fastpath, s);
if (length == 0 || length > stream_get_size(s))
length = fastpath_read_header_rdp(peer->rdp->fastpath, s);
if (length == 0 || length > stream_get_left(s))
{
printf("incorrect FastPath PDU header length %d\n", length);
return False;
}
if (!fastpath_read_security_header(peer->rdp->fastpath, s))
return False;
if (peer->rdp->fastpath->encryptionFlags & FASTPATH_OUTPUT_ENCRYPTED)
{
rdp_decrypt(peer->rdp, s, length);
}
//if (!fastpath_read_security_header(peer->rdp->fastpath, s))
// return False;
return fastpath_recv_inputs(peer->rdp->fastpath, s);
}

View File

@ -156,6 +156,20 @@ void rdp_write_share_data_header(STREAM* s, uint16 length, uint8 type, uint32 sh
stream_write_uint16(s, 0); /* compressedLength (2 bytes) */
}
static int rdp_security_stream_init(rdpRdp* rdp, STREAM* s)
{
if (rdp->do_crypt)
{
stream_seek(s, 12);
rdp->sec_flags |= SEC_ENCRYPT;
}
else if (rdp->sec_flags != 0)
{
stream_seek(s, 4);
}
return 0;
}
/**
* Initialize an RDP packet stream.\n
* @param rdp rdp module
@ -165,8 +179,11 @@ void rdp_write_share_data_header(STREAM* s, uint16 length, uint8 type, uint32 sh
STREAM* rdp_send_stream_init(rdpRdp* rdp)
{
STREAM* s;
s = transport_send_stream_init(rdp->transport, 2048);
stream_seek(s, RDP_PACKET_HEADER_LENGTH);
rdp_security_stream_init(rdp, s);
return s;
}
@ -175,6 +192,7 @@ STREAM* rdp_pdu_init(rdpRdp* rdp)
STREAM* s;
s = transport_send_stream_init(rdp->transport, 2048);
stream_seek(s, RDP_PACKET_HEADER_LENGTH);
rdp_security_stream_init(rdp, s);
stream_seek(s, RDP_SHARE_CONTROL_HEADER_LENGTH);
return s;
}
@ -184,6 +202,7 @@ STREAM* rdp_data_pdu_init(rdpRdp* rdp)
STREAM* s;
s = transport_send_stream_init(rdp->transport, 2048);
stream_seek(s, RDP_PACKET_HEADER_LENGTH);
rdp_security_stream_init(rdp, s);
stream_seek(s, RDP_SHARE_CONTROL_HEADER_LENGTH);
stream_seek(s, RDP_SHARE_DATA_HEADER_LENGTH);
return s;
@ -239,6 +258,45 @@ void rdp_write_header(rdpRdp* rdp, STREAM* s, uint16 length, uint16 channel_id)
stream_write_uint16_be(s, length); /* userData (OCTET_STRING) */
}
static uint32 rdp_security_stream_out(rdpRdp* rdp, STREAM* s, int length)
{
uint32 ml;
uint8* mk;
uint8* data;
uint32 sec_flags;
sec_flags = rdp->sec_flags;
if (sec_flags != 0)
{
rdp_write_security_header(s, sec_flags);
if (sec_flags & SEC_ENCRYPT)
{
data = s->p + 8;
length = length - (data - s->data);
mk = rdp->settings->sign_key;
ml = rdp->settings->rc4_key_len;
security_mac_signature(mk, ml, data, length, s->p);
stream_seek(s, 8);
security_encrypt(s->p, length, rdp);
}
rdp->sec_flags = 0;
}
return 0;
}
static uint32 rdp_get_sec_bytes(uint32 sec_flags)
{
uint32 sec_bytes;
if (sec_flags & SEC_ENCRYPT)
sec_bytes = 12;
else if (sec_flags != 0)
sec_bytes = 4;
else
sec_bytes = 0;
return sec_bytes;
}
/**
* Send an RDP packet.\n
* @param rdp RDP module
@ -249,12 +307,22 @@ void rdp_write_header(rdpRdp* rdp, STREAM* s, uint16 length, uint16 channel_id)
boolean rdp_send(rdpRdp* rdp, STREAM* s, uint16 channel_id)
{
uint16 length;
uint32 sec_bytes;
uint8* sec_hold;
printf("rdp_send:\n");
length = stream_get_length(s);
stream_set_pos(s, 0);
rdp_write_header(rdp, s, length, channel_id);
sec_bytes = rdp_get_sec_bytes(rdp->sec_flags);
sec_hold = s->p;
stream_seek(s, sec_bytes);
s->p = sec_hold;
rdp_security_stream_out(rdp, s, length);
stream_set_pos(s, length);
if (transport_write(rdp->transport, s) < 0)
return False;
@ -265,13 +333,23 @@ boolean rdp_send(rdpRdp* rdp, STREAM* s, uint16 channel_id)
boolean rdp_send_pdu(rdpRdp* rdp, STREAM* s, uint16 type, uint16 channel_id)
{
uint16 length;
uint32 sec_bytes;
uint8* sec_hold;
length = stream_get_length(s);
stream_set_pos(s, 0);
rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
sec_bytes = rdp_get_sec_bytes(rdp->sec_flags);
sec_hold = s->p;
stream_seek(s, sec_bytes);
rdp_write_share_control_header(s, length, type, channel_id);
s->p = sec_hold;
rdp_security_stream_out(rdp, s, length);
stream_set_pos(s, length);
if (transport_write(rdp->transport, s) < 0)
return False;
@ -282,16 +360,26 @@ boolean rdp_send_pdu(rdpRdp* rdp, STREAM* s, uint16 type, uint16 channel_id)
boolean rdp_send_data_pdu(rdpRdp* rdp, STREAM* s, uint8 type, uint16 channel_id)
{
uint16 length;
uint32 sec_bytes;
uint8* sec_hold;
length = stream_get_length(s);
stream_set_pos(s, 0);
rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
sec_bytes = rdp_get_sec_bytes(rdp->sec_flags);
sec_hold = s->p;
stream_seek(s, sec_bytes);
rdp_write_share_control_header(s, length, PDU_TYPE_DATA, channel_id);
rdp_write_share_data_header(s, length, type, rdp->settings->share_id);
//printf("send %s Data PDU (0x%02X), length:%d\n", DATA_PDU_TYPE_STRINGS[type], type, length);
s->p = sec_hold;
rdp_security_stream_out(rdp, s, length);
stream_set_pos(s, length);
if (transport_write(rdp->transport, s) < 0)
return False;
@ -437,6 +525,26 @@ boolean rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, STREAM* s)
}
}
/**
* Decrypt an RDP packet.\n
* @param rdp RDP module
* @param s stream
* @param length int
*/
boolean rdp_decrypt(rdpRdp* rdp, STREAM* s, int length)
{
int cryptlen;
//printf("rdp_decrypt:\n");
stream_seek(s, 8); /* signature */
cryptlen = length - 8;
//printf("length %d cryptlen %d\n", length, cryptlen);
security_decrypt(s->p, cryptlen, rdp);
//freerdp_hexdump(s->p, cryptlen);
return True;
}
/**
* Process an RDP packet.\n
* @param rdp RDP module
@ -449,6 +557,7 @@ static boolean rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
uint16 pduType;
uint16 pduLength;
uint16 channelId;
uint32 securityHeader;
if (!rdp_read_header(rdp, s, &length, &channelId))
{
@ -456,6 +565,24 @@ static boolean rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
return False;
}
if (rdp->settings->encryption)
{
stream_read_uint32(s, securityHeader);
if (securityHeader & SEC_SECURE_CHECKSUM)
{
printf("Error: TODO\n");
return False;
}
if (securityHeader & SEC_ENCRYPT)
{
if (!rdp_decrypt(rdp, s, length - 4))
{
printf("rdp_decrypt failed\n");
return False;
}
}
}
if (channelId != MCS_GLOBAL_CHANNEL_ID)
{
vchan_process(rdp->vchan, s, channelId);
@ -492,15 +619,18 @@ static boolean rdp_recv_fastpath_pdu(rdpRdp* rdp, STREAM* s)
{
uint16 length;
length = fastpath_read_header(rdp->fastpath, s);
if (length == 0 || length > stream_get_size(s))
length = fastpath_read_header_rdp(rdp->fastpath, s);
if (length == 0 || length > stream_get_left(s))
{
printf("incorrect FastPath PDU header length %d\n", length);
return False;
}
if (!fastpath_read_security_header(rdp->fastpath, s))
return False;
if (rdp->fastpath->encryptionFlags & FASTPATH_OUTPUT_ENCRYPTED)
{
rdp_decrypt(rdp, s, length);
}
return fastpath_recv_updates(rdp->fastpath, s);
}
@ -556,7 +686,10 @@ static int rdp_recv_callback(rdpTransport* transport, STREAM* s, void* extra)
case CONNECTION_STATE_CAPABILITY:
if (!rdp_client_connect_demand_active(rdp, s))
{
printf("rdp_client_connect_demand_active failed\n");
return -1;
}
break;
case CONNECTION_STATE_ACTIVE:

View File

@ -128,6 +128,12 @@ struct rdp_rdp
struct rdp_transport* transport;
struct rdp_vchan* vchan;
struct rdp_mppc* mppc;
struct crypto_rc4_struct* rc4_decrypt_key;
int decrypt_use_count;
struct crypto_rc4_struct* rc4_encrypt_key;
int encrypt_use_count;
uint32 sec_flags;
boolean do_crypt;
};
void rdp_read_security_header(STREAM* s, uint16* flags);
@ -171,4 +177,6 @@ void rdp_free(rdpRdp* rdp);
#define DEBUG_RDP(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
boolean rdp_decrypt(rdpRdp* rdp, STREAM* s, int length);
#endif /* __RDP_H */

View File

@ -97,19 +97,23 @@ void security_mac_salt_key(uint8* session_key_blob, uint8* client_random, uint8*
memcpy(output, session_key_blob, 16);
}
void security_licensing_encryption_key(uint8* session_key_blob, uint8* client_random, uint8* server_random, uint8* output)
void security_md5_16_32_32(uint8* in0, uint8* in1, uint8* in2, uint8* output)
{
CryptoMd5 md5;
/* LicensingEncryptionKey = MD5(Second128Bits(SessionKeyBlob) + ClientRandom + ServerRandom)) */
md5 = crypto_md5_init();
crypto_md5_update(md5, &session_key_blob[16], 16); /* Second128Bits(SessionKeyBlob) */
crypto_md5_update(md5, client_random, 32); /* ClientRandom */
crypto_md5_update(md5, server_random, 32); /* ServerRandom */
crypto_md5_update(md5, in0, 16);
crypto_md5_update(md5, in1, 32);
crypto_md5_update(md5, in2, 32);
crypto_md5_final(md5, output);
}
void security_licensing_encryption_key(uint8* session_key_blob, uint8* client_random, uint8* server_random, uint8* output)
{
/* LicensingEncryptionKey = MD5(Second128Bits(SessionKeyBlob) + ClientRandom + ServerRandom)) */
security_md5_16_32_32(&session_key_blob[16], client_random, server_random, output);
}
void security_uint32_le(uint8* output, uint32 value)
{
output[0] = (value) & 0xFF;
@ -172,3 +176,119 @@ void security_mac_signature(uint8* mac_key, int mac_key_length, uint8* data, uin
memcpy(output, md5_digest, 8);
}
static void security_A(uint8* master_secret, uint8* client_random, uint8* server_random, uint8* output)
{
security_premaster_hash("A", 1, master_secret, client_random, server_random, &output[0]);
security_premaster_hash("BB", 2, master_secret, client_random, server_random, &output[16]);
security_premaster_hash("CCC", 3, master_secret, client_random, server_random, &output[32]);
}
static void security_X(uint8* master_secret, uint8* client_random, uint8* server_random, uint8* output)
{
security_premaster_hash("X", 1, master_secret, client_random, server_random, &output[0]);
security_premaster_hash("YY", 2, master_secret, client_random, server_random, &output[16]);
security_premaster_hash("ZZZ", 3, master_secret, client_random, server_random, &output[32]);
}
boolean security_establish_keys(uint8* client_random, rdpSettings* settings)
{
uint8 pre_master_secret[48];
uint8 master_secret[48];
uint8 session_key_blob[48];
uint8* server_random;
uint8 salt40[] = { 0xD1, 0x26, 0x9E };
printf("security_establish_keys:\n");
server_random = settings->server_random.data;
freerdp_hexdump(client_random, 32);
freerdp_hexdump(server_random, 32);
memcpy(pre_master_secret, client_random, 24);
memcpy(pre_master_secret + 24, server_random, 24);
security_A(pre_master_secret, client_random, server_random, master_secret);
security_X(master_secret, client_random, server_random, session_key_blob);
memcpy(settings->sign_key, session_key_blob, 16);
security_md5_16_32_32(&session_key_blob[16], client_random, server_random, settings->decrypt_key);
security_md5_16_32_32(&session_key_blob[32], client_random, server_random, settings->encrypt_key);
if (settings->encryption_method == 1) /* 40 and 56 bit */
{
memcpy(settings->sign_key, salt40, 3); /* TODO 56 bit */
memcpy(settings->decrypt_key, salt40, 3); /* TODO 56 bit */
memcpy(settings->encrypt_key, salt40, 3); /* TODO 56 bit */
settings->rc4_key_len = 8;
}
else /* 128 bit */
{
settings->rc4_key_len = 16;
}
memcpy(settings->decrypt_update_key, settings->decrypt_key, 16);
memcpy(settings->encrypt_update_key, settings->encrypt_key, 16);
return True;
}
boolean security_key_update(uint8* key, uint8* update_key, int key_len)
{
uint8 sha1h[20];
CryptoMd5 md5;
CryptoSha1 sha1;
CryptoRc4 rc4;
uint8 salt40[] = { 0xD1, 0x26, 0x9E };
sha1 = crypto_sha1_init();
crypto_sha1_update(sha1, update_key, key_len);
crypto_sha1_update(sha1, pad1, sizeof(pad1));
crypto_sha1_update(sha1, key, key_len);
crypto_sha1_final(sha1, sha1h);
md5 = crypto_md5_init();
crypto_md5_update(md5, update_key, key_len);
crypto_md5_update(md5, pad2, sizeof(pad2));
crypto_md5_update(md5, sha1h, 20);
crypto_md5_final(md5, key);
rc4 = crypto_rc4_init(key, key_len);
crypto_rc4(rc4, key_len, key, key);
crypto_rc4_free(rc4);
if (key_len == 8)
memcpy(key, salt40, 3); /* TODO 56 bit */
return True;
}
boolean security_encrypt(uint8* data, int length, rdpRdp* rdp)
{
if (rdp->encrypt_use_count >= 4096)
{
security_key_update(rdp->settings->encrypt_key, rdp->settings->encrypt_update_key, rdp->settings->rc4_key_len);
crypto_rc4_free(rdp->rc4_encrypt_key);
rdp->rc4_encrypt_key = crypto_rc4_init(rdp->settings->encrypt_key, rdp->settings->rc4_key_len);
rdp->encrypt_use_count = 0;
}
crypto_rc4(rdp->rc4_encrypt_key, length, data, data);
rdp->encrypt_use_count += 1;
return True;
}
boolean security_decrypt(uint8* data, int length, rdpRdp* rdp)
{
if (rdp->decrypt_use_count >= 4096)
{
security_key_update(rdp->settings->decrypt_key, rdp->settings->decrypt_update_key, rdp->settings->rc4_key_len);
crypto_rc4_free(rdp->rc4_decrypt_key);
rdp->rc4_decrypt_key = crypto_rc4_init(rdp->settings->decrypt_key, rdp->settings->rc4_key_len);
rdp->decrypt_use_count = 0;
}
crypto_rc4(rdp->rc4_decrypt_key, length, data, data);
rdp->decrypt_use_count += 1;
return True;
}

View File

@ -33,5 +33,9 @@ void security_licensing_encryption_key(uint8* session_key_blob, uint8* client_ra
void security_mac_data(uint8* mac_salt_key, uint8* data, uint32 length, uint8* output);
void security_mac_signature(uint8* mac_key, int mac_key_length, uint8* data, uint32 length, uint8* output);
boolean security_establish_keys(uint8* client_random, rdpSettings* settings);
boolean security_encrypt(uint8* data, int length, rdpRdp* rdp);
boolean security_decrypt(uint8* data, int length, rdpRdp* rdp);
#endif /* __SECURITY_H */

View File

@ -169,6 +169,8 @@ void settings_free(rdpSettings* settings)
xfree(settings->client_dir);
xfree(settings->cert_file);
xfree(settings->privatekey_file);
freerdp_blob_free(&(settings->server_certificate));
certificate_free(settings->server_cert);
xfree(settings);
}
}

View File

@ -166,6 +166,11 @@ int tcp_read(rdpTcp* tcp, uint8* data, int length)
perror("recv");
return -1;
}
else
{
//printf("tcp_read: length %d\n", status);
//freerdp_hexdump(data, status);
}
return status;
}
@ -176,6 +181,9 @@ int tcp_write(rdpTcp* tcp, uint8* data, int length)
status = send(tcp->sockfd, data, length, MSG_NOSIGNAL);
//printf("tcp_write: length %d\n", status);
//freerdp_hexdump(data, status);
if (status < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)

View File

@ -367,6 +367,9 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
settings->rdp_security = True;
settings->tls_security = False;
settings->nla_security = False;
settings->encryption = True;
settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT;
settings->encryption_level = ENCRYPTION_LEVEL_HIGH;
}
else if (strncmp("tls", argv[index], 1) == 0) /* TLS */
{