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

📄 secure.c

📁 rdesktop is a client for Microsoft Windows NT Terminal Server, Windows 2000 Terminal Services, Wind
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	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);	modulus_len -= SEC_PADDING_SIZE;	if ((modulus_len < 64) || (modulus_len > SEC_MAX_MODULUS_SIZE))	{		error("Bad server public key size (%u bits)\n", modulus_len * 8);		return False;	}	in_uint8s(s, 8);	/* modulus_bits, unknown */	in_uint8p(s, *exponent, SEC_EXPONENT_SIZE);	in_uint8p(s, *modulus, modulus_len);	in_uint8s(s, SEC_PADDING_SIZE);	server_public_key_len = modulus_len;	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"));		ASN1_OBJECT_free(cert->cert_info->key->algor->algorithm);		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 = RSAPublicKey_dup((RSA *) epk->pkey.ptr);	EVP_PKEY_free(epk);	server_public_key_len = RSA_size(server_public_key);	if ((server_public_key_len < 64) || (server_public_key_len > SEC_MAX_MODULUS_SIZE))	{		error("Bad server public key size (%u bits)\n", server_public_key_len * 8);		return False;	}	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.		 */		X509_free(cacert);		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"));			X509_free(server_cert);			return False;		}		X509_free(server_cert);		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 = NULL, *exponent = NULL;	uint8 client_random[SEC_RANDOM_SIZE];	uint32 rc4_key_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_random(client_random);	if (NULL != server_public_key)	{			/* Which means we should use 				   RDP5-style encryption */		uint8 inr[SEC_MAX_MODULUS_SIZE];		uint32 padding_len = server_public_key_len - SEC_RANDOM_SIZE;		/* This is what the MS client do: */		memset(inr, 0, padding_len);		/*  *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! 		 */		memcpy(inr + padding_len, client_random, SEC_RANDOM_SIZE);		reverse(inr + padding_len, SEC_RANDOM_SIZE);		RSA_public_encrypt(server_public_key_len,				   inr, sec_crypted_random, server_public_key, RSA_NO_PADDING);		reverse(sec_crypted_random, server_public_key_len);		RSA_free(server_public_key);		server_public_key = NULL;	}	else	{			/* RDP4-style encryption */		sec_rsa_encrypt(sec_crypted_random,				client_random, SEC_RANDOM_SIZE, server_public_key_len, 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_depth = 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 (sec_flags & 0x0400)	/* SEC_REDIRECT_ENCRYPT */			{				uint8 swapbyte;				in_uint8s(s, 8);	/* signature */				sec_decrypt(s->p, s->end - s->p);				/* Check for a redirect packet, starts with 00 04 */				if (s->p[0] == 0 && s->p[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 foure 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 = s->p[0];					s->p[0] = s->p[2];					s->p[2] = swapbyte;					swapbyte = s->p[1];					s->p[1] = s->p[3];					s->p[3] = swapbyte;					swapbyte = s->p[2];					s->p[2] = s->p[3];					s->p[3] = swapbyte;				}#ifdef WITH_DEBUG				/* warning!  this debug statement will show passwords in the clear! */				hexdump(s->p, s->end - s->p);#endif			}		}		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;}/* Establish a secure connection */BOOLsec_reconnect(char *server){	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_reconnect(server, &mcs_data))		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();}/* reset the state of the sec layer */voidsec_reset_state(void){	g_server_rdp_version = 0;	sec_encrypt_use_count = 0;	sec_decrypt_use_count = 0;	mcs_reset_state();}

⌨️ 快捷键说明

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