Example #1
0
BOOL license_read_error_alert_packet(rdpLicense* license, STREAM* s)
{
	UINT32 dwErrorCode;
	UINT32 dwStateTransition;

	if(stream_get_left(s) < 8)
		return FALSE;
	stream_read_UINT32(s, dwErrorCode); /* dwErrorCode (4 bytes) */
	stream_read_UINT32(s, dwStateTransition); /* dwStateTransition (4 bytes) */
	if(!license_read_binary_blob(s, license->error_info)) /* bbErrorInfo */
		return FALSE;

#ifdef WITH_DEBUG_LICENSE
	printf("dwErrorCode: %s, dwStateTransition: %s\n",
			error_codes[dwErrorCode], state_transitions[dwStateTransition]);
#endif

	if (dwErrorCode == STATUS_VALID_CLIENT)
	{
		license->state = LICENSE_STATE_COMPLETED;
		return TRUE;
	}

	switch (dwStateTransition)
	{
		case ST_TOTAL_ABORT:
			license->state = LICENSE_STATE_ABORTED;
			break;

		case ST_NO_TRANSITION:
			license->state = LICENSE_STATE_COMPLETED;
			break;

		case ST_RESET_PHASE_TO_START:
			license->state = LICENSE_STATE_AWAIT;
			break;

		case ST_RESEND_LAST_MESSAGE:
			break;

		default:
			break;
	}
	return TRUE;
}
Example #2
0
tbool rdp_read_share_data_header(STREAM* s, uint16* length, uint8* type, uint32* share_id,
					uint8 *compressed_type, uint16 *compressed_len)
{
	if (stream_get_left(s) < 12)
		return false;

	/* Share Data Header */
	stream_read_uint32(s, *share_id); /* shareId (4 bytes) */
	stream_seek_uint8(s); /* pad1 (1 byte) */
	stream_seek_uint8(s); /* streamId (1 byte) */
	stream_read_uint16(s, *length); /* uncompressedLength (2 bytes) */
	stream_read_uint8(s, *type); /* pduType2, Data PDU Type (1 byte) */

	stream_read_uint8(s, *compressed_type); /* compressedType (1 byte) */
	stream_read_uint16(s, *compressed_len); /* compressedLength (2 bytes) */

	return true;
}
Example #3
0
boolean rdp_read_header(rdpRdp* rdp, STREAM* s, uint16* length, uint16* channel_id)
{
	uint16 initiator;
	enum DomainMCSPDU MCSPDU;

	MCSPDU = (rdp->settings->server_mode) ? DomainMCSPDU_SendDataRequest : DomainMCSPDU_SendDataIndication;
	mcs_read_domain_mcspdu_header(s, &MCSPDU, length);

	per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
	per_read_integer16(s, channel_id, 0); /* channelId */
	stream_seek(s, 1); /* dataPriority + Segmentation (0x70) */
	per_read_length(s, length); /* userData (OCTET_STRING) */

	if (*length > stream_get_left(s))
		return false;

	return true;
}
Example #4
0
boolean rdp_read_share_control_header(STREAM* s, uint16* length, uint16* type, uint16* channel_id)
{
	/* Share Control Header */
	stream_read_uint16(s, *length); /* totalLength */

	if (*length - 2 > stream_get_left(s))
		return false;

	stream_read_uint16(s, *type); /* pduType */
	*type &= 0x0F; /* type is in the 4 least significant bits */

	if (*length > 4)
		stream_read_uint16(s, *channel_id); /* pduSource */
	else /* Windows XP can send such short DEACTIVATE_ALL PDUs. */
		*channel_id = 0;

	return true;
}
Example #5
0
BOOL update_recv_altsec_window_order(rdpUpdate* update, wStream* s)
{
	UINT16 orderSize;
	rdpWindowUpdate* window = update->window;

	if(stream_get_left(s) < 6)
		return FALSE;
	stream_read_UINT16(s, orderSize); /* orderSize (2 bytes) */
	stream_read_UINT32(s, window->orderInfo.fieldFlags); /* FieldsPresentFlags (4 bytes) */

	if (window->orderInfo.fieldFlags & WINDOW_ORDER_TYPE_WINDOW)
		return update_recv_window_info_order(update, s, &window->orderInfo);
	else if (window->orderInfo.fieldFlags & WINDOW_ORDER_TYPE_NOTIFY)
		return update_recv_notification_icon_info_order(update, s, &window->orderInfo);
	else if (window->orderInfo.fieldFlags & WINDOW_ORDER_TYPE_DESKTOP)
		return update_recv_desktop_info_order(update, s, &window->orderInfo);
	return TRUE;
}
Example #6
0
static int drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
{
	int error;
	UINT32 Length;
	UINT32 ChannelId;

	ChannelId = drdynvc_read_variable_uint(s, cbChId);
	Length = drdynvc_read_variable_uint(s, Sp);
	DEBUG_DVC("ChannelId=%d Length=%d", ChannelId, Length);

	error = dvcman_receive_channel_data_first(drdynvc->channel_mgr, ChannelId, Length);

	if (error)
		return error;

	return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
		stream_get_tail(s), stream_get_left(s));
}
Example #7
0
static BOOL rfx_process_message_context(RFX_CONTEXT* context, STREAM* s)
{
	BYTE ctxId;
	UINT16 tileSize;
	UINT16 properties;

	if (stream_get_left(s) < 5)
	{
		DEBUG_WARN("RfxMessageContext packet too small");
		return FALSE;
	}

	stream_read_BYTE(s, ctxId); /* ctxId (1 byte), must be set to 0x00 */
	stream_read_UINT16(s, tileSize); /* tileSize (2 bytes), must be set to CT_TILE_64x64 (0x0040) */
	stream_read_UINT16(s, properties); /* properties (2 bytes) */

	DEBUG_RFX("ctxId %d tileSize %d properties 0x%X.", ctxId, tileSize, properties);

	context->properties = properties;
	context->flags = (properties & 0x0007);

	if (context->flags == CODEC_MODE)
		DEBUG_RFX("codec is in image mode.");
	else
		DEBUG_RFX("codec is in video mode.");

	switch ((properties & 0x1E00) >> 9)
	{
		case CLW_ENTROPY_RLGR1:
			context->mode = RLGR1;
			DEBUG_RFX("RLGR1.");
			break;

		case CLW_ENTROPY_RLGR3:
			context->mode = RLGR3;
			DEBUG_RFX("RLGR3.");
			break;

		default:
			DEBUG_WARN("unknown RLGR algorithm.");
			break;
	}
	return TRUE;
}
Example #8
0
boolean rdp_recv_client_synchronize_pdu(rdpRdp* rdp, STREAM* s)
{
	uint16 messageType;

	rdp->finalize_sc_pdus |= FINALIZE_SC_SYNCHRONIZE_PDU;

	if (stream_get_left(s) < 4)
		return false;

	stream_read_uint16(s, messageType); /* messageType (2 bytes) */

	if (messageType != SYNCMSGTYPE_SYNC)
		return false;

	/* targetUser (2 bytes) */
	stream_seek_uint16(s);

	return true;
}
Example #9
0
BOOL license_read_platform_challenge_packet(rdpLicense* license, STREAM* s)
{
	DEBUG_LICENSE("Receiving Platform Challenge Packet");
	if(stream_get_left(s) < 4)
		return FALSE;
	stream_seek(s, 4); /* ConnectFlags, Reserved (4 bytes) */

	/* EncryptedPlatformChallenge */
	license->encrypted_platform_challenge->type = BB_ANY_BLOB;
	license_read_binary_blob(s, license->encrypted_platform_challenge);
	license->encrypted_platform_challenge->type = BB_ENCRYPTED_DATA_BLOB;

	/* MACData (16 bytes) */
	if(!stream_skip(s, 16))
		return FALSE;

	license_decrypt_platform_challenge(license);
	return TRUE;
}
Example #10
0
static boolean rdp_recv_fastpath_pdu(rdpRdp* rdp, STREAM* s)
{
	uint16 length;

	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 (rdp->fastpath->encryptionFlags & FASTPATH_OUTPUT_ENCRYPTED)
	{
		rdp_decrypt(rdp, s, length);
	}

	return fastpath_recv_updates(rdp->fastpath, s);
}
Example #11
0
BOOL ber_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
{
	int length;

	if(!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) ||
		!ber_read_length(s, &length))
		return FALSE;

	if (length != 1 || stream_get_left(s) < 1)
		return FALSE;

	stream_read_BYTE(s, *enumerated);

	/* check that enumerated value falls within expected range */
	if (*enumerated + 1 > count)
		return FALSE;

	return TRUE;
}
Example #12
0
BOOL rdp_recv_client_synchronize_pdu(rdpRdp* rdp, STREAM* s)
{
	UINT16 messageType;

	rdp->finalize_sc_pdus |= FINALIZE_SC_SYNCHRONIZE_PDU;

	if (stream_get_left(s) < 4)
		return FALSE;

	stream_read_UINT16(s, messageType); /* messageType (2 bytes) */

	if (messageType != SYNCMSGTYPE_SYNC)
		return FALSE;

	/* targetUser (2 bytes) */
	stream_seek_UINT16(s);

	return TRUE;
}
Example #13
0
BOOL update_recv_window_info_order(rdpUpdate* update, wStream* s, WINDOW_ORDER_INFO* orderInfo)
{
	rdpContext* context = update->context;
	rdpWindowUpdate* window = update->window;

	if(stream_get_left(s) < 4)
		return FALSE;
	stream_read_UINT32(s, orderInfo->windowId); /* windowId (4 bytes) */

	if (orderInfo->fieldFlags & WINDOW_ORDER_ICON)
	{
		DEBUG_WND("Window Icon Order");
		if(!update_read_window_icon_order(s, orderInfo, &window->window_icon))
			return FALSE;
		IFCALL(window->WindowIcon, context, orderInfo, &window->window_icon);
	}
	else if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON)
	{
		DEBUG_WND("Window Cached Icon Order");
		if(!update_read_window_cached_icon_order(s, orderInfo, &window->window_cached_icon))
			return FALSE;
		IFCALL(window->WindowCachedIcon, context, orderInfo, &window->window_cached_icon);
	}
	else if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_DELETED)
	{
		DEBUG_WND("Window Deleted Order");
		update_read_window_delete_order(s, orderInfo);
		IFCALL(window->WindowDelete, context, orderInfo);
	}
	else
	{
		DEBUG_WND("Window State Order");
		if(!update_read_window_state_order(s, orderInfo, &window->window_state))
			return FALSE;

		if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW)
			IFCALL(window->WindowCreate, context, orderInfo, &window->window_state);
		else
			IFCALL(window->WindowUpdate, context, orderInfo, &window->window_state);
	}
	return TRUE;
}
Example #14
0
void cliprdr_process_long_format_names(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags)
{
	int allocated_formats = 8;
	BYTE* end_mark;
	CLIPRDR_FORMAT_NAME* format_name;
	
	stream_get_mark(s, end_mark);
	end_mark += length;
		
	cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) malloc(sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats);
	cliprdr->num_format_names = 0;

	while (stream_get_left(s) >= 6)
	{
		BYTE* p;
		int name_len;
		
		if (cliprdr->num_format_names >= allocated_formats)
		{
			allocated_formats *= 2;
			cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) realloc(cliprdr->format_names,
					sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats);
		}
		
		format_name = &cliprdr->format_names[cliprdr->num_format_names++];
		stream_read_UINT32(s, format_name->id);
		
		format_name->name = NULL;
		format_name->length = 0;

		for (p = stream_get_tail(s), name_len = 0; p + 1 < end_mark; p += 2, name_len += 2)
		{
			if (*((unsigned short*) p) == 0)
				break;
		}
		
		format_name->length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) stream_get_tail(s), name_len / 2, &format_name->name, 0, NULL, NULL);

		stream_seek(s, name_len + 2);
	}
}
Example #15
0
void cliprdr_process_long_format_names(cliprdrPlugin* cliprdr, STREAM* s, uint32 length, uint16 flags)
{
	int allocated_formats = 8;
	uint8* end_mark;
	CLIPRDR_FORMAT_NAME* format_name;
	
	stream_get_mark(s, end_mark);
	end_mark += length;
		
	cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) xmalloc(sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats);
	cliprdr->num_format_names = 0;

	while (stream_get_left(s) >= 6)
	{
		uint8* p;
		int name_len;
		
		if (cliprdr->num_format_names >= allocated_formats)
		{
			allocated_formats *= 2;
			cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) xrealloc(cliprdr->format_names,
					sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats);
		}
		
		format_name = &cliprdr->format_names[cliprdr->num_format_names++];
		stream_read_uint32(s, format_name->id);
		
		format_name->name = NULL;
		format_name->length = 0;

		for (p = stream_get_tail(s), name_len = 0; p + 1 < end_mark; p += 2, name_len += 2)
		{
			if (*((unsigned short*) p) == 0)
				break;
		}
		
		format_name->name = freerdp_uniconv_in(cliprdr->uniconv, stream_get_tail(s), name_len);
		format_name->length = strlen(format_name->name);
		stream_seek(s, name_len + 2);
	}
}
Example #16
0
static tbool rdp_recv_fastpath_pdu(rdpRdp* rdp, STREAM* s)
{
	uint16 length;
	rdpFastPath* fastpath;

	fastpath = rdp->fastpath;
	length = fastpath_read_header_rdp(fastpath, s);

	if (length == 0 || length > stream_get_left(s))
	{
		printf("incorrect FastPath PDU header length %d\n", length);
		return false;
	}

	if (fastpath->encryptionFlags & FASTPATH_OUTPUT_ENCRYPTED)
	{
		rdp_decrypt(rdp, s, length, (fastpath->encryptionFlags & FASTPATH_OUTPUT_SECURE_CHECKSUM) ? SEC_SECURE_CHECKSUM : 0);
	}

	return fastpath_recv_updates(rdp->fastpath, s);
}
Example #17
0
BOOL license_read_scope_list(STREAM* s, SCOPE_LIST* scopeList)
{
	UINT32 i;
	UINT32 scopeCount;

	if(stream_get_left(s) < 4)
		return FALSE;
	stream_read_UINT32(s, scopeCount); /* ScopeCount (4 bytes) */

	scopeList->count = scopeCount;
	scopeList->array = (LICENSE_BLOB*) malloc(sizeof(LICENSE_BLOB) * scopeCount);

	/* ScopeArray */
	for (i = 0; i < scopeCount; i++)
	{
		scopeList->array[i].type = BB_SCOPE_BLOB;
		if(!license_read_binary_blob(s, &scopeList->array[i]))
			return FALSE;
	}
	return TRUE;
}
Example #18
0
static BOOL rfx_process_message_tile(RFX_CONTEXT* context, RFX_TILE* tile, STREAM* s)
{
	BYTE quantIdxY;
	BYTE quantIdxCb;
	BYTE quantIdxCr;
	UINT16 xIdx, yIdx;
	UINT16 YLen, CbLen, CrLen;

	if (stream_get_left(s) < 13)
	{
		DEBUG_WARN("RfxMessageTile packet too small");
		return FALSE;
	}

	/* RFX_TILE */
	stream_read_BYTE(s, quantIdxY); /* quantIdxY (1 byte) */
	stream_read_BYTE(s, quantIdxCb); /* quantIdxCb (1 byte) */
	stream_read_BYTE(s, quantIdxCr); /* quantIdxCr (1 byte) */
	stream_read_UINT16(s, xIdx); /* xIdx (2 bytes) */
	stream_read_UINT16(s, yIdx); /* yIdx (2 bytes) */
	stream_read_UINT16(s, YLen); /* YLen (2 bytes) */
	stream_read_UINT16(s, CbLen); /* CbLen (2 bytes) */
	stream_read_UINT16(s, CrLen); /* CrLen (2 bytes) */

	DEBUG_RFX("quantIdxY:%d quantIdxCb:%d quantIdxCr:%d xIdx:%d yIdx:%d YLen:%d CbLen:%d CrLen:%d",
		quantIdxY, quantIdxCb, quantIdxCr, xIdx, yIdx, YLen, CbLen, CrLen);

	tile->x = xIdx * 64;
	tile->y = yIdx * 64;

	return rfx_decode_rgb(context, s,
		YLen, context->quants + (quantIdxY * 10),
		CbLen, context->quants + (quantIdxCb * 10),
		CrLen, context->quants + (quantIdxCr * 10),
		tile->data, 64 * 4);
}
Example #19
0
void update_read_pointer_color(STREAM* s, POINTER_COLOR_UPDATE* pointer_color)
{
	stream_read_UINT16(s, pointer_color->cacheIndex); /* cacheIndex (2 bytes) */
	stream_read_UINT16(s, pointer_color->xPos); /* xPos (2 bytes) */
	stream_read_UINT16(s, pointer_color->yPos); /* yPos (2 bytes) */
	stream_read_UINT16(s, pointer_color->width); /* width (2 bytes) */
	stream_read_UINT16(s, pointer_color->height); /* height (2 bytes) */
	stream_read_UINT16(s, pointer_color->lengthAndMask); /* lengthAndMask (2 bytes) */
	stream_read_UINT16(s, pointer_color->lengthXorMask); /* lengthXorMask (2 bytes) */

	/**
	 * There does not seem to be any documentation on why
	 * xPos / yPos can be larger than width / height
	 * so it is missing in documentation or a bug in implementation
	 * 2.2.9.1.1.4.4 Color Pointer Update (TS_COLORPOINTERATTRIBUTE)
	 */
	if (pointer_color->xPos >= pointer_color->width)
		pointer_color->xPos = 0;
	if (pointer_color->yPos >= pointer_color->height)
		pointer_color->yPos = 0;

	if (pointer_color->lengthXorMask > 0)
	{
		pointer_color->xorMaskData = (BYTE*) malloc(pointer_color->lengthXorMask);
		stream_read(s, pointer_color->xorMaskData, pointer_color->lengthXorMask);
	}

	if (pointer_color->lengthAndMask > 0)
	{
		pointer_color->andMaskData = (BYTE*) malloc(pointer_color->lengthAndMask);
		stream_read(s, pointer_color->andMaskData, pointer_color->lengthAndMask);
	}

	if (stream_get_left(s) > 0)
		stream_seek_BYTE(s); /* pad (1 byte) */
}
Example #20
0
int rdp_recv_data_pdu(rdpRdp* rdp, STREAM* s)
{
	BYTE type;
	UINT16 length;
	UINT32 share_id;
	BYTE compressed_type;
	UINT16 compressed_len;
	UINT32 roff;
	UINT32 rlen;
	STREAM* comp_stream;

	if (!rdp_read_share_data_header(s, &length, &type, &share_id, &compressed_type, &compressed_len))
		return -1;

	comp_stream = s;

	if (compressed_type & PACKET_COMPRESSED)
	{
		if (stream_get_left(s) < compressed_len - 18)
		{
			printf("decompress_rdp: not enough bytes for compressed_len=%d\n", compressed_len);
			return -1;	
		}
		if (decompress_rdp(rdp->mppc_dec, s->p, compressed_len - 18, compressed_type, &roff, &rlen))
		{
			comp_stream = stream_new(0);
			comp_stream->data = rdp->mppc_dec->history_buf + roff;
			comp_stream->p = comp_stream->data;
			comp_stream->size = rlen;
		}
		else
		{
			printf("decompress_rdp() failed\n");
			return -1;
		}
		stream_seek(s, compressed_len - 18);
	}

#ifdef WITH_DEBUG_RDP
	/* if (type != DATA_PDU_TYPE_UPDATE) */
		DEBUG_RDP("recv %s Data PDU (0x%02X), length:%d",
				type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length);
#endif

	switch (type)
	{
		case DATA_PDU_TYPE_UPDATE:
			if (!update_recv(rdp->update, comp_stream))
				return -1;
			break;

		case DATA_PDU_TYPE_CONTROL:
			if (!rdp_recv_server_control_pdu(rdp, comp_stream))
				return -1;
			break;

		case DATA_PDU_TYPE_POINTER:
			if (!update_recv_pointer(rdp->update, comp_stream))
				return -1;
			break;

		case DATA_PDU_TYPE_INPUT:
			break;

		case DATA_PDU_TYPE_SYNCHRONIZE:
			if (!rdp_recv_synchronize_pdu(rdp, comp_stream))
				return -1;
			break;

		case DATA_PDU_TYPE_REFRESH_RECT:
			break;

		case DATA_PDU_TYPE_PLAY_SOUND:
			if (!update_recv_play_sound(rdp->update, comp_stream))
				return -1;
			break;

		case DATA_PDU_TYPE_SUPPRESS_OUTPUT:
			break;

		case DATA_PDU_TYPE_SHUTDOWN_REQUEST:
			break;

		case DATA_PDU_TYPE_SHUTDOWN_DENIED:
			break;

		case DATA_PDU_TYPE_SAVE_SESSION_INFO:
			if(!rdp_recv_save_session_info(rdp, comp_stream))
				return -1;
			break;

		case DATA_PDU_TYPE_FONT_LIST:
			break;

		case DATA_PDU_TYPE_FONT_MAP:
			if(!rdp_recv_font_map_pdu(rdp, comp_stream))
				return -1;
			break;

		case DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS:
			break;

		case DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST:
			break;

		case DATA_PDU_TYPE_BITMAP_CACHE_ERROR:
			break;

		case DATA_PDU_TYPE_SET_KEYBOARD_IME_STATUS:
			break;

		case DATA_PDU_TYPE_OFFSCREEN_CACHE_ERROR:
			break;

		case DATA_PDU_TYPE_SET_ERROR_INFO:
			if (!rdp_recv_set_error_info_data_pdu(rdp, comp_stream))
				return -1;
			break;

		case DATA_PDU_TYPE_DRAW_NINEGRID_ERROR:
			break;

		case DATA_PDU_TYPE_DRAW_GDIPLUS_ERROR:
			break;

		case DATA_PDU_TYPE_ARC_STATUS:
			break;

		case DATA_PDU_TYPE_STATUS_INFO:
			break;

		case DATA_PDU_TYPE_MONITOR_LAYOUT:
			break;

		default:
			break;
	}

	if (comp_stream != s)
	{
		stream_detach(comp_stream);
		stream_free(comp_stream);
	}

	return 0;
}
Example #21
0
BOOL rdp_decrypt(rdpRdp* rdp, STREAM* s, int length, UINT16 securityFlags)
{
	BYTE cmac[8];
	BYTE wmac[8];

	if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
	{
		UINT16 len;
		BYTE version, pad;
		BYTE* sig;

		if (stream_get_left(s) < 12)
			return FALSE;

		stream_read_UINT16(s, len); /* 0x10 */
		stream_read_BYTE(s, version); /* 0x1 */
		stream_read_BYTE(s, pad);

		sig = s->p;
		stream_seek(s, 8);	/* signature */

		length -= 12;

		if (!security_fips_decrypt(s->p, length, rdp))
		{
			printf("FATAL: cannot decrypt\n");
			return FALSE; /* TODO */
		}

		if (!security_fips_check_signature(s->p, length - pad, sig, rdp))
		{
			printf("FATAL: invalid packet signature\n");
			return FALSE; /* TODO */
		}

		/* is this what needs adjusting? */
		s->size -= pad;
		return TRUE;
	}

	if (stream_get_left(s) < 8)
		return FALSE;

	stream_read(s, wmac, sizeof(wmac));
	length -= sizeof(wmac);
	security_decrypt(s->p, length, rdp);

	if (securityFlags & SEC_SECURE_CHECKSUM)
		security_salted_mac_signature(rdp, s->p, length, FALSE, cmac);
	else
		security_mac_signature(rdp, s->p, length, cmac);

	if (memcmp(wmac, cmac, sizeof(wmac)) != 0)
	{
		printf("WARNING: invalid packet signature\n");
		/*
		 * Because Standard RDP Security is totally broken,
		 * and cannot protect against MITM, don't treat signature
		 * verification failure as critical. This at least enables
		 * us to work with broken RDP clients and servers that
		 * generate invalid signatures.
		 */
		//return FALSE;
	}

	return TRUE;
}
Example #22
0
BOOL WTSVirtualChannelWrite(
	/* __in */  void* hChannelHandle,
	/* __in */  BYTE* Buffer,
	/* __in */  UINT32 Length,
	/* __out */ UINT32* pBytesWritten)
{
	rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
	wts_data_item* item;
	wStream* s;
	int cbLen;
	int cbChId;
	int first;
	UINT32 written;

	if (channel == NULL)
		return FALSE;

	if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
	{
		item = (wts_data_item*) malloc(sizeof(wts_data_item));
		ZeroMemory(item, sizeof(wts_data_item));

		item->buffer = malloc(Length);
		item->length = Length;
		CopyMemory(item->buffer, Buffer, Length);

		wts_queue_send_item(channel, item);
	}
	else if (channel->vcm->drdynvc_channel == NULL || channel->vcm->drdynvc_state != DRDYNVC_STATE_READY)
	{
		DEBUG_DVC("drdynvc not ready");
		return FALSE;
	}
	else
	{
		s = stream_new(0);
		first = TRUE;

		while (Length > 0)
		{
			item = (wts_data_item*) malloc(sizeof(wts_data_item));
			ZeroMemory(item, sizeof(wts_data_item));

			item->buffer = malloc(channel->client->settings->VirtualChannelChunkSize);
			stream_attach(s, item->buffer, channel->client->settings->VirtualChannelChunkSize);

			stream_seek_BYTE(s);
			cbChId = wts_write_variable_uint(s, channel->channel_id);

			if (first && (Length > (UINT32) stream_get_left(s)))
			{
				cbLen = wts_write_variable_uint(s, Length);
				item->buffer[0] = (DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId;
			}
			else
			{
				item->buffer[0] = (DATA_PDU << 4) | cbChId;
			}

			first = FALSE;
			written = stream_get_left(s);

			if (written > Length)
				written = Length;

			stream_write(s, Buffer, written);
			item->length = stream_get_length(s);
			stream_detach(s);
			Length -= written;
			Buffer += written;

			wts_queue_send_item(channel->vcm->drdynvc_channel, item);
		}

		stream_free(s);
	}

	if (pBytesWritten != NULL)
		*pBytesWritten = Length;
	return TRUE;
}
Example #23
0
static tbool rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
{
	uint16 length;
	uint16 pduType;
	uint16 pduLength;
	uint16 pduSource;
	uint16 channelId;
	uint16 securityFlags;
	uint8* nextp;

	if (!rdp_read_header(rdp, s, &length, &channelId))
	{
		printf("Incorrect RDP header.\n");
		return false;
	}

	if (rdp->settings->encryption)
	{
		rdp_read_security_header(s, &securityFlags);
		if (securityFlags & (SEC_ENCRYPT|SEC_REDIRECTION_PKT))
		{
			if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
			{
				printf("rdp_decrypt failed\n");
				return false;
			}
		}
		if (securityFlags & SEC_REDIRECTION_PKT)
		{
			/*
			 * [MS-RDPBCGR] 2.2.13.2.1
			 *  - no share control header, nor the 2 byte pad
			 */
			s->p -= 2;
			rdp_recv_enhanced_security_redirection_packet(rdp, s);
			return true;
		}
	}

	if (channelId != MCS_GLOBAL_CHANNEL_ID)
	{
		freerdp_channel_process(rdp->instance, s, channelId);
	}
	else
	{
		while (stream_get_left(s) > 3)
		{
			stream_get_mark(s, nextp);
			rdp_read_share_control_header(s, &pduLength, &pduType, &pduSource);
			nextp += pduLength;

			rdp->settings->pdu_source = pduSource;

			switch (pduType)
			{
				case PDU_TYPE_DATA:
					if (!rdp_recv_data_pdu(rdp, s))
					{
						printf("rdp_recv_data_pdu failed\n");
						return false;
					}
					break;

				case PDU_TYPE_DEACTIVATE_ALL:
					if (!rdp_recv_deactivate_all(rdp, s))
						return false;
					break;

				case PDU_TYPE_SERVER_REDIRECTION:
					rdp_recv_enhanced_security_redirection_packet(rdp, s);
					break;

				default:
					printf("incorrect PDU type: 0x%04X\n", pduType);
					break;
			}
			stream_set_mark(s, nextp);
		}
	}

	return true;
}
Example #24
0
boolean rdp_read_info_packet(STREAM* s, rdpSettings* settings)
{
	uint32 flags;
	uint16 cbDomain;
	uint16 cbUserName;
	uint16 cbPassword;
	uint16 cbAlternateShell;
	uint16 cbWorkingDir;

	stream_seek_uint32(s); /* CodePage */
	stream_read_uint32(s, flags); /* flags */

	settings->autologon = ((flags & INFO_AUTOLOGON) ? true : false);
	settings->remote_app = ((flags & INFO_RAIL) ? true : false);
	settings->console_audio = ((flags & INFO_REMOTECONSOLEAUDIO) ? true : false);
	settings->compression = ((flags & INFO_COMPRESSION) ? true : false);

	stream_read_uint16(s, cbDomain); /* cbDomain */
	stream_read_uint16(s, cbUserName); /* cbUserName */
	stream_read_uint16(s, cbPassword); /* cbPassword */
	stream_read_uint16(s, cbAlternateShell); /* cbAlternateShell */
	stream_read_uint16(s, cbWorkingDir); /* cbWorkingDir */

	if (stream_get_left(s) < cbDomain + 2)
		return false;
	if (cbDomain > 0)
	{
		settings->domain = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbDomain);
		stream_seek(s, cbDomain);
	}
	stream_seek(s, 2);

	if (stream_get_left(s) < cbUserName + 2)
		return false;
	if (cbUserName > 0)
	{
		settings->username = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbUserName);
		stream_seek(s, cbUserName);
	}
	stream_seek(s, 2);

	if (stream_get_left(s) < cbPassword + 2)
		return false;
	if (cbPassword > 0)
	{
		settings->password = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbPassword);
		stream_seek(s, cbPassword);
	}
	stream_seek(s, 2);

	if (stream_get_left(s) < cbAlternateShell + 2)
		return false;
	if (cbAlternateShell > 0)
	{
		settings->shell = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbAlternateShell);
		stream_seek(s, cbAlternateShell);
	}
	stream_seek(s, 2);

	if (stream_get_left(s) < cbWorkingDir + 2)
		return false;
	if (cbWorkingDir > 0)
	{
		settings->directory = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbWorkingDir);
		stream_seek(s, cbWorkingDir);
	}
	stream_seek(s, 2);

	if (settings->rdp_version >= 5)
		return rdp_read_extended_info_packet(s, settings); /* extraInfo */

	return true;
}
Example #25
0
static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* s)
{
	int i;
	int pos;
	BYTE quant;
	UINT32* quants;
	UINT16 subtype;
	UINT32 blockLen;
	UINT32 blockType;
	UINT32 tilesDataSize;
	PTP_WORK* work_objects = NULL;
	RFX_TILE_WORK_PARAM* params = NULL;

	if (stream_get_left(s) < 14)
	{
		DEBUG_WARN("RfxMessageTileSet packet too small");
		return FALSE;
	}

	stream_read_UINT16(s, subtype); /* subtype (2 bytes) must be set to CBT_TILESET (0xCAC2) */

	if (subtype != CBT_TILESET)
	{
		DEBUG_WARN("invalid subtype, expected CBT_TILESET.");
		return FALSE;
	}

	stream_seek_UINT16(s); /* idx (2 bytes), must be set to 0x0000 */
	stream_seek_UINT16(s); /* properties (2 bytes) */

	stream_read_BYTE(s, context->num_quants); /* numQuant (1 byte) */
	stream_seek_BYTE(s); /* tileSize (1 byte), must be set to 0x40 */

	if (context->num_quants < 1)
	{
		DEBUG_WARN("no quantization value.");
		return TRUE;
	}

	stream_read_UINT16(s, message->num_tiles); /* numTiles (2 bytes) */

	if (message->num_tiles < 1)
	{
		DEBUG_WARN("no tiles.");
		return TRUE;
	}

	stream_read_UINT32(s, tilesDataSize); /* tilesDataSize (4 bytes) */

	if (context->quants != NULL)
		context->quants = (UINT32*) realloc((void*) context->quants, context->num_quants * 10 * sizeof(UINT32));
	else
		context->quants = (UINT32*) malloc(context->num_quants * 10 * sizeof(UINT32));
	quants = context->quants;

	/* quantVals */
	if (stream_get_left(s) < context->num_quants * 5)
	{
		DEBUG_WARN("RfxMessageTileSet packet too small for num_quants=%d", context->num_quants);
		return FALSE;
	}

	for (i = 0; i < context->num_quants; i++)
	{
		/* RFX_CODEC_QUANT */
		stream_read_BYTE(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		stream_read_BYTE(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		stream_read_BYTE(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		stream_read_BYTE(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		stream_read_BYTE(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);

		DEBUG_RFX("quant %d (%d %d %d %d %d %d %d %d %d %d).",
			i, context->quants[i * 10], context->quants[i * 10 + 1],
			context->quants[i * 10 + 2], context->quants[i * 10 + 3],
			context->quants[i * 10 + 4], context->quants[i * 10 + 5],
			context->quants[i * 10 + 6], context->quants[i * 10 + 7],
			context->quants[i * 10 + 8], context->quants[i * 10 + 9]);
	}

	message->tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE*) * message->num_tiles);
	ZeroMemory(message->tiles, sizeof(RFX_TILE*) * message->num_tiles);

	if (context->priv->UseThreads)
	{
		work_objects = (PTP_WORK*) malloc(sizeof(PTP_WORK) * message->num_tiles);
		params = (RFX_TILE_WORK_PARAM*) malloc(sizeof(RFX_TILE_WORK_PARAM) * message->num_tiles);
	}

	/* tiles */
	for (i = 0; i < message->num_tiles; i++)
	{
		/* RFX_TILE */
		if (stream_get_left(s) < 6)
		{
			DEBUG_WARN("RfxMessageTileSet packet too small to read tile %d/%d", i, message->num_tiles);
			return FALSE;
		}

		stream_read_UINT16(s, blockType); /* blockType (2 bytes), must be set to CBT_TILE (0xCAC3) */
		stream_read_UINT32(s, blockLen); /* blockLen (4 bytes) */

		if (stream_get_left(s) < blockLen - 6)
		{
			DEBUG_WARN("RfxMessageTileSet not enough bytes to read tile %d/%d with blocklen=%d", i, message->num_tiles, blockLen);
			return FALSE;
		}

		pos = stream_get_pos(s) - 6 + blockLen;

		if (blockType != CBT_TILE)
		{
			DEBUG_WARN("unknown block type 0x%X, expected CBT_TILE (0xCAC3).", blockType);
			break;
		}

		message->tiles[i] = rfx_tile_pool_take(context);

		if (context->priv->UseThreads)
		{
			params[i].context = context;
			params[i].tile = message->tiles[i];
			CopyMemory(&(params[i].s), s, sizeof(STREAM));

			work_objects[i] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_process_message_tile_work_callback,
					(void*) &params[i], &context->priv->ThreadPoolEnv);

			SubmitThreadpoolWork(work_objects[i]);
		}
		else
		{
			rfx_process_message_tile(context, message->tiles[i], s);
		}

		stream_set_pos(s, pos);
	}

	if (context->priv->UseThreads)
	{
		for (i = 0; i < message->num_tiles; i++)
			WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE);

		free(work_objects);
		free(params);
	}
	return TRUE;
}
Example #26
0
static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s)
{
	BYTE type;
	UINT16 length;
	UINT32 share_id;
	BYTE compressed_type;
	UINT16 compressed_len;

	if (!rdp_read_share_data_header(s, &length, &type, &share_id, &compressed_type, &compressed_len))
		return FALSE;

	switch (type)
	{
		case DATA_PDU_TYPE_SYNCHRONIZE:
			if (!rdp_recv_client_synchronize_pdu(client->context->rdp, s))
				return FALSE;
			break;

		case DATA_PDU_TYPE_CONTROL:
			if (!rdp_server_accept_client_control_pdu(client->context->rdp, s))
				return FALSE;
			break;

		case DATA_PDU_TYPE_INPUT:
			if (!input_recv(client->context->rdp->input, s))
				return FALSE;
			break;

		case DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST:
			/* TODO: notify server bitmap cache data */
			break;

		case DATA_PDU_TYPE_FONT_LIST:

			if (!rdp_server_accept_client_font_list_pdu(client->context->rdp, s))
				return FALSE;

			if (!client->connected)
			{
				/**
				 * PostConnect should only be called once and should not be called
				 * after a reactivation sequence.
				 */

				IFCALLRET(client->PostConnect, client->connected, client);

				if (!client->connected)
					return FALSE;
			}

			if (!client->activated)
			{
				/* Activate will be called everytime after the client is activated/reactivated. */
			
				IFCALLRET(client->Activate, client->activated, client);

				if (!client->activated)
					return FALSE;
			}

			break;

		case DATA_PDU_TYPE_SHUTDOWN_REQUEST:
			mcs_send_disconnect_provider_ultimatum(client->context->rdp->mcs);
			return FALSE;

		case DATA_PDU_TYPE_FRAME_ACKNOWLEDGE:
			if(stream_get_left(s) < 4)
				return FALSE;
			stream_read_UINT32(s, client->ack_frame_id);
			break;

		case DATA_PDU_TYPE_REFRESH_RECT:
			if (!update_read_refresh_rect(client->update, s))
				return FALSE;
			break;

		case DATA_PDU_TYPE_SUPPRESS_OUTPUT:
			if (!update_read_suppress_output(client->update, s))
				return FALSE;
			break;

		default:
			fprintf(stderr, "Data PDU type %d\n", type);
			break;
	}

	return TRUE;
}
Example #27
0
boolean WTSVirtualChannelWrite(
	/* __in */  void* hChannelHandle,
	/* __in */  uint8* Buffer,
	/* __in */  uint32 Length,
	/* __out */ uint32* pBytesWritten)
{
	rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
	wts_data_item* item;
	STREAM* s;
	int cbLen;
	int cbChId;
	int first;
	uint32 written;

	if (channel == NULL)
		return false;

	if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
	{
		item = xnew(wts_data_item);
		item->buffer = xmalloc(Length);
		item->length = Length;
		memcpy(item->buffer, Buffer, Length);

		wts_queue_send_item(channel, item);
	}
	else if (channel->vcm->drdynvc_channel == NULL || channel->vcm->drdynvc_state != DRDYNVC_STATE_READY)
	{
		DEBUG_DVC("drdynvc not ready");
		return false;
	}
	else
	{
		s = stream_new(0);
		first = true;

		while (Length > 0)
		{
			item = xnew(wts_data_item);
			item->buffer = xmalloc(channel->client->settings->vc_chunk_size);
			stream_attach(s, item->buffer, channel->client->settings->vc_chunk_size);

			stream_seek_uint8(s);
			cbChId = wts_write_variable_uint(s, channel->channel_id);
			if (first && (Length > (uint32) stream_get_left(s)))
			{
				cbLen = wts_write_variable_uint(s, Length);
				item->buffer[0] = (DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId;
			}
			else
			{
				item->buffer[0] = (DATA_PDU << 4) | cbChId;
			}
			first = false;
			written = stream_get_left(s);
			if (written > Length)
				written = Length;
			stream_write(s, Buffer, written);
			item->length = stream_get_length(s);
			stream_detach(s);
			Length -= written;
			Buffer += written;

			wts_queue_send_item(channel->vcm->drdynvc_channel, item);
		}

		stream_free(s);
	}

	if (pBytesWritten != NULL)
		*pBytesWritten = Length;
	return true;
}
Example #28
0
BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate, wStream* s)
{
	UINT32 dwSigAlgId;
	UINT32 dwKeyAlgId;
	UINT32 wPublicKeyBlobType;
	UINT32 wPublicKeyBlobLen;
	UINT32 wSignatureBlobType;
	UINT32 wSignatureBlobLen;
	BYTE* sigdata;
	int sigdatalen;

	if(stream_get_left(s) < 12)
		return FALSE;

	/* -4, because we need to include dwVersion */
	sigdata = stream_get_tail(s) - 4;
	stream_read_UINT32(s, dwSigAlgId);
	stream_read_UINT32(s, dwKeyAlgId);

	if (!(dwSigAlgId == SIGNATURE_ALG_RSA && dwKeyAlgId == KEY_EXCHANGE_ALG_RSA))
	{
		fprintf(stderr, "certificate_read_server_proprietary_certificate: parse error 1\n");
		return FALSE;
	}

	stream_read_UINT16(s, wPublicKeyBlobType);

	if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
	{
		fprintf(stderr, "certificate_read_server_proprietary_certificate: parse error 2\n");
		return FALSE;
	}

	stream_read_UINT16(s, wPublicKeyBlobLen);
	if(stream_get_left(s) < wPublicKeyBlobLen)
		return FALSE;

	if (!certificate_process_server_public_key(certificate, s, wPublicKeyBlobLen))
	{
		fprintf(stderr, "certificate_read_server_proprietary_certificate: parse error 3\n");
		return FALSE;
	}

	if(stream_get_left(s) < 4)
		return FALSE;

	sigdatalen = stream_get_tail(s) - sigdata;
	stream_read_UINT16(s, wSignatureBlobType);

	if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB)
	{
		fprintf(stderr, "certificate_read_server_proprietary_certificate: parse error 4\n");
		return FALSE;
	}

	stream_read_UINT16(s, wSignatureBlobLen);
	if(stream_get_left(s) < wSignatureBlobLen)
		return FALSE;

	if (wSignatureBlobLen != 72)
	{
		fprintf(stderr, "certificate_process_server_public_signature: invalid signature length (got %d, expected %d)\n", wSignatureBlobLen, 64);
		return FALSE;
	}

	if (!certificate_process_server_public_signature(certificate, sigdata, sigdatalen, s, wSignatureBlobLen))
	{
		fprintf(stderr, "certificate_read_server_proprietary_certificate: parse error 5\n");
		return FALSE;
	}

	return TRUE;
}
Example #29
0
RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, BYTE* data, UINT32 length)
{
	int pos;
	STREAM* s;
	UINT32 blockLen;
	UINT32 blockType;
	RFX_MESSAGE* message;

	message = (RFX_MESSAGE*) malloc(sizeof(RFX_MESSAGE));
	ZeroMemory(message, sizeof(RFX_MESSAGE));

	s = stream_new(0);
	stream_attach(s, data, length);

	while (stream_get_left(s) > 6)
	{
		/* RFX_BLOCKT */
		stream_read_UINT16(s, blockType); /* blockType (2 bytes) */
		stream_read_UINT32(s, blockLen); /* blockLen (4 bytes) */

		DEBUG_RFX("blockType 0x%X blockLen %d", blockType, blockLen);

		if (blockLen == 0)
		{
			DEBUG_WARN("zero blockLen");
			break;
		}

		if (stream_get_left(s) < blockLen - 6)
		{
			DEBUG_WARN("rfx_process_message: packet too small for blocklen=%d", blockLen);
			break;
		}


		pos = stream_get_pos(s) - 6 + blockLen;

		if (blockType >= WBT_CONTEXT && blockType <= WBT_EXTENSION)
		{
			/* RFX_CODEC_CHANNELT */
			/* codecId (1 byte) must be set to 0x01 */
			/* channelId (1 byte) must be set to 0x00 */
			if (!stream_skip(s, 2))
			{
				DEBUG_WARN("rfx_process_message: unable to skip RFX_CODEC_CHANNELT");
				break;
			}
		}

		switch (blockType)
		{
			case WBT_SYNC:
				rfx_process_message_sync(context, s);
				break;

			case WBT_CODEC_VERSIONS:
				rfx_process_message_codec_versions(context, s);
				break;

			case WBT_CHANNELS:
				rfx_process_message_channels(context, s);
				break;

			case WBT_CONTEXT:
				rfx_process_message_context(context, s);
				break;

			case WBT_FRAME_BEGIN:
				rfx_process_message_frame_begin(context, message, s);
				break;

			case WBT_FRAME_END:
				rfx_process_message_frame_end(context, message, s);
				break;

			case WBT_REGION:
				rfx_process_message_region(context, message, s);
				break;

			case WBT_EXTENSION:
				rfx_process_message_tileset(context, message, s);
				break;

			default:
				DEBUG_WARN("unknown blockType 0x%X", blockType);
				break;
		}

		stream_set_pos(s, pos);
	}

	stream_detach(s);
	stream_free(s);

	return message;
}
Example #30
0
BOOL certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info)
{
	wStream* s;
	int length;
	BYTE padding;
	UINT32 version;
	int modulus_length;
	int exponent_length;
	int error = 0;

	s = stream_new(0);
	stream_attach(s, cert->data, cert->length);
	info->Modulus = 0;

	if(!ber_read_sequence_tag(s, &length)) /* Certificate (SEQUENCE) */
		goto error1;
	error++;

	if(!ber_read_sequence_tag(s, &length)) /* TBSCertificate (SEQUENCE) */
		goto error1;
	error++;

	if(!ber_read_contextual_tag(s, 0, &length, TRUE))	/* Explicit Contextual Tag [0] */
		goto error1;
	error++;
	if(!ber_read_integer(s, &version)) /* version (INTEGER) */
		goto error1;
	error++;
	version++;

	/* serialNumber */
	if(!ber_read_integer(s, NULL)) /* CertificateSerialNumber (INTEGER) */
		goto error1;
	error++;

	/* signature */
	if(!ber_read_sequence_tag(s, &length) || !stream_skip(s, length)) /* AlgorithmIdentifier (SEQUENCE) */
		goto error1;
	error++;

	/* issuer */
	if(!ber_read_sequence_tag(s, &length) || !stream_skip(s, length)) /* Name (SEQUENCE) */
		goto error1;
	error++;

	/* validity */
	if(!ber_read_sequence_tag(s, &length) || !stream_skip(s, length)) /* Validity (SEQUENCE) */
		goto error1;
	error++;

	/* subject */
	if(!ber_read_sequence_tag(s, &length) || !stream_skip(s, length)) /* Name (SEQUENCE) */
		goto error1;
	error++;

	/* subjectPublicKeyInfo */
	if(!ber_read_sequence_tag(s, &length)) /* SubjectPublicKeyInfo (SEQUENCE) */
		goto error1;
	error++;

	/* subjectPublicKeyInfo::AlgorithmIdentifier */
	if(!ber_read_sequence_tag(s, &length) || !stream_skip(s, length)) /* AlgorithmIdentifier (SEQUENCE) */
		goto error1;
	error++;

	/* subjectPublicKeyInfo::subjectPublicKey */
	if(!ber_read_bit_string(s, &length, &padding)) /* BIT_STRING */
		goto error1;
	error++;

	/* RSAPublicKey (SEQUENCE) */
	if(!ber_read_sequence_tag(s, &length)) /* SEQUENCE */
		goto error1;
	error++;

	if(!ber_read_integer_length(s, &modulus_length)) /* modulus (INTEGER) */
		goto error1;
	error++;

	/* skip zero padding, if any */
	do
	{
		if(stream_get_left(s) < 1)
			goto error1;
		stream_peek_BYTE(s, padding);

		if (padding == 0)
		{
			if(!stream_skip(s, 1))
				goto error1;
			modulus_length--;
		}
	}
	while (padding == 0);
	error++;

	if(stream_get_left(s) < modulus_length)
		goto error1;
	info->ModulusLength = modulus_length;
	info->Modulus = (BYTE*) malloc(info->ModulusLength);
	stream_read(s, info->Modulus, info->ModulusLength);
	error++;

	if(!ber_read_integer_length(s, &exponent_length)) /* publicExponent (INTEGER) */
		goto error2;
	error++;
	if(stream_get_left(s) < exponent_length || exponent_length > 4)
		goto error2;
	stream_read(s, &info->exponent[4 - exponent_length], exponent_length);
	crypto_reverse(info->Modulus, info->ModulusLength);
	crypto_reverse(info->exponent, 4);

	stream_detach(s);
	stream_free(s);
	return TRUE;

error2:
	free(info->Modulus);
	info->Modulus = 0;
error1:
	fprintf(stderr, "error reading when reading certificate: part=%s error=%d\n", certificate_read_errors[error], error);
	stream_detach(s);
	stream_free(s);
	return FALSE;
}