Merge pull request #368 from pjd/crypto

Server-side Standard RDP Security support.
This commit is contained in:
Marc-André Moreau
2012-01-25 08:30:16 -08:00
20 changed files with 622 additions and 108 deletions

View File

@@ -145,6 +145,7 @@ typedef struct
/* Certificates */
typedef struct rdp_certificate rdpCertificate;
typedef struct rdp_key rdpKey;
struct rdp_CertBlob
{
@@ -296,7 +297,8 @@ struct rdp_settings
boolean nla_security; /* 146 */
boolean rdp_security; /* 147 */
uint32 ntlm_version; /* 148 */
uint32 paddingF[160 - 149]; /* 149 */
boolean secure_checksum; /* 149 */
uint32 paddingF[160 - 150]; /* 150 */
/* Session */
boolean console_audio; /* 160 */
@@ -349,7 +351,9 @@ struct rdp_settings
rdpBlob* server_certificate; /* 267 */
boolean ignore_certificate; /* 268 */
rdpCertificate* server_cert; /* 269 */
uint32 paddingL[280 - 270]; /* 270 */
char* rdp_key_file; /* 270 */
rdpKey* server_key; /* 271 */
uint32 paddingL[280 - 272]; /* 272 */
/* Codecs */
boolean rfx_codec; /* 280 */

View File

@@ -1793,22 +1793,17 @@ boolean rdp_recv_demand_active(rdpRdp* rdp, STREAM* s)
uint16 numberCapabilities;
uint16 lengthSourceDescriptor;
uint16 lengthCombinedCapabilities;
uint32 securityHeader;
uint16 securityFlags;
if (!rdp_read_header(rdp, s, &length, &channelId))
return false;
if (rdp->settings->encryption)
{
stream_read_uint32(s, securityHeader);
if (securityHeader & SEC_SECURE_CHECKSUM)
rdp_read_security_header(s, &securityFlags);
if (securityFlags & SEC_ENCRYPT)
{
printf("Error: TODO\n");
return false;
}
if (securityHeader & SEC_ENCRYPT)
{
if (!rdp_decrypt(rdp, s, length - 4))
if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
{
printf("rdp_decrypt failed\n");
return false;
@@ -1927,9 +1922,24 @@ boolean rdp_recv_confirm_active(rdpRdp* rdp, STREAM* s)
uint16 lengthSourceDescriptor;
uint16 lengthCombinedCapabilities;
uint16 numberCapabilities;
uint16 securityFlags;
if (!rdp_read_header(rdp, s, &length, &channelId))
return false;
if (rdp->settings->encryption)
{
rdp_read_security_header(s, &securityFlags);
if (securityFlags & SEC_ENCRYPT)
{
if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
{
printf("rdp_decrypt failed\n");
return false;
}
}
}
if (channelId != MCS_GLOBAL_CHANNEL_ID)
return false;

View File

@@ -17,6 +17,13 @@
* limitations under the License.
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include "certificate.h"
/**
@@ -251,6 +258,7 @@ static boolean certificate_process_server_public_key(rdpCertificate* certificate
modlen = keylen - 8;
freerdp_blob_alloc(&(certificate->cert_info.modulus), modlen);
stream_read(s, certificate->cert_info.modulus.data, modlen);
/* 8 bytes of zero padding */
stream_seek(s, 8);
return true;
@@ -482,3 +490,71 @@ void certificate_free(rdpCertificate* certificate)
}
}
rdpKey* key_new(const char *keyfile)
{
rdpKey* key;
RSA *rsa;
FILE *fp;
key = (rdpKey*) xzalloc(sizeof(rdpKey));
if (key == NULL)
return NULL;
fp = fopen(keyfile, "r");
if (fp == NULL) {
printf("unable to load RSA key from %s: %s.", keyfile,
strerror(errno));
return NULL;
}
rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
if (rsa == NULL) {
ERR_print_errors_fp(stdout);
fclose(fp);
return NULL;
}
fclose(fp);
switch (RSA_check_key(rsa)) {
case 0:
RSA_free(rsa);
printf("invalid RSA key in %s", keyfile);
return NULL;
case 1:
/* Valid key. */
break;
default:
ERR_print_errors_fp(stdout);
RSA_free(rsa);
return NULL;
}
if (BN_num_bytes(rsa->e) > 4) {
RSA_free(rsa);
printf("RSA public exponent too large in %s", keyfile);
return NULL;
}
freerdp_blob_alloc(&key->modulus, BN_num_bytes(rsa->n));
BN_bn2bin(rsa->n, key->modulus.data);
crypto_reverse(key->modulus.data, key->modulus.length);
freerdp_blob_alloc(&key->private_exponent, BN_num_bytes(rsa->d));
BN_bn2bin(rsa->d, key->private_exponent.data);
crypto_reverse(key->private_exponent.data, key->private_exponent.length);
memset(key->exponent, 0, sizeof(key->exponent));
BN_bn2bin(rsa->e, key->exponent + sizeof(key->exponent) - BN_num_bytes(rsa->e));
crypto_reverse(key->exponent, sizeof(key->exponent));
RSA_free(rsa);
return key;
}
void key_free(rdpKey* key)
{
if (key != NULL)
{
freerdp_blob_free(&key->modulus);
freerdp_blob_free(&key->private_exponent);
xfree(key);
}
}

View File

@@ -42,6 +42,13 @@
#define BB_RSA_KEY_BLOB 6
#define BB_RSA_SIGNATURE_BLOB 8
struct rdp_key
{
rdpBlob modulus;
rdpBlob private_exponent;
uint8 exponent[4];
};
void certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info);
rdpX509CertChain* certificate_new_x509_certificate_chain(uint32 count);
@@ -54,6 +61,9 @@ boolean certificate_read_server_certificate(rdpCertificate* certificate, uint8*
rdpCertificate* certificate_new(void);
void certificate_free(rdpCertificate* certificate);
rdpKey* key_new(const char *keyfile);
void key_free(rdpKey* key);
#ifdef WITH_DEBUG_CERTIFICATE
#define DEBUG_CERTIFICATE(fmt, ...) DEBUG_CLASS(CERTIFICATE, fmt, ## __VA_ARGS__)
#else

View File

@@ -182,7 +182,7 @@ boolean rdp_client_redirect(rdpRdp* rdp)
static boolean rdp_client_establish_keys(rdpRdp* rdp)
{
uint8 client_random[32];
uint8 client_random[CLIENT_RANDOM_LENGTH];
uint8 crypt_client_random[256 + 8];
uint32 key_len;
uint8* mod;
@@ -198,15 +198,14 @@ static boolean rdp_client_establish_keys(rdpRdp* rdp)
/* encrypt client random */
memset(crypt_client_random, 0, sizeof(crypt_client_random));
memset(client_random, 0x5e, 32);
crypto_nonce(client_random, 32);
crypto_nonce(client_random, sizeof(client_random));
key_len = rdp->settings->server_cert->cert_info.modulus.length;
mod = rdp->settings->server_cert->cert_info.modulus.data;
exp = rdp->settings->server_cert->cert_info.exponent;
crypto_rsa_public_encrypt(client_random, 32, key_len, mod, exp, crypt_client_random);
crypto_rsa_public_encrypt(client_random, sizeof(client_random), key_len, mod, exp, crypt_client_random);
/* send crypt client random to server */
length = RDP_PACKET_HEADER_LENGTH + RDP_SECURITY_HEADER_LENGTH + 4 + key_len + 8;
length = RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + 4 + key_len + 8;
s = transport_send_stream_init(rdp->mcs->transport, length);
rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
rdp_write_security_header(s, SEC_EXCHANGE_PKT);
@@ -225,6 +224,75 @@ static boolean rdp_client_establish_keys(rdpRdp* rdp)
}
rdp->do_crypt = true;
if (rdp->settings->secure_checksum)
rdp->do_secure_checksum = true;
if (rdp->settings->encryption_method == ENCRYPTION_METHOD_FIPS)
{
uint8 fips_ivec[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec);
rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec);
rdp->fips_hmac = crypto_hmac_new();
return true;
}
rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len);
rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);
return true;
}
static boolean rdp_server_establish_keys(rdpRdp* rdp, STREAM* s)
{
uint8 client_random[64]; /* Should be only 32 after successfull decryption, but on failure might take up to 64 bytes. */
uint8 crypt_client_random[256 + 8];
uint32 rand_len, key_len;
uint16 channel_id, length, sec_flags;
uint8* mod;
uint8* priv_exp;
if (rdp->settings->encryption == false)
{
/* No RDP Security. */
return true;
}
if (!rdp_read_header(rdp, s, &length, &channel_id))
{
printf("rdp_server_establish_keys: invalid RDP header\n");
return false;
}
rdp_read_security_header(s, &sec_flags);
if ((sec_flags & SEC_EXCHANGE_PKT) == 0)
{
printf("rdp_server_establish_keys: missing SEC_EXCHANGE_PKT in security header\n");
return false;
}
stream_read_uint32(s, rand_len);
key_len = rdp->settings->server_key->modulus.length;
if (rand_len != key_len + 8)
{
printf("rdp_server_establish_keys: invalid encrypted client random length\n");
return false;
}
memset(crypt_client_random, 0, sizeof(crypt_client_random));
stream_read(s, crypt_client_random, rand_len);
/* 8 zero bytes of padding */
stream_seek(s, 8);
mod = rdp->settings->server_key->modulus.data;
priv_exp = rdp->settings->server_key->private_exponent.data;
crypto_rsa_private_decrypt(crypt_client_random, rand_len - 8, key_len, mod, priv_exp, client_random);
/* now calculate encrypt / decrypt and update keys */
if (!security_establish_keys(client_random, rdp))
{
return false;
}
rdp->do_crypt = true;
if (rdp->settings->secure_checksum)
rdp->do_secure_checksum = true;
if (rdp->settings->encryption_method == ENCRYPTION_METHOD_FIPS)
{
@@ -371,7 +439,7 @@ boolean rdp_client_connect_demand_active(rdpRdp* rdp, STREAM* s)
if (!rdp_recv_demand_active(rdp, s))
{
stream_set_mark(s, mark);
stream_seek(s, RDP_PACKET_HEADER_LENGTH);
stream_seek(s, RDP_PACKET_HEADER_MAX_LENGTH);
if (rdp_recv_out_of_sequence_pdu(rdp, s) != true)
return false;
@@ -434,14 +502,11 @@ boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s)
if (!nego_read_request(rdp->nego, s))
return false;
if (rdp->nego->requested_protocols == PROTOCOL_RDP)
{
printf("Standard RDP encryption is not supported.\n");
return false;
}
rdp->nego->selected_protocol = 0;
printf("Requested protocols:");
if ((rdp->nego->requested_protocols | PROTOCOL_TLS))
if ((rdp->nego->requested_protocols & PROTOCOL_TLS))
{
printf(" TLS");
if (rdp->settings->tls_security)
@@ -452,7 +517,7 @@ boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s)
else
printf("(n)");
}
if ((rdp->nego->requested_protocols | PROTOCOL_NLA))
if ((rdp->nego->requested_protocols & PROTOCOL_NLA))
{
printf(" NLA");
if (rdp->settings->nla_security)
@@ -463,6 +528,14 @@ boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s)
else
printf("(n)");
}
printf(" RDP");
if (rdp->settings->rdp_security && rdp->nego->selected_protocol == 0)
{
printf("(Y)");
rdp->nego->selected_protocol = PROTOCOL_RDP;
}
else
printf("(n)");
printf("\n");
if (!nego_send_negotiation_response(rdp->nego))
@@ -564,8 +637,20 @@ boolean rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, STREAM* s)
return true;
}
boolean rdp_server_accept_client_keys(rdpRdp* rdp, STREAM* s)
{
if (!rdp_server_establish_keys(rdp, s))
return false;
rdp->state = CONNECTION_STATE_ESTABLISH_KEYS;
return true;
}
boolean rdp_server_accept_client_info(rdpRdp* rdp, STREAM* s)
{
if (!rdp_recv_client_info(rdp, s))
return false;

View File

@@ -39,6 +39,7 @@ enum CONNECTION_STATE
CONNECTION_STATE_MCS_ERECT_DOMAIN,
CONNECTION_STATE_MCS_ATTACH_USER,
CONNECTION_STATE_MCS_CHANNEL_JOIN,
CONNECTION_STATE_ESTABLISH_KEYS,
CONNECTION_STATE_LICENSE,
CONNECTION_STATE_CAPABILITY,
CONNECTION_STATE_FINALIZATION,
@@ -59,6 +60,7 @@ boolean rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, STREAM* s);
boolean rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, STREAM* s);
boolean rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, STREAM* s);
boolean rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, STREAM* s);
boolean rdp_server_accept_client_keys(rdpRdp* rdp, STREAM* s);
boolean rdp_server_accept_client_info(rdpRdp* rdp, STREAM* s);
boolean rdp_server_accept_confirm_active(rdpRdp* rdp, STREAM* s);
boolean rdp_server_reactivate(rdpRdp* rdp);

View File

@@ -24,6 +24,7 @@
#include <freerdp/utils/stream.h>
#include "orders.h"
#include "per.h"
#include "update.h"
#include "surface.h"
@@ -99,10 +100,7 @@ uint16 fastpath_read_header_rdp(rdpFastPath* fastpath, STREAM* s)
{
uint8 header;
uint16 length;
uint8 t;
uint16 hs;
hs = 2;
stream_read_uint8(s, header);
if (fastpath != NULL)
@@ -111,18 +109,9 @@ uint16 fastpath_read_header_rdp(rdpFastPath* fastpath, STREAM* s)
fastpath->numberEvents = (header & 0x3C) >> 2;
}
stream_read_uint8(s, length); /* length1 */
/* If most significant bit is not set, length2 is not presented. */
if ((length & 0x80))
{
hs++;
length &= 0x7F;
length <<= 8;
stream_read_uint8(s, t);
length += t;
}
per_read_length(s, &length);
return length - hs;
return length - stream_get_length(s);
}
static void fastpath_recv_orders(rdpFastPath* fastpath, STREAM* s)
@@ -485,19 +474,48 @@ boolean fastpath_recv_inputs(rdpFastPath* fastpath, STREAM* s)
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)
{
rdpRdp *rdp;
STREAM* s;
s = transport_send_stream_init(fastpath->rdp->transport, 127);
stream_seek(s, 2); /* fpInputHeader and length1 */
/* length2 is not necessary since input PDU should not exceed 127 bytes */
rdp = fastpath->rdp;
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) */
return s;
}
boolean fastpath_send_input_pdu(rdpFastPath* fastpath, STREAM* s)
{
rdpRdp *rdp;
uint16 length;
uint8 eventHeader;
int sec_bytes;
rdp = fastpath->rdp;
length = stream_get_length(s);
if (length > 127)
@@ -506,11 +524,39 @@ boolean fastpath_send_input_pdu(rdpFastPath* fastpath, STREAM* s)
return false;
}
stream_set_pos(s, 0);
stream_write_uint8(s, (1 << 2));
stream_write_uint8(s, length);
eventHeader = FASTPATH_INPUT_ACTION_FASTPATH;
eventHeader |= (1 << 2); /* numberEvents */
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)
return false;
@@ -522,26 +568,33 @@ STREAM* fastpath_update_pdu_init(rdpFastPath* fastpath)
STREAM* s;
s = transport_send_stream_init(fastpath->rdp->transport, FASTPATH_MAX_PACKET_SIZE);
stream_seek(s, 3); /* fpOutputHeader, length1 and length2 */
stream_seek(s, fastpath_get_sec_bytes(fastpath->rdp));
stream_seek(s, 3); /* updateHeader, size */
return s;
}
boolean fastpath_send_update_pdu(rdpFastPath* fastpath, uint8 updateCode, STREAM* s)
{
rdpRdp *rdp;
uint8* bm;
uint8* ptr;
int fragment;
int sec_bytes;
uint16 length;
boolean result;
uint16 pduLength;
uint16 maxLength;
uint32 totalLength;
uint8 fragmentation;
uint8 header;
STREAM* update;
result = true;
maxLength = FASTPATH_MAX_PACKET_SIZE - 6;
totalLength = stream_get_length(s) - 6;
rdp = fastpath->rdp;
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);
update = stream_new(0);
@@ -549,7 +602,7 @@ boolean fastpath_send_update_pdu(rdpFastPath* fastpath, uint8 updateCode, STREAM
{
length = MIN(maxLength, totalLength);
totalLength -= length;
pduLength = length + 6;
pduLength = length + 6 + sec_bytes;
if (totalLength == 0)
fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST;
@@ -557,14 +610,28 @@ boolean fastpath_send_update_pdu(rdpFastPath* fastpath, uint8 updateCode, STREAM
fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT;
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, pduLength & 0xFF); /* length2 */
if (sec_bytes > 0)
stream_seek(s, sec_bytes);
fastpath_write_update_header(s, updateCode, fragmentation, 0);
stream_write_uint16(s, length);
stream_attach(update, bm, 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)
{
stream_detach(update);
@@ -573,8 +640,8 @@ boolean fastpath_send_update_pdu(rdpFastPath* fastpath, uint8 updateCode, STREAM
}
stream_detach(update);
/* Reserve 6 bytes for the next fragment header, if any. */
stream_seek(s, length - 6);
/* Reserve 6+sec_bytes bytes for the next fragment header, if any. */
stream_seek(s, length - 6 - sec_bytes);
}
stream_free(update);

View File

@@ -25,12 +25,24 @@
typedef struct rdp_fastpath rdpFastPath;
enum FASTPATH_INPUT_ACTION_TYPE
{
FASTPATH_INPUT_ACTION_FASTPATH = 0x0,
FASTPATH_INPUT_ACTION_X224 = 0x3
};
enum FASTPATH_OUTPUT_ACTION_TYPE
{
FASTPATH_OUTPUT_ACTION_FASTPATH = 0x0,
FASTPATH_OUTPUT_ACTION_X224 = 0x3
};
enum FASTPATH_INPUT_ENCRYPTION_FLAGS
{
FASTPATH_INPUT_SECURE_CHECKSUM = 0x1,
FASTPATH_INPUT_ENCRYPTED = 0x2
};
enum FASTPATH_OUTPUT_ENCRYPTION_FLAGS
{
FASTPATH_OUTPUT_SECURE_CHECKSUM = 0x1,

View File

@@ -407,6 +407,7 @@ boolean gcc_read_server_data_blocks(STREAM* s, rdpSettings* settings, int length
break;
default:
printf("gcc_read_server_data_blocks: ignoring type=%hu\n", type);
break;
}
offset += blockLength;
@@ -740,10 +741,16 @@ boolean gcc_read_client_security_data(STREAM* s, rdpSettings *settings, uint16 b
if (blockLength < 8)
return false;
stream_read_uint32(s, settings->encryption_method); /* encryptionMethods */
if (settings->encryption_method == 0)
stream_read_uint32(s, settings->encryption_method); /* extEncryptionMethods */
if (settings->encryption)
{
stream_read_uint32(s, settings->encryption_method); /* encryptionMethods */
if (settings->encryption_method == 0)
stream_read_uint32(s, settings->encryption_method); /* extEncryptionMethods */
}
else
{
stream_seek(s, 8);
}
return true;
}
@@ -825,16 +832,129 @@ boolean gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
return true;
}
static const uint8 initial_signature[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01
};
void gcc_write_server_security_data(STREAM* s, rdpSettings *settings)
{
gcc_write_user_data_header(s, SC_SECURITY, 12);
uint32 headerLen, serverRandomLen, serverCertLen, wPublicKeyBlobLen;
uint8 signature[sizeof(initial_signature)];
uint8 encryptedSignature[TSSK_KEY_LENGTH];
uint8* sigData;
int expLen, keyLen, sigDataLen;
stream_write_uint32(s, ENCRYPTION_METHOD_NONE); /* encryptionMethod */
stream_write_uint32(s, ENCRYPTION_LEVEL_NONE); /* encryptionLevel */
#if 0
stream_write_uint32(s, 0); /* serverRandomLen */
stream_write_uint32(s, 0); /* serverCertLen */
#endif
if (!settings->encryption) {
settings->encryption_method = ENCRYPTION_METHOD_NONE;
settings->encryption_level = ENCRYPTION_LEVEL_NONE;
}
else if ((settings->encryption_method & ENCRYPTION_METHOD_FIPS) != 0)
{
settings->encryption_method = ENCRYPTION_METHOD_FIPS;
}
else if ((settings->encryption_method & ENCRYPTION_METHOD_128BIT) != 0)
{
settings->encryption_method = ENCRYPTION_METHOD_128BIT;
}
else if ((settings->encryption_method & ENCRYPTION_METHOD_40BIT) != 0)
{
settings->encryption_method = ENCRYPTION_METHOD_40BIT;
}
if (settings->encryption_method != ENCRYPTION_METHOD_NONE)
settings->encryption_level = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
headerLen = 12;
keyLen = 0;
wPublicKeyBlobLen = 0;
serverRandomLen = 0;
serverCertLen = 0;
if (settings->encryption_method != ENCRYPTION_METHOD_NONE ||
settings->encryption_level != ENCRYPTION_LEVEL_NONE) {
serverRandomLen = 32;
keyLen = settings->server_key->modulus.length;
expLen = sizeof(settings->server_key->exponent);
wPublicKeyBlobLen = 4; /* magic (RSA1) */
wPublicKeyBlobLen += 4; /* keylen */
wPublicKeyBlobLen += 4; /* bitlen */
wPublicKeyBlobLen += 4; /* datalen */
wPublicKeyBlobLen += expLen;
wPublicKeyBlobLen += keyLen;
wPublicKeyBlobLen += 8; /* 8 bytes of zero padding */
serverCertLen = 4; /* dwVersion */
serverCertLen += 4; /* dwSigAlgId */
serverCertLen += 4; /* dwKeyAlgId */
serverCertLen += 2; /* wPublicKeyBlobType */
serverCertLen += 2; /* wPublicKeyBlobLen */
serverCertLen += wPublicKeyBlobLen;
serverCertLen += 2; /* wSignatureBlobType */
serverCertLen += 2; /* wSignatureBlobLen */
serverCertLen += sizeof(encryptedSignature); /* SignatureBlob */
serverCertLen += 8; /* 8 bytes of zero padding */
headerLen += sizeof(serverRandomLen);
headerLen += sizeof(serverCertLen);
headerLen += serverRandomLen;
headerLen += serverCertLen;
}
gcc_write_user_data_header(s, SC_SECURITY, headerLen);
stream_write_uint32(s, settings->encryption_method); /* encryptionMethod */
stream_write_uint32(s, settings->encryption_level); /* encryptionLevel */
if (settings->encryption_method == ENCRYPTION_METHOD_NONE &&
settings->encryption_level == ENCRYPTION_LEVEL_NONE) {
return;
}
stream_write_uint32(s, serverRandomLen); /* serverRandomLen */
stream_write_uint32(s, serverCertLen); /* serverCertLen */
freerdp_blob_alloc(settings->server_random, serverRandomLen);
crypto_nonce(settings->server_random->data, serverRandomLen);
stream_write(s, settings->server_random->data, serverRandomLen);
sigData = stream_get_tail(s);
stream_write_uint32(s, CERT_CHAIN_VERSION_1); /* dwVersion (4 bytes) */
stream_write_uint32(s, SIGNATURE_ALG_RSA); /* dwSigAlgId */
stream_write_uint32(s, KEY_EXCHANGE_ALG_RSA); /* dwKeyAlgId */
stream_write_uint16(s, BB_RSA_KEY_BLOB); /* wPublicKeyBlobType */
stream_write_uint16(s, wPublicKeyBlobLen); /* wPublicKeyBlobLen */
stream_write(s, "RSA1", 4); /* magic */
stream_write_uint32(s, keyLen + 8); /* keylen */
stream_write_uint32(s, keyLen * 8); /* bitlen */
stream_write_uint32(s, keyLen - 1); /* datalen */
stream_write(s, settings->server_key->exponent, expLen);
stream_write(s, settings->server_key->modulus.data, keyLen);
stream_write_zero(s, 8);
sigDataLen = stream_get_tail(s) - sigData;
stream_write_uint16(s, BB_RSA_SIGNATURE_BLOB); /* wSignatureBlobType */
stream_write_uint16(s, keyLen + 8); /* wSignatureBlobLen */
memcpy(signature, initial_signature, sizeof(initial_signature));
CryptoMd5 md5Ctx;
md5Ctx = crypto_md5_init();
crypto_md5_update(md5Ctx, sigData, sigDataLen);
crypto_md5_final(md5Ctx, signature);
crypto_rsa_private_encrypt(signature, sizeof(signature), TSSK_KEY_LENGTH, tssk_modulus, tssk_privateExponent, encryptedSignature);
stream_write(s, encryptedSignature, sizeof(encryptedSignature));
stream_write_zero(s, 8);
}
/**

View File

@@ -564,15 +564,32 @@ boolean rdp_recv_client_info(rdpRdp* rdp, STREAM* s)
{
uint16 length;
uint16 channelId;
uint16 sec_flags;
uint16 securityFlags;
if (!rdp_read_header(rdp, s, &length, &channelId))
return false;
rdp_read_security_header(s, &sec_flags);
if ((sec_flags & SEC_INFO_PKT) == 0)
rdp_read_security_header(s, &securityFlags);
if ((securityFlags & SEC_INFO_PKT) == 0)
return false;
if (rdp->settings->encryption)
{
if (securityFlags & SEC_REDIRECTION_PKT)
{
printf("Error: SEC_REDIRECTION_PKT unsupported\n");
return false;
}
if (securityFlags & SEC_ENCRYPT)
{
if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
{
printf("rdp_decrypt failed\n");
return false;
}
}
}
return rdp_read_info_packet(s, rdp->settings);
}

View File

@@ -111,7 +111,7 @@ STREAM* license_send_stream_init(rdpLicense* license)
{
STREAM* s;
s = transport_send_stream_init(license->rdp->transport, 4096);
stream_seek(s, LICENSE_PACKET_HEADER_LENGTH);
stream_seek(s, LICENSE_PACKET_HEADER_MAX_LENGTH);
return s;
}
@@ -135,7 +135,7 @@ boolean license_send(rdpLicense* license, STREAM* s, uint8 type)
stream_set_pos(s, 0);
sec_flags = SEC_LICENSE_PKT;
wMsgSize = length - LICENSE_PACKET_HEADER_LENGTH + 4;
wMsgSize = length - LICENSE_PACKET_HEADER_MAX_LENGTH + 4;
/**
* Using EXTENDED_ERROR_MSG_SUPPORTED here would cause mstsc to crash when
* running in server mode! This flag seems to be incorrectly documented.

View File

@@ -44,8 +44,8 @@ typedef struct rdp_license rdpLicense;
#define LICENSE_PKT_SC_MASK (LICENSE_REQUEST | PLATFORM_CHALLENGE | NEW_LICENSE | UPGRADE_LICENSE | ERROR_ALERT)
#define LICENSE_PKT_MASK (LICENSE_PKT_CS_MASK | LICENSE_PKT_SC_MASK)
#define LICENSE_PREAMBLE_LENGTH 4
#define LICENSE_PACKET_HEADER_LENGTH (RDP_PACKET_HEADER_LENGTH + RDP_SECURITY_HEADER_LENGTH + LICENSE_PREAMBLE_LENGTH)
#define LICENSE_PREAMBLE_LENGTH 4
#define LICENSE_PACKET_HEADER_MAX_LENGTH (RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + LICENSE_PREAMBLE_LENGTH)
/* Cryptographic Lengths */
#define CLIENT_RANDOM_LENGTH 32

View File

@@ -124,7 +124,7 @@ struct rdp_mcs
};
typedef struct rdp_mcs rdpMcs;
#define MCS_SEND_DATA_HEADER_LENGTH 8
#define MCS_SEND_DATA_HEADER_MAX_LENGTH 8
#define MCS_TYPE_CONNECT_INITIAL 0x65
#define MCS_TYPE_CONNECT_RESPONSE 0x66

View File

@@ -521,8 +521,13 @@ void nego_process_negotiation_failure(rdpNego* nego, STREAM* s)
boolean nego_send_negotiation_response(rdpNego* nego)
{
STREAM* s;
rdpSettings* settings;
int length;
uint8 *bm, *em;
boolean ret;
ret = true;
settings = nego->transport->settings;
s = transport_send_stream_init(nego->transport, 256);
length = TPDU_CONNECTION_CONFIRM_LENGTH;
@@ -538,6 +543,20 @@ boolean nego_send_negotiation_response(rdpNego* nego)
stream_write_uint32(s, nego->selected_protocol); /* selectedProtocol */
length += 8;
}
else if (!settings->rdp_security)
{
stream_write_uint8(s, TYPE_RDP_NEG_FAILURE);
stream_write_uint8(s, 0); /* flags */
stream_write_uint16(s, 8); /* RDP_NEG_DATA length (8) */
/*
* TODO: Check for other possibilities,
* like SSL_NOT_ALLOWED_BY_SERVER.
*/
printf("nego_send_negotiation_response: client supports only Standard RDP Security\n");
stream_write_uint32(s, SSL_REQUIRED_BY_SERVER);
length += 8;
ret = false;
}
stream_get_mark(s, em);
stream_set_mark(s, bm);
@@ -548,11 +567,42 @@ boolean nego_send_negotiation_response(rdpNego* nego)
if (transport_write(nego->transport, s) < 0)
return false;
/* update settings with negotiated protocol security */
nego->transport->settings->requested_protocols = nego->requested_protocols;
nego->transport->settings->selected_protocol = nego->selected_protocol;
if (ret)
{
/* update settings with negotiated protocol security */
settings->requested_protocols = nego->requested_protocols;
settings->selected_protocol = nego->selected_protocol;
return true;
if (settings->selected_protocol == PROTOCOL_RDP)
{
settings->tls_security = false;
settings->nla_security = false;
settings->rdp_security = true;
settings->encryption = true;
settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->encryption_level = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
}
else if (settings->selected_protocol == PROTOCOL_TLS)
{
settings->tls_security = true;
settings->nla_security = false;
settings->rdp_security = false;
settings->encryption = false;
settings->encryption_method = ENCRYPTION_METHOD_NONE;
settings->encryption_level = ENCRYPTION_LEVEL_NONE;
}
else if (settings->selected_protocol == PROTOCOL_NLA)
{
settings->tls_security = true;
settings->nla_security = true;
settings->rdp_security = false;
settings->encryption = false;
settings->encryption_method = ENCRYPTION_METHOD_NONE;
settings->encryption_level = ENCRYPTION_LEVEL_NONE;
}
}
return ret;
}
/**

View File

@@ -23,6 +23,10 @@ static boolean freerdp_peer_initialize(freerdp_peer* client)
{
client->context->rdp->settings->server_mode = true;
client->context->rdp->state = CONNECTION_STATE_INITIAL;
if (client->context->rdp->settings->rdp_key_file != NULL) {
client->context->rdp->settings->server_key =
key_new(client->context->rdp->settings->rdp_key_file);
}
return true;
}
@@ -112,18 +116,35 @@ static boolean peer_recv_data_pdu(freerdp_peer* client, STREAM* s)
static boolean peer_recv_tpkt_pdu(freerdp_peer* client, STREAM* s)
{
rdpRdp *rdp;
uint16 length;
uint16 pduType;
uint16 pduLength;
uint16 pduSource;
uint16 channelId;
uint16 securityFlags;
if (!rdp_read_header(client->context->rdp, s, &length, &channelId))
rdp = client->context->rdp;
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)
{
if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
{
printf("rdp_decrypt failed\n");
return false;
}
}
}
if (channelId != MCS_GLOBAL_CHANNEL_ID)
{
freerdp_channel_peer_process(client, s, channelId);
@@ -169,7 +190,7 @@ static boolean peer_recv_fastpath_pdu(freerdp_peer* client, STREAM* s)
if (fastpath->encryptionFlags & FASTPATH_OUTPUT_ENCRYPTED)
{
rdp_decrypt(rdp, s, length);
rdp_decrypt(rdp, s, length, (fastpath->encryptionFlags & FASTPATH_OUTPUT_SECURE_CHECKSUM) ? SEC_SECURE_CHECKSUM : 0);
}
return fastpath_recv_inputs(fastpath, s);
@@ -215,6 +236,15 @@ static boolean peer_recv_callback(rdpTransport* transport, STREAM* s, void* extr
break;
case CONNECTION_STATE_MCS_CHANNEL_JOIN:
if (client->context->rdp->settings->encryption) {
if (!rdp_server_accept_client_keys(client->context->rdp, s))
return false;
break;
}
client->context->rdp->state = CONNECTION_STATE_ESTABLISH_KEYS;
/* FALLTHROUGH */
case CONNECTION_STATE_ESTABLISH_KEYS:
if (!rdp_server_accept_client_info(client->context->rdp, s))
return false;
IFCALL(client->Capabilities, client);

View File

@@ -105,7 +105,7 @@ boolean rdp_read_share_control_header(STREAM* s, uint16* length, uint16* type, u
void rdp_write_share_control_header(STREAM* s, uint16 length, uint16 type, uint16 channel_id)
{
length -= RDP_PACKET_HEADER_LENGTH;
length -= RDP_PACKET_HEADER_MAX_LENGTH;
/* Share Control Header */
stream_write_uint16(s, length); /* totalLength */
@@ -113,7 +113,7 @@ void rdp_write_share_control_header(STREAM* s, uint16 length, uint16 type, uint1
stream_write_uint16(s, channel_id); /* pduSource */
}
boolean rdp_read_share_data_header(STREAM* s, uint16* length, uint8* type, uint32* share_id,
boolean 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)
@@ -126,7 +126,7 @@ boolean rdp_read_share_data_header(STREAM* s, uint16* length, uint8* type, uint3
stream_read_uint16(s, *length); /* uncompressedLength (2 bytes) */
stream_read_uint8(s, *type); /* pduType2, Data PDU Type (1 byte) */
if (*type & 0x80)
if (*type & 0x80)
{
stream_read_uint8(s, *compressed_type); /* compressedType (1 byte) */
stream_read_uint16(s, *compressed_len); /* compressedLength (2 bytes) */
@@ -143,7 +143,7 @@ boolean rdp_read_share_data_header(STREAM* s, uint16* length, uint8* type, uint3
void rdp_write_share_data_header(STREAM* s, uint16 length, uint8 type, uint32 share_id)
{
length -= RDP_PACKET_HEADER_LENGTH;
length -= RDP_PACKET_HEADER_MAX_LENGTH;
length -= RDP_SHARE_CONTROL_HEADER_LENGTH;
length -= RDP_SHARE_DATA_HEADER_LENGTH;
@@ -165,6 +165,8 @@ static int rdp_security_stream_init(rdpRdp* rdp, STREAM* s)
if (rdp->settings->encryption_method == ENCRYPTION_METHOD_FIPS)
stream_seek(s, 4);
rdp->sec_flags |= SEC_ENCRYPT;
if (rdp->do_secure_checksum)
rdp->sec_flags |= SEC_SECURE_CHECKSUM;
}
else if (rdp->sec_flags != 0)
{
@@ -184,7 +186,7 @@ STREAM* rdp_send_stream_init(rdpRdp* rdp)
STREAM* s;
s = transport_send_stream_init(rdp->transport, 2048);
stream_seek(s, RDP_PACKET_HEADER_LENGTH);
stream_seek(s, RDP_PACKET_HEADER_MAX_LENGTH);
rdp_security_stream_init(rdp, s);
return s;
@@ -194,7 +196,7 @@ STREAM* rdp_pdu_init(rdpRdp* rdp)
{
STREAM* s;
s = transport_send_stream_init(rdp->transport, 2048);
stream_seek(s, RDP_PACKET_HEADER_LENGTH);
stream_seek(s, RDP_PACKET_HEADER_MAX_LENGTH);
rdp_security_stream_init(rdp, s);
stream_seek(s, RDP_SHARE_CONTROL_HEADER_LENGTH);
return s;
@@ -204,7 +206,7 @@ STREAM* rdp_data_pdu_init(rdpRdp* rdp)
{
STREAM* s;
s = transport_send_stream_init(rdp->transport, 2048);
stream_seek(s, RDP_PACKET_HEADER_LENGTH);
stream_seek(s, RDP_PACKET_HEADER_MAX_LENGTH);
rdp_security_stream_init(rdp, s);
stream_seek(s, RDP_SHARE_CONTROL_HEADER_LENGTH);
stream_seek(s, RDP_SHARE_DATA_HEADER_LENGTH);
@@ -257,7 +259,7 @@ void rdp_write_header(rdpRdp* rdp, STREAM* s, uint16 length, uint16 channel_id)
{
int pad;
body_length = length - RDP_PACKET_HEADER_LENGTH - 16;
body_length = length - RDP_PACKET_HEADER_MAX_LENGTH - 16;
pad = 8 - (body_length % 8);
if (pad != 8)
length += pad;
@@ -267,8 +269,13 @@ void rdp_write_header(rdpRdp* rdp, STREAM* s, uint16 length, uint16 channel_id)
per_write_integer16(s, rdp->mcs->user_id, MCS_BASE_CHANNEL_ID); /* initiator */
per_write_integer16(s, channel_id, 0); /* channelId */
stream_write_uint8(s, 0x70); /* dataPriority + segmentation */
length = (length - RDP_PACKET_HEADER_LENGTH) | 0x8000;
/*
* 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.
*/
length = (length - RDP_PACKET_HEADER_MAX_LENGTH) | 0x8000;
stream_write_uint16_be(s, length); /* userData (OCTET_STRING) */
}
@@ -312,7 +319,10 @@ static uint32 rdp_security_stream_out(rdpRdp* rdp, STREAM* s, int length)
{
data = s->p + 8;
length = length - (data - s->data);
security_mac_signature(rdp, data, length, s->p);
if (sec_flags & SEC_SECURE_CHECKSUM)
security_salted_mac_signature(rdp, data, length, true, s->p);
else
security_mac_signature(rdp, data, length, s->p);
stream_seek(s, 8);
security_encrypt(s->p, length, rdp);
}
@@ -371,7 +381,7 @@ boolean rdp_send(rdpRdp* rdp, STREAM* s, uint16 channel_id)
s->p = sec_hold;
length += rdp_security_stream_out(rdp, s, length);
stream_set_pos(s, length);
if (transport_write(rdp->transport, s) < 0)
return false;
@@ -575,7 +585,7 @@ boolean rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, STREAM* s)
* @param length int
*/
boolean rdp_decrypt(rdpRdp* rdp, STREAM* s, int length)
boolean rdp_decrypt(rdpRdp* rdp, STREAM* s, int length, uint16 securityFlags)
{
uint8 cmac[8], wmac[8];
@@ -614,10 +624,21 @@ boolean rdp_decrypt(rdpRdp* rdp, STREAM* s, int length)
stream_read(s, wmac, sizeof(wmac));
length -= sizeof(wmac);
security_decrypt(s->p, length, rdp);
security_mac_signature(rdp, s->p, length, cmac);
if (memcmp(wmac, cmac, sizeof(wmac)) != 0) {
printf("FATAL: invalid packet signature\n");
return false;
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;
}
@@ -635,7 +656,7 @@ static boolean rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
uint16 pduLength;
uint16 pduSource;
uint16 channelId;
uint32 securityHeader;
uint16 securityFlags;
if (!rdp_read_header(rdp, s, &length, &channelId))
{
@@ -645,21 +666,16 @@ static boolean rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
if (rdp->settings->encryption)
{
stream_read_uint32(s, securityHeader);
if (securityHeader & SEC_SECURE_CHECKSUM)
rdp_read_security_header(s, &securityFlags);
if (securityFlags & (SEC_ENCRYPT|SEC_REDIRECTION_PKT))
{
printf("Error: TODO\n");
return false;
}
if (securityHeader & (SEC_ENCRYPT|SEC_REDIRECTION_PKT))
{
if (!rdp_decrypt(rdp, s, length - 4))
if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
{
printf("rdp_decrypt failed\n");
return false;
}
}
if (securityHeader & SEC_REDIRECTION_PKT)
if (securityFlags & SEC_REDIRECTION_PKT)
{
/*
* [MS-RDPBCGR] 2.2.13.2.1
@@ -712,7 +728,7 @@ static boolean rdp_recv_fastpath_pdu(rdpRdp* rdp, STREAM* s)
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);
@@ -721,7 +737,7 @@ static boolean rdp_recv_fastpath_pdu(rdpRdp* rdp, STREAM* s)
if (fastpath->encryptionFlags & FASTPATH_OUTPUT_ENCRYPTED)
{
rdp_decrypt(rdp, s, length);
rdp_decrypt(rdp, s, length, (fastpath->encryptionFlags & FASTPATH_OUTPUT_SECURE_CHECKSUM) ? SEC_SECURE_CHECKSUM : 0);
}
return fastpath_recv_updates(rdp->fastpath, s);

View File

@@ -63,7 +63,7 @@
#define RDP_SECURITY_HEADER_LENGTH 4
#define RDP_SHARE_CONTROL_HEADER_LENGTH 6
#define RDP_SHARE_DATA_HEADER_LENGTH 12
#define RDP_PACKET_HEADER_LENGTH (TPDU_DATA_LENGTH + MCS_SEND_DATA_HEADER_LENGTH)
#define RDP_PACKET_HEADER_MAX_LENGTH (TPDU_DATA_LENGTH + MCS_SEND_DATA_HEADER_MAX_LENGTH)
#define PDU_TYPE_DEMAND_ACTIVE 0x1
#define PDU_TYPE_CONFIRM_ACTIVE 0x3
@@ -143,6 +143,7 @@ struct rdp_rdp
struct crypto_hmac_struct* fips_hmac;
uint32 sec_flags;
boolean do_crypt;
boolean do_secure_checksum;
uint8 sign_key[16];
uint8 decrypt_key[16];
uint8 encrypt_key[16];
@@ -198,6 +199,6 @@ void rdp_free(rdpRdp* rdp);
#define DEBUG_RDP(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
boolean rdp_decrypt(rdpRdp* rdp, STREAM* s, int length);
boolean rdp_decrypt(rdpRdp* rdp, STREAM* s, int length, uint16 securityFlags);
#endif /* __RDP_H */

View File

@@ -264,7 +264,13 @@ void security_salted_mac_signature(rdpRdp *rdp, uint8* data, uint32 length, bool
if (encryption)
security_uint32_le(use_count_le, rdp->encrypt_use_count);
else
security_uint32_le(use_count_le, rdp->decrypt_use_count);
{
/*
* We calculate checksum on plain text, so we must have already
* decrypt it, which means decrypt_use_count is off by one.
*/
security_uint32_le(use_count_le, rdp->decrypt_use_count - 1);
}
/* SHA1_Digest = SHA1(MACKeyN + pad1 + length + data) */
sha1 = crypto_sha1_init();

View File

@@ -56,6 +56,7 @@ rdpSettings* settings_new(void* instance)
settings->kbd_fn_keys = 0;
settings->kbd_layout = 0;
settings->encryption = false;
settings->secure_checksum = false;
settings->port = 3389;
settings->desktop_resize = true;
@@ -197,6 +198,7 @@ void settings_free(rdpSettings* settings)
freerdp_blob_free(settings->server_certificate);
xfree(settings->server_random);
xfree(settings->server_certificate);
xfree(settings->rdp_key_file);
certificate_free(settings->server_cert);
xfree(settings->client_auto_reconnect_cookie);
xfree(settings->server_auto_reconnect_cookie);
@@ -204,6 +206,7 @@ void settings_free(rdpSettings* settings)
xfree(settings->bitmapCacheV2CellInfo);
xfree(settings->glyphCache);
xfree(settings->fragCache);
key_free(settings->server_key);
xfree(settings);
}
}

View File

@@ -101,6 +101,7 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
" --ntlm: force NTLM authentication protocol version (1 or 2)\n"
" --ignore-certificate: ignore verification of logon certificate\n"
" --sec: force protocol security (rdp, tls or nla)\n"
" --secure-checksum: use salted checksums with Standard RDP encryption\n"
" --version: print version information\n"
"\n", argv[0]);
return FREERDP_ARGS_PARSE_HELP; //TODO: What is the correct return
@@ -600,6 +601,10 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
}
num_extensions++;
}
else if (strcmp("--secure-checksum", argv[index]) == 0)
{
settings->secure_checksum = true;
}
else if (strcmp("--version", argv[index]) == 0)
{
printf("This is FreeRDP version %s\n", FREERDP_VERSION_FULL);