当前仓库属于关闭状态,部分功能使用受限,详情请查阅 仓库状态说明
1 Star 1 Fork 0

Charles / rdesktop
关闭

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
secure.c 28.01 KB
一键复制 编辑 原始数据 按行查看 历史
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049
/* -*- c-basic-offset: 8 -*-
rdesktop: A Remote Desktop Protocol client.
Protocol services - RDP encryption and licensing
Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
Copyright 2005-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
Copyright 2017-2018 Henrik Andersson <hean01@cendio.se> for Cendio AB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rdesktop.h"
#include "ssl.h"
extern char g_hostname[16];
extern uint32 g_requested_session_width;
extern uint32 g_requested_session_height;
extern int g_dpi;
extern unsigned int g_keylayout;
extern int g_keyboard_type;
extern int g_keyboard_subtype;
extern int g_keyboard_functionkeys;
extern RD_BOOL g_encryption;
extern RD_BOOL g_licence_issued;
extern RD_BOOL g_licence_error_result;
extern RDP_VERSION g_rdp_version;
extern RD_BOOL g_console_session;
extern uint32 g_redirect_session_id;
extern int g_server_depth;
extern VCHANNEL g_channels[];
extern unsigned int g_num_channels;
extern uint8 g_client_random[SEC_RANDOM_SIZE];
static int g_rc4_key_len;
static RDSSL_RC4 g_rc4_decrypt_key;
static RDSSL_RC4 g_rc4_encrypt_key;
static uint32 g_server_public_key_len;
static uint8 g_sec_sign_key[16];
static uint8 g_sec_decrypt_key[16];
static uint8 g_sec_encrypt_key[16];
static uint8 g_sec_decrypt_update_key[16];
static uint8 g_sec_encrypt_update_key[16];
static uint8 g_sec_crypted_random[SEC_MAX_MODULUS_SIZE];
uint16 g_server_rdp_version = 0;
/* These values must be available to reset state - Session Directory */
static int g_sec_encrypt_use_count = 0;
static int g_sec_decrypt_use_count = 0;
/*
* I believe this is based on SSLv3 with the following differences:
* MAC algorithm (5.2.3.1) uses only 32-bit length in place of seq_num/type/length fields
* MAC algorithm uses SHA1 and MD5 for the two hash functions instead of one or other
* key_block algorithm (6.2.2) uses 'X', 'YY', 'ZZZ' instead of 'A', 'BB', 'CCC'
* key_block partitioning is different (16 bytes each: MAC secret, decrypt key, encrypt key)
* encryption/decryption keys updated every 4096 packets
* See http://wp.netscape.com/eng/ssl3/draft302.txt
*/
/*
* 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)
{
uint8 shasig[20];
uint8 pad[4];
RDSSL_SHA1 sha1;
RDSSL_MD5 md5;
int i;
for (i = 0; i < 3; i++)
{
memset(pad, salt + i, i + 1);
rdssl_sha1_init(&sha1);
rdssl_sha1_update(&sha1, pad, i + 1);
rdssl_sha1_update(&sha1, in, 48);
rdssl_sha1_update(&sha1, salt1, 32);
rdssl_sha1_update(&sha1, salt2, 32);
rdssl_sha1_final(&sha1, shasig);
rdssl_md5_init(&md5);
rdssl_md5_update(&md5, in, 48);
rdssl_md5_update(&md5, shasig, 20);
rdssl_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)
{
RDSSL_MD5 md5;
rdssl_md5_init(&md5);
rdssl_md5_update(&md5, in, 16);
rdssl_md5_update(&md5, salt1, 32);
rdssl_md5_update(&md5, salt2, 32);
rdssl_md5_final(&md5, out);
}
/*
* 16-byte sha1 hash
*/
void
sec_hash_sha1_16(uint8 * out, uint8 * in, uint8 * salt1)
{
RDSSL_SHA1 sha1;
rdssl_sha1_init(&sha1);
rdssl_sha1_update(&sha1, in, 16);
rdssl_sha1_update(&sha1, salt1, 16);
rdssl_sha1_final(&sha1, out);
}
/* create string from hash */
void
sec_hash_to_string(char *out, int out_size, uint8 * in, int in_size)
{
int k;
memset(out, 0, out_size);
for (k = 0; k < in_size; k++, out += 2)
{
sprintf(out, "%.2x", in[k]);
}
}
/* 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(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(g_sec_sign_key, key_block, 16);
/* Generate export keys from next two blocks of 16 bytes */
sec_hash_16(g_sec_decrypt_key, &key_block[16], client_random, server_random);
sec_hash_16(g_sec_encrypt_key, &key_block[32], client_random, server_random);
if (rc4_key_size == 1)
{
logger(Protocol, Debug, "sec_generate_keys(), 40-bit encryption enabled");
sec_make_40bit(g_sec_sign_key);
sec_make_40bit(g_sec_decrypt_key);
sec_make_40bit(g_sec_encrypt_key);
g_rc4_key_len = 8;
}
else
{
logger(Protocol, Debug,
"sec_generate_key(), rc_4_key_size == %d, 128-bit encryption enabled",
rc4_key_size);
g_rc4_key_len = 16;
}
/* Save initial RC4 keys as update keys */
memcpy(g_sec_decrypt_update_key, g_sec_decrypt_key, 16);
memcpy(g_sec_encrypt_update_key, g_sec_encrypt_key, 16);
/* Initialise RC4 state arrays */
rdssl_rc4_set_key(&g_rc4_decrypt_key, g_sec_decrypt_key, g_rc4_key_len);
rdssl_rc4_set_key(&g_rc4_encrypt_key, g_sec_encrypt_key, g_rc4_key_len);
}
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
};
/* 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];
RDSSL_SHA1 sha1;
RDSSL_MD5 md5;
buf_out_uint32(lenhdr, datalen);
rdssl_sha1_init(&sha1);
rdssl_sha1_update(&sha1, session_key, keylen);
rdssl_sha1_update(&sha1, pad_54, 40);
rdssl_sha1_update(&sha1, lenhdr, 4);
rdssl_sha1_update(&sha1, data, datalen);
rdssl_sha1_final(&sha1, shasig);
rdssl_md5_init(&md5);
rdssl_md5_update(&md5, session_key, keylen);
rdssl_md5_update(&md5, pad_92, 48);
rdssl_md5_update(&md5, shasig, 20);
rdssl_md5_final(&md5, md5sig);
memcpy(signature, md5sig, siglen);
}
/* Update an encryption key */
static void
sec_update(uint8 * key, uint8 * update_key)
{
uint8 shasig[20];
RDSSL_SHA1 sha1;
RDSSL_MD5 md5;
RDSSL_RC4 update;
rdssl_sha1_init(&sha1);
rdssl_sha1_update(&sha1, update_key, g_rc4_key_len);
rdssl_sha1_update(&sha1, pad_54, 40);
rdssl_sha1_update(&sha1, key, g_rc4_key_len);
rdssl_sha1_final(&sha1, shasig);
rdssl_md5_init(&md5);
rdssl_md5_update(&md5, update_key, g_rc4_key_len);
rdssl_md5_update(&md5, pad_92, 48);
rdssl_md5_update(&md5, shasig, 20);
rdssl_md5_final(&md5, key);
rdssl_rc4_set_key(&update, key, g_rc4_key_len);
rdssl_rc4_crypt(&update, key, key, g_rc4_key_len);
if (g_rc4_key_len == 8)
sec_make_40bit(key);
}
/* Encrypt data using RC4 */
static void
sec_encrypt(uint8 * data, int length)
{
if (g_sec_encrypt_use_count == 4096)
{
sec_update(g_sec_encrypt_key, g_sec_encrypt_update_key);
rdssl_rc4_set_key(&g_rc4_encrypt_key, g_sec_encrypt_key, g_rc4_key_len);
g_sec_encrypt_use_count = 0;
}
rdssl_rc4_crypt(&g_rc4_encrypt_key, data, data, length);
g_sec_encrypt_use_count++;
}
/* Decrypt data using RC4 */
void
sec_decrypt(uint8 * data, int length)
{
if (length <= 0)
return;
if (g_sec_decrypt_use_count == 4096)
{
sec_update(g_sec_decrypt_key, g_sec_decrypt_update_key);
rdssl_rc4_set_key(&g_rc4_decrypt_key, g_sec_decrypt_key, g_rc4_key_len);
g_sec_decrypt_use_count = 0;
}
rdssl_rc4_crypt(&g_rc4_decrypt_key, data, data, length);
g_sec_decrypt_use_count++;
}
/* Perform an RSA public key encryption operation */
static void
sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus,
uint8 * exponent)
{
rdssl_rsa_encrypt(out, in, len, modulus_size, modulus, exponent);
}
/* Initialise secure transport packet */
STREAM
sec_init(uint32 flags, int maxlen)
{
int hdrlen;
STREAM s;
if (!g_licence_issued && !g_licence_error_result)
hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4;
else
hdrlen = (flags & SEC_ENCRYPT) ? 12 : 0;
s = mcs_init(maxlen + hdrlen);
s_push_layer(s, sec_hdr, hdrlen);
return s;
}
/* Transmit secure transport packet over specified channel */
void
sec_send_to_channel(STREAM s, uint32 flags, uint16 channel)
{
int datalen;
#ifdef WITH_SCARD
scard_lock(SCARD_LOCK_SEC);
#endif
s_pop_layer(s, sec_hdr);
if ((!g_licence_issued && !g_licence_error_result) || (flags & SEC_ENCRYPT))
out_uint32_le(s, flags);
if (flags & SEC_ENCRYPT)
{
unsigned char *data;
flags &= ~SEC_ENCRYPT;
datalen = s_remaining(s) - 8;
inout_uint8p(s, data, datalen + 8);
sec_sign(data, 8, g_sec_sign_key, g_rc4_key_len, data + 8, datalen);
sec_encrypt(data + 8, datalen);
}
mcs_send_to_channel(s, channel);
#ifdef WITH_SCARD
scard_unlock(SCARD_LOCK_SEC);
#endif
}
/* Transmit secure transport packet */
void
sec_send(STREAM s, uint32 flags)
{
sec_send_to_channel(s, flags, MCS_GLOBAL_CHANNEL);
}
/* Transfer the client random to the server */
static void
sec_establish_key(void)
{
uint32 length = g_server_public_key_len + SEC_PADDING_SIZE;
uint32 flags = SEC_EXCHANGE_PKT;
STREAM s;
s = sec_init(flags, length + 4);
out_uint32_le(s, length);
out_uint8a(s, g_sec_crypted_random, g_server_public_key_len);
out_uint8s(s, SEC_PADDING_SIZE);
s_mark_end(s);
sec_send(s, flags);
s_free(s);
}
/* Output connect initial data blob */
static void
sec_out_mcs_connect_initial_pdu(STREAM s, uint32 selected_protocol)
{
int length = 162 + 76 + 12 + 4 + (g_dpi > 0 ? 18 : 0);
unsigned int i;
uint32 rdpversion = RDP_40;
uint16 capflags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
uint16 colorsupport = RNS_UD_24BPP_SUPPORT | RNS_UD_16BPP_SUPPORT | RNS_UD_32BPP_SUPPORT;
uint32 physwidth, physheight, desktopscale, devicescale;
logger(Protocol, Debug, "%s()", __func__);
if (g_rdp_version >= RDP_V5)
rdpversion = RDP_50;
if (g_num_channels > 0)
length += g_num_channels * 12 + 8;
/* Generic Conference Control (T.124) ConferenceCreateRequest */
out_uint16_be(s, 5);
out_uint16_be(s, 0x14);
out_uint8(s, 0x7c);
out_uint16_be(s, 1);
out_uint16_be(s, (length | 0x8000)); /* remaining length */
out_uint16_be(s, 8); /* length? */
out_uint16_be(s, 16);
out_uint8(s, 0);
out_uint16_le(s, 0xc001);
out_uint8(s, 0);
out_uint32_le(s, 0x61637544); /* OEM ID: "Duca", as in Ducati. */
out_uint16_be(s, ((length - 14) | 0x8000)); /* remaining length */
/* Client information (TS_UD_CS_CORE) */
out_uint16_le(s, CS_CORE); /* type */
out_uint16_le(s, 216 + (g_dpi > 0 ? 18 : 0)); /* length */
out_uint32_le(s, rdpversion); /* version */
out_uint16_le(s, g_requested_session_width); /* desktopWidth */
out_uint16_le(s, g_requested_session_height); /* desktopHeight */
out_uint16_le(s, RNS_UD_COLOR_8BPP); /* colorDepth */
out_uint16_le(s, RNS_UD_SAS_DEL); /* SASSequence */
out_uint32_le(s, g_keylayout); /* keyboardLayout */
/*
* According to s.1.7 of MS-RDPESC if the build number is at least 4,304,
* SCREDIR_VERSION_LONGHORN is assumed; otherwise SCREDIR_VERSIONXP is to be used
*/
out_uint32_le(s, 2600); /* Client build. We are now 2600 compatible :-) */
/* Unicode name of client, padded to 32 bytes */
out_utf16s_padded(s, g_hostname, 32, 0x00);
out_uint32_le(s, g_keyboard_type); /* keyboardType */
out_uint32_le(s, g_keyboard_subtype); /* keyboardSubtype */
out_uint32_le(s, g_keyboard_functionkeys); /* keyboardFunctionKey */
out_uint8s(s, 64); /* imeFileName */
out_uint16_le(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth (overrides colorDepth) */
out_uint16_le(s, 1); /* clientProductId (should be 1) */
out_uint32_le(s, 0); /* serialNumber (should be 0) */
/* highColorDepth (overrides postBeta2ColorDepth). Capped at 24BPP.
To get 32BPP sessions, we need to set a capability flag. */
out_uint16_le(s, MIN(g_server_depth, 24));
if (g_server_depth == 32)
capflags |= RNS_UD_CS_WANT_32BPP_SESSION;
out_uint16_le(s, colorsupport); /* supportedColorDepths */
out_uint16_le(s, capflags); /* earlyCapabilityFlags */
out_uint8s(s, 64); /* clientDigProductId */
out_uint8(s, 0); /* connectionType */
out_uint8(s, 0); /* pad */
out_uint32_le(s, selected_protocol); /* serverSelectedProtocol */
if (g_dpi > 0)
{
/* Extended client info describing monitor geometry */
utils_calculate_dpi_scale_factors(g_requested_session_width,
g_requested_session_height, g_dpi, &physwidth,
&physheight, &desktopscale, &devicescale);
out_uint32_le(s, physwidth); /* physicalwidth */
out_uint32_le(s, physheight); /* physicalheight */
out_uint16_le(s, ORIENTATION_LANDSCAPE); /* Orientation */
out_uint32_le(s, desktopscale); /* DesktopScaleFactor */
out_uint32_le(s, devicescale); /* DeviceScaleFactor */
}
/* Write a Client Cluster Data (TS_UD_CS_CLUSTER) */
uint32 cluster_flags = 0;
out_uint16_le(s, CS_CLUSTER); /* header.type */
out_uint16_le(s, 12); /* length */
cluster_flags |= SEC_CC_REDIRECTION_SUPPORTED;
cluster_flags |= (SEC_CC_REDIRECT_VERSION_4 << 2);
if (g_console_session || g_redirect_session_id != 0)
cluster_flags |= SEC_CC_REDIRECT_SESSIONID_FIELD_VALID;
out_uint32_le(s, cluster_flags);
out_uint32(s, g_redirect_session_id);
/* Client encryption settings (TS_UD_CS_SEC) */
out_uint16_le(s, CS_SECURITY); /* type */
out_uint16_le(s, 12); /* length */
out_uint32_le(s, g_encryption ? 0x3 : 0); /* encryptionMethods */
out_uint32(s, 0); /* extEncryptionMethods */
/* Channel definitions (TS_UD_CS_NET) */
logger(Protocol, Debug, "sec_out_mcs_data(), g_num_channels is %d", g_num_channels);
if (g_num_channels > 0)
{
out_uint16_le(s, CS_NET); /* type */
out_uint16_le(s, g_num_channels * 12 + 8); /* length */
out_uint32_le(s, g_num_channels); /* number of virtual channels */
for (i = 0; i < g_num_channels; i++)
{
logger(Protocol, Debug, "sec_out_mcs_data(), requesting channel %s",
g_channels[i].name);
out_uint8a(s, g_channels[i].name, 8);
out_uint32_be(s, g_channels[i].flags);
}
}
s_mark_end(s);
}
/* Parse a public key structure */
static RD_BOOL
sec_parse_public_key(STREAM s, uint8 * modulus, uint8 * exponent)
{
uint32 magic, modulus_len;
if (!s_check_rem(s, 8)) {
return False;
}
in_uint32_le(s, magic);
if (magic != SEC_RSA_MAGIC)
{
logger(Protocol, Error, "sec_parse_public_key(), magic (0x%x) != SEC_RSA_MAGIC",
magic);
return False;
}
in_uint32_le(s, modulus_len);
modulus_len -= SEC_PADDING_SIZE;
if ((modulus_len < SEC_MODULUS_SIZE) || (modulus_len > SEC_MAX_MODULUS_SIZE))
{
logger(Protocol, Error,
"sec_parse_public_key(), invalid public key size (%u bits) from server",
modulus_len * 8);
return False;
}
if (!s_check_rem(s, 1 + SEC_EXPONENT_SIZE + modulus_len + SEC_PADDING_SIZE)) {
return False;
}
in_uint8s(s, 8); /* modulus_bits, unknown */
in_uint8a(s, exponent, SEC_EXPONENT_SIZE);
in_uint8a(s, modulus, modulus_len);
in_uint8s(s, SEC_PADDING_SIZE);
g_server_public_key_len = modulus_len;
return True;
}
/* Parse a public signature structure */
static RD_BOOL
sec_parse_public_sig(STREAM s, uint32 len, uint8 * modulus, uint8 * exponent)
{
uint8 signature[SEC_MAX_MODULUS_SIZE];
uint32 sig_len;
if (len != 72)
{
return True;
}
memset(signature, 0, sizeof(signature));
sig_len = len - 8;
in_uint8a(s, signature, sig_len);
return rdssl_sig_ok(exponent, SEC_EXPONENT_SIZE, modulus, g_server_public_key_len,
signature, sig_len);
}
/* Parse a crypto information structure */
static RD_BOOL
sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
uint8 ** server_random, uint8 * modulus, uint8 * exponent)
{
uint32 crypt_level, random_len, rsa_info_len;
uint32 cacert_len, cert_len, flags;
RDSSL_CERT *cacert, *server_cert;
RDSSL_RKEY *server_public_key;
uint16 tag, length;
size_t next_tag;
logger(Protocol, Debug, "%s()", __func__);
in_uint32_le(s, *rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */
in_uint32_le(s, crypt_level); /* 1 = low, 2 = medium, 3 = high */
if (crypt_level == 0)
{
/* no encryption */
logger(Protocol, Debug, "sec_parse_crypt_info(), got ENCRYPTION_LEVEL_NONE");
return False;
}
in_uint32_le(s, random_len);
in_uint32_le(s, rsa_info_len);
if (random_len != SEC_RANDOM_SIZE)
{
logger(Protocol, Error, "sec_parse_crypt_info(), got random len %d, expected %d",
random_len, SEC_RANDOM_SIZE);
return False;
}
in_uint8p(s, *server_random, random_len);
/* RSA info */
if (!s_check_rem(s, rsa_info_len))
{
logger(Protocol, Error, "sec_parse_crypt_info(), !s_check_rem(s, rsa_info_len)");
return False;
}
in_uint32_le(s, flags); /* 1 = RDP4-style, 0x80000002 = X.509 */
if (flags & 1)
{
logger(Protocol, Debug,
"sec_parse_crypt_info(), We're going for the RDP4-style encryption");
in_uint8s(s, 8); /* unknown */
while (!s_check_end(s))
{
in_uint16_le(s, tag);
in_uint16_le(s, length);
next_tag = s_tell(s) + length;
switch (tag)
{
case SEC_TAG_PUBKEY:
if (!sec_parse_public_key(s, modulus, exponent))
{
logger(Protocol, Error,
"sec_parse_crypt_info(), invalid public key");
return False;
}
logger(Protocol, Debug,
"sec_parse_crypt_info(), got public key");
break;
case SEC_TAG_KEYSIG:
if (!sec_parse_public_sig(s, length, modulus, exponent))
{
logger(Protocol, Error,
"sec_parse_crypt_info(), invalid public sig");
return False;
}
break;
default:
logger(Protocol, Warning,
"sec_parse_crypt_info(), unhandled crypt tag 0x%x",
tag);
}
s_seek(s, next_tag);
}
}
else
{
uint32 certcount;
unsigned char *certdata;
logger(Protocol, Debug,
"sec_parse_crypt_info(), We're going for the RDP5-style encryption");
in_uint32_le(s, certcount); /* Number of certificates */
if (certcount < 2)
{
logger(Protocol, Error,
"sec_parse_crypt_info(), server didn't send enough x509 certificates");
return False;
}
for (; certcount > 2; certcount--)
{ /* ignore all the certificates between the root and the signing CA */
uint32 ignorelen;
RDSSL_CERT *ignorecert;
unsigned char *ignoredata;
in_uint32_le(s, ignorelen);
in_uint8p(s, ignoredata, ignorelen);
ignorecert = rdssl_cert_read(ignoredata, ignorelen);
if (ignorecert == NULL)
{ /* XXX: error out? */
logger(Protocol, Error,
"sec_parse_crypt_info(), got a bad cert: this will probably screw up the rest of the communication");
}
else
{
rdssl_cert_free(ignorecert);
}
}
/* Do da funky X.509 stuffy
"How did I find out about this? I looked up and saw a
bright light and when I came to I had a scar on my forehead
and knew about X.500"
- Peter Gutman in a early version of
http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
*/
in_uint32_le(s, cacert_len);
in_uint8p(s, certdata, cacert_len);
logger(Protocol, Debug,
"sec_parse_crypt_info(), server CA Certificate length is %d", cacert_len);
cacert = rdssl_cert_read(certdata, cacert_len);
if (NULL == cacert)
{
logger(Protocol, Error,
"sec_parse_crypt_info(), couldn't load CA Certificate from server");
return False;
}
in_uint32_le(s, cert_len);
in_uint8p(s, certdata, cert_len);
logger(Protocol, Debug, "sec_parse_crypt_info(), certificate length is %d",
cert_len);
server_cert = rdssl_cert_read(certdata, cert_len);
if (NULL == server_cert)
{
rdssl_cert_free(cacert);
logger(Protocol, Error,
"sec_parse_crypt_info(), couldn't load Certificate from server");
return False;
}
if (!rdssl_certs_ok(server_cert, cacert))
{
rdssl_cert_free(server_cert);
rdssl_cert_free(cacert);
logger(Protocol, Error,
"sec_parse_crypt_info(), security error, CA Certificate invalid");
return False;
}
rdssl_cert_free(cacert);
in_uint8s(s, 16); /* Padding */
server_public_key = rdssl_cert_to_rkey(server_cert, &g_server_public_key_len);
if (NULL == server_public_key)
{
logger(Protocol, Debug,
"sec_parse_crypt_info(). failed to parse X509 correctly");
rdssl_cert_free(server_cert);
return False;
}
rdssl_cert_free(server_cert);
if ((g_server_public_key_len < SEC_MODULUS_SIZE) ||
(g_server_public_key_len > SEC_MAX_MODULUS_SIZE))
{
logger(Protocol, Error,
"sec_parse_crypt_info(), bad server public key size (%u bits)",
g_server_public_key_len * 8);
rdssl_rkey_free(server_public_key);
return False;
}
if (rdssl_rkey_get_exp_mod(server_public_key, exponent, SEC_EXPONENT_SIZE,
modulus, SEC_MAX_MODULUS_SIZE) != 0)
{
logger(Protocol, Error,
"sec_parse_crypt_info(), problem extracting RSA exponent, modulus");
rdssl_rkey_free(server_public_key);
return False;
}
rdssl_rkey_free(server_public_key);
return True; /* There's some garbage here we don't care about */
}
return s_check_end(s);
}
/* Process crypto information blob */
static void
sec_process_crypt_info(STREAM s)
{
uint8 *server_random = NULL;
uint8 modulus[SEC_MAX_MODULUS_SIZE];
uint8 exponent[SEC_EXPONENT_SIZE];
uint32 rc4_key_size;
logger(Protocol, Debug, "%s()", __func__);
memset(modulus, 0, sizeof(modulus));
memset(exponent, 0, sizeof(exponent));
if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, modulus, exponent))
return;
logger(Protocol, Debug, "sec_parse_crypt_info(), generating client random");
generate_random(g_client_random);
sec_rsa_encrypt(g_sec_crypted_random, g_client_random, SEC_RANDOM_SIZE,
g_server_public_key_len, modulus, exponent);
sec_generate_keys(g_client_random, server_random, rc4_key_size);
}
/* Process SRV_INFO, find RDP version supported by server */
static void
sec_process_srv_info(STREAM s)
{
in_uint16_le(s, g_server_rdp_version);
logger(Protocol, Debug, "sec_process_srv_info(), server RDP version is %d",
g_server_rdp_version);
if (1 == g_server_rdp_version)
{
g_rdp_version = RDP_V4;
g_server_depth = 8;
}
}
/* Process connect response data blob */
void
sec_process_mcs_data(STREAM s)
{
uint16 tag, length;
size_t next_tag;
uint8 len;
in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */
in_uint8(s, len);
if (len & 0x80)
in_uint8(s, len);
logger(Protocol, Debug, "%s()", __func__);
while (!s_check_end(s))
{
in_uint16_le(s, tag);
in_uint16_le(s, length);
if (length <= 4)
return;
next_tag = s_tell(s) + length - 4;
switch (tag)
{
case SEC_TAG_SRV_INFO:
logger(Protocol, Debug, "%s(), SEC_TAG_SRV_INFO", __func__);
sec_process_srv_info(s);
break;
case SEC_TAG_SRV_CRYPT:
logger(Protocol, Debug, "%s(), SEC_TAG_SRV_CRYPT", __func__);
sec_process_crypt_info(s);
break;
case SEC_TAG_SRV_CHANNELS:
logger(Protocol, Debug, "%s(), SEC_TAG_SRV_CHANNELS", __func__);
/* FIXME: We should parse this information and
use it to map RDP5 channels to MCS
channels */
break;
default:
logger(Protocol, Warning, "Unhandled response tag 0x%x", tag);
}
s_seek(s, next_tag);
}
}
/* Receive secure transport packet */
STREAM
sec_recv(RD_BOOL * is_fastpath)
{
uint8 fastpath_hdr, fastpath_flags;
uint16 sec_flags;
uint16 channel;
STREAM s;
struct stream packet;
size_t data_offset;
size_t remaining;
unsigned char *data;
while ((s = mcs_recv(&channel, is_fastpath, &fastpath_hdr)) != NULL)
{
packet = *s;
if (*is_fastpath == True)
{
/* If fastpath packet is encrypted, read data
signature and decrypt */
/* FIXME: extracting flags from hdr could be made less obscure */
fastpath_flags = (fastpath_hdr & 0xC0) >> 6;
if (fastpath_flags & FASTPATH_OUTPUT_ENCRYPTED)
{
if (!s_check_rem(s, 8)) {
rdp_protocol_error("consume fastpath signature from stream would overrun", &packet);
}
in_uint8s(s, 8); /* signature */
data_offset = s_tell(s);
remaining = s_remaining(s);
inout_uint8p(s, data, remaining);
sec_decrypt(data, remaining);
s_seek(s, data_offset);
}
return s;
}
if (g_encryption || (!g_licence_issued && !g_licence_error_result))
{
data_offset = s_tell(s);
/* TS_SECURITY_HEADER */
in_uint16_le(s, sec_flags);
in_uint8s(s, 2); /* skip sec_flags_hi */
if (g_encryption)
{
data_offset = s_tell(s);
if (sec_flags & SEC_ENCRYPT)
{
if (!s_check_rem(s, 8)) {
rdp_protocol_error("consume encrypt signature from stream would overrun", &packet);
}
in_uint8s(s, 8); /* signature */
data_offset = s_tell(s);
remaining = s_remaining(s);
inout_uint8p(s, data, remaining);
sec_decrypt(data, remaining);
}
if (sec_flags & SEC_LICENSE_PKT)
{
s_seek(s, data_offset);
licence_process(s);
continue;
}
if (sec_flags & SEC_REDIRECTION_PKT)
{
uint8 swapbyte;
if (!s_check_rem(s, 8)) {
rdp_protocol_error("consume redirect signature from stream would overrun", &packet);
}
in_uint8s(s, 8); /* signature */
data_offset = s_tell(s);
remaining = s_remaining(s);
inout_uint8p(s, data, remaining);
sec_decrypt(data, remaining);
/* Check for a redirect packet, starts with 00 04 */
if (data[0] == 0 && data[1] == 4)
{
/* for some reason the PDU and the length seem to be swapped.
This isn't good, but we're going to do a byte for byte
swap. So the first four value appear as: 00 04 XX YY,
where XX YY is the little endian length. We're going to
use 04 00 as the PDU type, so after our swap this will look
like: XX YY 04 00 */
swapbyte = data[0];
data[0] = data[2];
data[2] = swapbyte;
swapbyte = data[1];
data[1] = data[3];
data[3] = swapbyte;
swapbyte = data[2];
data[2] = data[3];
data[3] = swapbyte;
}
}
}
else
{
if (sec_flags & SEC_LICENSE_PKT)
{
licence_process(s);
continue;
}
}
s_seek(s, data_offset);
}
if (channel != MCS_GLOBAL_CHANNEL)
{
channel_process(s, channel);
continue;
}
return s;
}
return NULL;
}
/* Establish a secure connection */
RD_BOOL
sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect)
{
uint32 selected_proto;
STREAM mcs_data;
/* Start a MCS connect sequence */
if (!mcs_connect_start(server, username, domain, password, reconnect, &selected_proto))
return False;
/* We exchange some RDP data during the MCS-Connect */
mcs_data = s_alloc(512);
sec_out_mcs_connect_initial_pdu(mcs_data, selected_proto);
/* finalize the MCS connect sequence */
if (!mcs_connect_finalize(mcs_data))
return False;
/* sec_process_mcs_data(&mcs_data); */
if (g_encryption)
sec_establish_key();
s_free(mcs_data);
return True;
}
/* Disconnect a connection */
void
sec_disconnect(void)
{
/* Perform a User-initiated disconnect sequence, see
[MS-RDPBCGR] 1.3.1.4 Disconnect Sequences */
mcs_disconnect(RN_USER_REQUESTED);
}
/* reset the state of the sec layer */
void
sec_reset_state(void)
{
g_server_rdp_version = 0;
g_sec_encrypt_use_count = 0;
g_sec_decrypt_use_count = 0;
g_licence_issued = 0;
g_licence_error_result = 0;
mcs_reset_state();
}
1
https://gitee.com/chanrain511/rdesktop.git
git@gitee.com:chanrain511/rdesktop.git
chanrain511
rdesktop
rdesktop
master

搜索帮助