Add Standard RDP encryption suport for fastpath. Both input and output.

This commit is contained in:
Pawel Jakub Dawidek 2012-01-25 16:08:14 +01:00
parent 9c8a6bd8e9
commit 61aa1dfb79

View File

@ -474,19 +474,48 @@ boolean fastpath_recv_inputs(rdpFastPath* fastpath, STREAM* s)
return true; return true;
} }
static uint32 fastpath_get_sec_bytes(rdpRdp* rdp)
{
uint32 sec_bytes;
if (rdp->do_crypt)
{
sec_bytes = 8;
if (rdp->settings->encryption_method == ENCRYPTION_METHOD_FIPS)
sec_bytes += 4;
}
else
sec_bytes = 0;
return sec_bytes;
}
STREAM* fastpath_input_pdu_init(rdpFastPath* fastpath, uint8 eventFlags, uint8 eventCode) STREAM* fastpath_input_pdu_init(rdpFastPath* fastpath, uint8 eventFlags, uint8 eventCode)
{ {
rdpRdp *rdp;
STREAM* s; STREAM* s;
s = transport_send_stream_init(fastpath->rdp->transport, 127);
stream_seek(s, 2); /* fpInputHeader and length1 */ rdp = fastpath->rdp;
/* length2 is not necessary since input PDU should not exceed 127 bytes */
s = transport_send_stream_init(rdp->transport, 256);
stream_seek(s, 3); /* fpInputHeader, length1 and length2 */
if (rdp->do_crypt) {
rdp->sec_flags |= SEC_ENCRYPT;
if (rdp->do_secure_checksum)
rdp->sec_flags |= SEC_SECURE_CHECKSUM;
}
stream_seek(s, fastpath_get_sec_bytes(rdp));
stream_write_uint8(s, eventFlags | (eventCode << 5)); /* eventHeader (1 byte) */ stream_write_uint8(s, eventFlags | (eventCode << 5)); /* eventHeader (1 byte) */
return s; return s;
} }
boolean fastpath_send_input_pdu(rdpFastPath* fastpath, STREAM* s) boolean fastpath_send_input_pdu(rdpFastPath* fastpath, STREAM* s)
{ {
rdpRdp *rdp;
uint16 length; uint16 length;
uint8 eventHeader;
int sec_bytes;
rdp = fastpath->rdp;
length = stream_get_length(s); length = stream_get_length(s);
if (length > 127) if (length > 127)
@ -495,11 +524,39 @@ boolean fastpath_send_input_pdu(rdpFastPath* fastpath, STREAM* s)
return false; return false;
} }
stream_set_pos(s, 0); eventHeader = FASTPATH_INPUT_ACTION_FASTPATH;
stream_write_uint8(s, (1 << 2)); eventHeader |= (1 << 2); /* numberEvents */
stream_write_uint8(s, length); if (rdp->sec_flags & SEC_ENCRYPT)
eventHeader |= (FASTPATH_INPUT_ENCRYPTED << 6);
if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
eventHeader |= (FASTPATH_INPUT_SECURE_CHECKSUM << 6);
stream_set_pos(s, length); stream_set_pos(s, 0);
stream_write_uint8(s, eventHeader);
sec_bytes = fastpath_get_sec_bytes(fastpath->rdp);
/*
* We always encode length in two bytes, eventhough we could use
* only one byte if length <= 0x7F. It is just easier that way,
* because we can leave room for fixed-length header, store all
* the data first and then store the header.
*/
stream_write_uint16_be(s, 0x8000 | (length + sec_bytes));
if (sec_bytes > 0)
{
uint8* ptr;
ptr = stream_get_tail(s) + sec_bytes;
if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
security_salted_mac_signature(rdp, ptr, length - 3, true, stream_get_tail(s));
else
security_mac_signature(rdp, ptr, length - 3, stream_get_tail(s));
security_encrypt(ptr, length - 3, rdp);
}
rdp->sec_flags = 0;
stream_set_pos(s, length + sec_bytes);
if (transport_write(fastpath->rdp->transport, s) < 0) if (transport_write(fastpath->rdp->transport, s) < 0)
return false; return false;
@ -511,26 +568,33 @@ STREAM* fastpath_update_pdu_init(rdpFastPath* fastpath)
STREAM* s; STREAM* s;
s = transport_send_stream_init(fastpath->rdp->transport, FASTPATH_MAX_PACKET_SIZE); s = transport_send_stream_init(fastpath->rdp->transport, FASTPATH_MAX_PACKET_SIZE);
stream_seek(s, 3); /* fpOutputHeader, length1 and length2 */ stream_seek(s, 3); /* fpOutputHeader, length1 and length2 */
stream_seek(s, fastpath_get_sec_bytes(fastpath->rdp));
stream_seek(s, 3); /* updateHeader, size */ stream_seek(s, 3); /* updateHeader, size */
return s; return s;
} }
boolean fastpath_send_update_pdu(rdpFastPath* fastpath, uint8 updateCode, STREAM* s) boolean fastpath_send_update_pdu(rdpFastPath* fastpath, uint8 updateCode, STREAM* s)
{ {
rdpRdp *rdp;
uint8* bm; uint8* bm;
uint8* ptr;
int fragment; int fragment;
int sec_bytes;
uint16 length; uint16 length;
boolean result; boolean result;
uint16 pduLength; uint16 pduLength;
uint16 maxLength; uint16 maxLength;
uint32 totalLength; uint32 totalLength;
uint8 fragmentation; uint8 fragmentation;
uint8 header;
STREAM* update; STREAM* update;
result = true; result = true;
maxLength = FASTPATH_MAX_PACKET_SIZE - 6; rdp = fastpath->rdp;
totalLength = stream_get_length(s) - 6; sec_bytes = fastpath_get_sec_bytes(rdp);
maxLength = FASTPATH_MAX_PACKET_SIZE - 6 - sec_bytes;
totalLength = stream_get_length(s) - 6 - sec_bytes;
stream_set_pos(s, 0); stream_set_pos(s, 0);
update = stream_new(0); update = stream_new(0);
@ -538,7 +602,7 @@ boolean fastpath_send_update_pdu(rdpFastPath* fastpath, uint8 updateCode, STREAM
{ {
length = MIN(maxLength, totalLength); length = MIN(maxLength, totalLength);
totalLength -= length; totalLength -= length;
pduLength = length + 6; pduLength = length + 6 + sec_bytes;
if (totalLength == 0) if (totalLength == 0)
fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST; fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST;
@ -546,14 +610,28 @@ boolean fastpath_send_update_pdu(rdpFastPath* fastpath, uint8 updateCode, STREAM
fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT; fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT;
stream_get_mark(s, bm); stream_get_mark(s, bm);
stream_write_uint8(s, 0); /* fpOutputHeader (1 byte) */ header = 0;
if (sec_bytes > 0)
header |= (FASTPATH_OUTPUT_ENCRYPTED << 6);
stream_write_uint8(s, header); /* fpOutputHeader (1 byte) */
stream_write_uint8(s, 0x80 | (pduLength >> 8)); /* length1 */ stream_write_uint8(s, 0x80 | (pduLength >> 8)); /* length1 */
stream_write_uint8(s, pduLength & 0xFF); /* length2 */ stream_write_uint8(s, pduLength & 0xFF); /* length2 */
if (sec_bytes > 0)
stream_seek(s, sec_bytes);
fastpath_write_update_header(s, updateCode, fragmentation, 0); fastpath_write_update_header(s, updateCode, fragmentation, 0);
stream_write_uint16(s, length); stream_write_uint16(s, length);
stream_attach(update, bm, pduLength); stream_attach(update, bm, pduLength);
stream_seek(update, pduLength); stream_seek(update, pduLength);
if (sec_bytes > 0)
{
ptr = bm + 3 + sec_bytes;
if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
security_salted_mac_signature(rdp, ptr, length + 3, true, bm + 3);
else
security_mac_signature(rdp, ptr, length + 3, bm + 3);
security_encrypt(ptr, length + 3, rdp);
}
if (transport_write(fastpath->rdp->transport, update) < 0) if (transport_write(fastpath->rdp->transport, update) < 0)
{ {
stream_detach(update); stream_detach(update);
@ -562,8 +640,8 @@ boolean fastpath_send_update_pdu(rdpFastPath* fastpath, uint8 updateCode, STREAM
} }
stream_detach(update); stream_detach(update);
/* Reserve 6 bytes for the next fragment header, if any. */ /* Reserve 6+sec_bytes bytes for the next fragment header, if any. */
stream_seek(s, length - 6); stream_seek(s, length - 6 - sec_bytes);
} }
stream_free(update); stream_free(update);