⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 secure.c

📁 rdesktop是一个开放源码的Window NT中断服务器的客户端
💻 C
📖 第 1 页 / 共 2 页
字号:
	out_uint32_le(s, 4);	out_uint32(s, 0);	out_uint32_le(s, 12);	out_uint8s(s, 64);	/* reserved? 4 + 12 doublewords */	out_uint16_le(s, 0xca01);	/* colour depth? */	out_uint16_le(s, 1);	out_uint32(s, 0);	out_uint8(s, g_server_bpp);	out_uint16_le(s, 0x0700);	out_uint8(s, 0);	out_uint32_le(s, 1);	out_uint8s(s, 64);	/* End of client info */	out_uint16_le(s, SEC_TAG_CLI_4);	out_uint16_le(s, 12);	out_uint32_le(s, g_console_session ? 0xb : 9);	out_uint32(s, 0);	/* Client encryption settings */	out_uint16_le(s, SEC_TAG_CLI_CRYPT);	out_uint16_le(s, 12);	/* length */	out_uint32_le(s, g_encryption ? 0x3 : 0);	/* encryption supported, 128-bit supported */	out_uint32(s, 0);	/* Unknown */	DEBUG_RDP5(("g_num_channels is %d\n", g_num_channels));	if (g_num_channels > 0)	{		out_uint16_le(s, SEC_TAG_CLI_CHANNELS);		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++)		{			DEBUG_RDP5(("Requesting channel %s\n", 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 BOOLsec_parse_public_key(STREAM s, uint8 ** modulus, uint8 ** exponent){	uint32 magic, modulus_len;	in_uint32_le(s, magic);	if (magic != SEC_RSA_MAGIC)	{		error("RSA magic 0x%x\n", magic);		return False;	}	in_uint32_le(s, modulus_len);	if (modulus_len != SEC_MODULUS_SIZE + SEC_PADDING_SIZE)	{		error("modulus len 0x%x\n", modulus_len);		return False;	}	in_uint8s(s, 8);	/* modulus_bits, unknown */	in_uint8p(s, *exponent, SEC_EXPONENT_SIZE);	in_uint8p(s, *modulus, SEC_MODULUS_SIZE);	in_uint8s(s, SEC_PADDING_SIZE);	return s_check(s);}static BOOLsec_parse_x509_key(X509 * cert){	EVP_PKEY *epk = NULL;	/* By some reason, Microsoft sets the OID of the Public RSA key to	   the oid for "MD5 with RSA Encryption" instead of "RSA Encryption"	   Kudos to Richard Levitte for the following (. intiutive .) 	   lines of code that resets the OID and let's us extract the key. */	if (OBJ_obj2nid(cert->cert_info->key->algor->algorithm) == NID_md5WithRSAEncryption)	{		DEBUG_RDP5(("Re-setting algorithm type to RSA in server certificate\n"));		cert->cert_info->key->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption);	}	epk = X509_get_pubkey(cert);	if (NULL == epk)	{		error("Failed to extract public key from certificate\n");		return False;	}	server_public_key = (RSA *) epk->pkey.ptr;	return True;}/* Parse a crypto information structure */static BOOLsec_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;	X509 *cacert, *server_cert;	uint16 tag, length;	uint8 *next_tag, *end;	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 */		return False;	in_uint32_le(s, random_len);	in_uint32_le(s, rsa_info_len);	if (random_len != SEC_RANDOM_SIZE)	{		error("random len %d, expected %d\n", random_len, SEC_RANDOM_SIZE);		return False;	}	in_uint8p(s, *server_random, random_len);	/* RSA info */	end = s->p + rsa_info_len;	if (end > s->end)		return False;	in_uint32_le(s, flags);	/* 1 = RDP4-style, 0x80000002 = X.509 */	if (flags & 1)	{		DEBUG_RDP5(("We're going for the RDP4-style encryption\n"));		in_uint8s(s, 8);	/* unknown */		while (s->p < end)		{			in_uint16_le(s, tag);			in_uint16_le(s, length);			next_tag = s->p + length;			switch (tag)			{				case SEC_TAG_PUBKEY:					if (!sec_parse_public_key(s, modulus, exponent))						return False;					DEBUG_RDP5(("Got Public key, RDP4-style\n"));					break;				case SEC_TAG_KEYSIG:					/* Is this a Microsoft key that we just got? */					/* Care factor: zero! */					/* Actually, it would probably be a good idea to check if the public key is signed with this key, and then store this 					   key as a known key of the hostname. This would prevent some MITM-attacks. */					break;				default:					unimpl("crypt tag 0x%x\n", tag);			}			s->p = next_tag;		}	}	else	{		uint32 certcount;		DEBUG_RDP5(("We're going for the RDP5-style encryption\n"));		in_uint32_le(s, certcount);	/* Number of certificates */		if (certcount < 2)		{			error("Server didn't send enough X509 certificates\n");			return False;		}		for (; certcount > 2; certcount--)		{		/* ignore all the certificates between the root and the signing CA */			uint32 ignorelen;			X509 *ignorecert;			DEBUG_RDP5(("Ignored certs left: %d\n", certcount));			in_uint32_le(s, ignorelen);			DEBUG_RDP5(("Ignored Certificate length is %d\n", ignorelen));			ignorecert = d2i_X509(NULL, &(s->p), ignorelen);			if (ignorecert == NULL)			{	/* XXX: error out? */				DEBUG_RDP5(("got a bad cert: this will probably screw up the rest of the communication\n"));			}#ifdef WITH_DEBUG_RDP5			DEBUG_RDP5(("cert #%d (ignored):\n", certcount));			X509_print_fp(stdout, ignorecert);#endif		}		/* 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);		DEBUG_RDP5(("CA Certificate length is %d\n", cacert_len));		cacert = d2i_X509(NULL, &(s->p), cacert_len);		/* Note: We don't need to move s->p here - d2i_X509 is		   "kind" enough to do it for us */		if (NULL == cacert)		{			error("Couldn't load CA Certificate from server\n");			return False;		}		/* Currently, we don't use the CA Certificate. 		   FIXME: 		   *) Verify the server certificate (server_cert) with the 		   CA certificate.		   *) Store the CA Certificate with the hostname of the 		   server we are connecting to as key, and compare it		   when we connect the next time, in order to prevent		   MITM-attacks.		 */		in_uint32_le(s, cert_len);		DEBUG_RDP5(("Certificate length is %d\n", cert_len));		server_cert = d2i_X509(NULL, &(s->p), cert_len);		if (NULL == server_cert)		{			error("Couldn't load Certificate from server\n");			return False;		}		in_uint8s(s, 16);	/* Padding */		/* Note: Verifying the server certificate must be done here, 		   before sec_parse_public_key since we'll have to apply		   serious violence to the key after this */		if (!sec_parse_x509_key(server_cert))		{			DEBUG_RDP5(("Didn't parse X509 correctly\n"));			return False;		}		return True;	/* There's some garbage here we don't care about */	}	return s_check_end(s);}/* Process crypto information blob */static voidsec_process_crypt_info(STREAM s){	uint8 *server_random, *modulus, *exponent;	uint8 client_random[SEC_RANDOM_SIZE];	uint32 rc4_key_size;	uint8 inr[SEC_MODULUS_SIZE];	if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, &modulus, &exponent))	{		DEBUG(("Failed to parse crypt info\n"));		return;	}	DEBUG(("Generating client random\n"));	/* Generate a client random, and hence determine encryption keys */	/* This is what the MS client do: */	memset(inr, 0, SEC_RANDOM_SIZE);	/*  *ARIGL!* Plaintext attack, anyone?	   I tried doing:	   generate_random(inr);	   ..but that generates connection errors now and then (yes, 	   "now and then". Something like 0 to 3 attempts needed before a 	   successful connection. Nice. Not! 	 */	generate_random(client_random);	if (NULL != server_public_key)	{			/* Which means we should use 				   RDP5-style encryption */		memcpy(inr + SEC_RANDOM_SIZE, client_random, SEC_RANDOM_SIZE);		reverse(inr + SEC_RANDOM_SIZE, SEC_RANDOM_SIZE);		RSA_public_encrypt(SEC_MODULUS_SIZE,				   inr, sec_crypted_random, server_public_key, RSA_NO_PADDING);		reverse(sec_crypted_random, SEC_MODULUS_SIZE);	}	else	{			/* RDP4-style encryption */		sec_rsa_encrypt(sec_crypted_random,				client_random, SEC_RANDOM_SIZE, modulus, exponent);	}	sec_generate_keys(client_random, server_random, rc4_key_size);}/* Process SRV_INFO, find RDP version supported by server */static voidsec_process_srv_info(STREAM s){	in_uint16_le(s, g_server_rdp_version);	DEBUG_RDP5(("Server RDP version is %d\n", g_server_rdp_version));	if (1 == g_server_rdp_version)	{		g_use_rdp5 = 0;		g_server_bpp = 8;	}}/* Process connect response data blob */voidsec_process_mcs_data(STREAM s){	uint16 tag, length;	uint8 *next_tag;	uint8 len;	in_uint8s(s, 21);	/* header (T.124 ConferenceCreateResponse) */	in_uint8(s, len);	if (len & 0x80)		in_uint8(s, len);	while (s->p < s->end)	{		in_uint16_le(s, tag);		in_uint16_le(s, length);		if (length <= 4)			return;		next_tag = s->p + length - 4;		switch (tag)		{			case SEC_TAG_SRV_INFO:				sec_process_srv_info(s);				break;			case SEC_TAG_SRV_CRYPT:				sec_process_crypt_info(s);				break;			case SEC_TAG_SRV_CHANNELS:				/* FIXME: We should parse this information and				   use it to map RDP5 channels to MCS 				   channels */				break;			default:				unimpl("response tag 0x%x\n", tag);		}		s->p = next_tag;	}}/* Receive secure transport packet */STREAMsec_recv(uint8 * rdpver){	uint32 sec_flags;	uint16 channel;	STREAM s;	while ((s = mcs_recv(&channel, rdpver)) != NULL)	{		if (rdpver != NULL)		{			if (*rdpver != 3)			{				if (*rdpver & 0x80)				{					in_uint8s(s, 8);	/* signature */					sec_decrypt(s->p, s->end - s->p);				}				return s;			}		}		if (g_encryption || !g_licence_issued)		{			in_uint32_le(s, sec_flags);			if (sec_flags & SEC_ENCRYPT)			{				in_uint8s(s, 8);	/* signature */				sec_decrypt(s->p, s->end - s->p);			}			if (sec_flags & SEC_LICENCE_NEG)			{				licence_process(s);				continue;			}		}		if (channel != MCS_GLOBAL_CHANNEL)		{			channel_process(s, channel);			*rdpver = 0xff;			return s;		}		return s;	}	return NULL;}/* Establish a secure connection */BOOLsec_connect(char *server, char *username){	struct stream mcs_data;	/* We exchange some RDP data during the MCS-Connect */	mcs_data.size = 512;	mcs_data.p = mcs_data.data = (uint8 *) xmalloc(mcs_data.size);	sec_out_mcs_data(&mcs_data);	if (!mcs_connect(server, &mcs_data, username))		return False;	/*      sec_process_mcs_data(&mcs_data); */	if (g_encryption)		sec_establish_key();	xfree(mcs_data.data);	return True;}/* Disconnect a connection */voidsec_disconnect(void){	mcs_disconnect();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -