/[rdesktop]/sourceforge.net/trunk/rdesktop/secure.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/secure.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 966 - (show annotations)
Wed Aug 3 11:48:22 2005 UTC (18 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 22058 byte(s)
Added URL to MSDN, about the keyboard type, subtype, functionkeys.

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - RDP encryption and licensing
4 Copyright (C) Matthew Chapman 1999-2005
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "rdesktop.h"
22
23 #include <openssl/rc4.h>
24 #include <openssl/md5.h>
25 #include <openssl/sha.h>
26 #include <openssl/bn.h>
27 #include <openssl/x509v3.h>
28
29 extern char g_hostname[16];
30 extern int g_width;
31 extern int g_height;
32 extern int g_keylayout;
33 extern int g_keyboard_type;
34 extern int g_keyboard_subtype;
35 extern int g_keyboard_functionkeys;
36 extern BOOL g_encryption;
37 extern BOOL g_licence_issued;
38 extern BOOL g_use_rdp5;
39 extern BOOL g_console_session;
40 extern int g_server_bpp;
41 extern uint16 mcs_userid;
42 extern VCHANNEL g_channels[];
43 extern unsigned int g_num_channels;
44
45 static int rc4_key_len;
46 static RC4_KEY rc4_decrypt_key;
47 static RC4_KEY rc4_encrypt_key;
48 static RSA *server_public_key;
49
50 static uint8 sec_sign_key[16];
51 static uint8 sec_decrypt_key[16];
52 static uint8 sec_encrypt_key[16];
53 static uint8 sec_decrypt_update_key[16];
54 static uint8 sec_encrypt_update_key[16];
55 static uint8 sec_crypted_random[SEC_MODULUS_SIZE];
56
57 uint16 g_server_rdp_version = 0;
58
59 /*
60 * I believe this is based on SSLv3 with the following differences:
61 * MAC algorithm (5.2.3.1) uses only 32-bit length in place of seq_num/type/length fields
62 * MAC algorithm uses SHA1 and MD5 for the two hash functions instead of one or other
63 * key_block algorithm (6.2.2) uses 'X', 'YY', 'ZZZ' instead of 'A', 'BB', 'CCC'
64 * key_block partitioning is different (16 bytes each: MAC secret, decrypt key, encrypt key)
65 * encryption/decryption keys updated every 4096 packets
66 * See http://wp.netscape.com/eng/ssl3/draft302.txt
67 */
68
69 /*
70 * 48-byte transformation used to generate master secret (6.1) and key material (6.2.2).
71 * Both SHA1 and MD5 algorithms are used.
72 */
73 void
74 sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt)
75 {
76 uint8 shasig[20];
77 uint8 pad[4];
78 SHA_CTX sha;
79 MD5_CTX md5;
80 int i;
81
82 for (i = 0; i < 3; i++)
83 {
84 memset(pad, salt + i, i + 1);
85
86 SHA1_Init(&sha);
87 SHA1_Update(&sha, pad, i + 1);
88 SHA1_Update(&sha, in, 48);
89 SHA1_Update(&sha, salt1, 32);
90 SHA1_Update(&sha, salt2, 32);
91 SHA1_Final(shasig, &sha);
92
93 MD5_Init(&md5);
94 MD5_Update(&md5, in, 48);
95 MD5_Update(&md5, shasig, 20);
96 MD5_Final(&out[i * 16], &md5);
97 }
98 }
99
100 /*
101 * 16-byte transformation used to generate export keys (6.2.2).
102 */
103 void
104 sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2)
105 {
106 MD5_CTX md5;
107
108 MD5_Init(&md5);
109 MD5_Update(&md5, in, 16);
110 MD5_Update(&md5, salt1, 32);
111 MD5_Update(&md5, salt2, 32);
112 MD5_Final(out, &md5);
113 }
114
115 /* Reduce key entropy from 64 to 40 bits */
116 static void
117 sec_make_40bit(uint8 * key)
118 {
119 key[0] = 0xd1;
120 key[1] = 0x26;
121 key[2] = 0x9e;
122 }
123
124 /* Generate encryption keys given client and server randoms */
125 static void
126 sec_generate_keys(uint8 * client_random, uint8 * server_random, int rc4_key_size)
127 {
128 uint8 pre_master_secret[48];
129 uint8 master_secret[48];
130 uint8 key_block[48];
131
132 /* Construct pre-master secret */
133 memcpy(pre_master_secret, client_random, 24);
134 memcpy(pre_master_secret + 24, server_random, 24);
135
136 /* Generate master secret and then key material */
137 sec_hash_48(master_secret, pre_master_secret, client_random, server_random, 'A');
138 sec_hash_48(key_block, master_secret, client_random, server_random, 'X');
139
140 /* First 16 bytes of key material is MAC secret */
141 memcpy(sec_sign_key, key_block, 16);
142
143 /* Generate export keys from next two blocks of 16 bytes */
144 sec_hash_16(sec_decrypt_key, &key_block[16], client_random, server_random);
145 sec_hash_16(sec_encrypt_key, &key_block[32], client_random, server_random);
146
147 if (rc4_key_size == 1)
148 {
149 DEBUG(("40-bit encryption enabled\n"));
150 sec_make_40bit(sec_sign_key);
151 sec_make_40bit(sec_decrypt_key);
152 sec_make_40bit(sec_encrypt_key);
153 rc4_key_len = 8;
154 }
155 else
156 {
157 DEBUG(("rc_4_key_size == %d, 128-bit encryption enabled\n", rc4_key_size));
158 rc4_key_len = 16;
159 }
160
161 /* Save initial RC4 keys as update keys */
162 memcpy(sec_decrypt_update_key, sec_decrypt_key, 16);
163 memcpy(sec_encrypt_update_key, sec_encrypt_key, 16);
164
165 /* Initialise RC4 state arrays */
166 RC4_set_key(&rc4_decrypt_key, rc4_key_len, sec_decrypt_key);
167 RC4_set_key(&rc4_encrypt_key, rc4_key_len, sec_encrypt_key);
168 }
169
170 static uint8 pad_54[40] = {
171 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
172 54, 54, 54,
173 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
174 54, 54, 54
175 };
176
177 static uint8 pad_92[48] = {
178 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
179 92, 92, 92, 92, 92, 92, 92,
180 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
181 92, 92, 92, 92, 92, 92, 92
182 };
183
184 /* Output a uint32 into a buffer (little-endian) */
185 void
186 buf_out_uint32(uint8 * buffer, uint32 value)
187 {
188 buffer[0] = (value) & 0xff;
189 buffer[1] = (value >> 8) & 0xff;
190 buffer[2] = (value >> 16) & 0xff;
191 buffer[3] = (value >> 24) & 0xff;
192 }
193
194 /* Generate a MAC hash (5.2.3.1), using a combination of SHA1 and MD5 */
195 void
196 sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data, int datalen)
197 {
198 uint8 shasig[20];
199 uint8 md5sig[16];
200 uint8 lenhdr[4];
201 SHA_CTX sha;
202 MD5_CTX md5;
203
204 buf_out_uint32(lenhdr, datalen);
205
206 SHA1_Init(&sha);
207 SHA1_Update(&sha, session_key, keylen);
208 SHA1_Update(&sha, pad_54, 40);
209 SHA1_Update(&sha, lenhdr, 4);
210 SHA1_Update(&sha, data, datalen);
211 SHA1_Final(shasig, &sha);
212
213 MD5_Init(&md5);
214 MD5_Update(&md5, session_key, keylen);
215 MD5_Update(&md5, pad_92, 48);
216 MD5_Update(&md5, shasig, 20);
217 MD5_Final(md5sig, &md5);
218
219 memcpy(signature, md5sig, siglen);
220 }
221
222 /* Update an encryption key */
223 static void
224 sec_update(uint8 * key, uint8 * update_key)
225 {
226 uint8 shasig[20];
227 SHA_CTX sha;
228 MD5_CTX md5;
229 RC4_KEY update;
230
231 SHA1_Init(&sha);
232 SHA1_Update(&sha, update_key, rc4_key_len);
233 SHA1_Update(&sha, pad_54, 40);
234 SHA1_Update(&sha, key, rc4_key_len);
235 SHA1_Final(shasig, &sha);
236
237 MD5_Init(&md5);
238 MD5_Update(&md5, update_key, rc4_key_len);
239 MD5_Update(&md5, pad_92, 48);
240 MD5_Update(&md5, shasig, 20);
241 MD5_Final(key, &md5);
242
243 RC4_set_key(&update, rc4_key_len, key);
244 RC4(&update, rc4_key_len, key, key);
245
246 if (rc4_key_len == 8)
247 sec_make_40bit(key);
248 }
249
250 /* Encrypt data using RC4 */
251 static void
252 sec_encrypt(uint8 * data, int length)
253 {
254 static int use_count;
255
256 if (use_count == 4096)
257 {
258 sec_update(sec_encrypt_key, sec_encrypt_update_key);
259 RC4_set_key(&rc4_encrypt_key, rc4_key_len, sec_encrypt_key);
260 use_count = 0;
261 }
262
263 RC4(&rc4_encrypt_key, length, data, data);
264 use_count++;
265 }
266
267 /* Decrypt data using RC4 */
268 void
269 sec_decrypt(uint8 * data, int length)
270 {
271 static int use_count;
272
273 if (use_count == 4096)
274 {
275 sec_update(sec_decrypt_key, sec_decrypt_update_key);
276 RC4_set_key(&rc4_decrypt_key, rc4_key_len, sec_decrypt_key);
277 use_count = 0;
278 }
279
280 RC4(&rc4_decrypt_key, length, data, data);
281 use_count++;
282 }
283
284 static void
285 reverse(uint8 * p, int len)
286 {
287 int i, j;
288 uint8 temp;
289
290 for (i = 0, j = len - 1; i < j; i++, j--)
291 {
292 temp = p[i];
293 p[i] = p[j];
294 p[j] = temp;
295 }
296 }
297
298 /* Perform an RSA public key encryption operation */
299 static void
300 sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint8 * modulus, uint8 * exponent)
301 {
302 BN_CTX *ctx;
303 BIGNUM mod, exp, x, y;
304 uint8 inr[SEC_MODULUS_SIZE];
305 int outlen;
306
307 reverse(modulus, SEC_MODULUS_SIZE);
308 reverse(exponent, SEC_EXPONENT_SIZE);
309 memcpy(inr, in, len);
310 reverse(inr, len);
311
312 ctx = BN_CTX_new();
313 BN_init(&mod);
314 BN_init(&exp);
315 BN_init(&x);
316 BN_init(&y);
317
318 BN_bin2bn(modulus, SEC_MODULUS_SIZE, &mod);
319 BN_bin2bn(exponent, SEC_EXPONENT_SIZE, &exp);
320 BN_bin2bn(inr, len, &x);
321 BN_mod_exp(&y, &x, &exp, &mod, ctx);
322 outlen = BN_bn2bin(&y, out);
323 reverse(out, outlen);
324 if (outlen < SEC_MODULUS_SIZE)
325 memset(out + outlen, 0, SEC_MODULUS_SIZE - outlen);
326
327 BN_free(&y);
328 BN_clear_free(&x);
329 BN_free(&exp);
330 BN_free(&mod);
331 BN_CTX_free(ctx);
332 }
333
334 /* Initialise secure transport packet */
335 STREAM
336 sec_init(uint32 flags, int maxlen)
337 {
338 int hdrlen;
339 STREAM s;
340
341 if (!g_licence_issued)
342 hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4;
343 else
344 hdrlen = (flags & SEC_ENCRYPT) ? 12 : 0;
345 s = mcs_init(maxlen + hdrlen);
346 s_push_layer(s, sec_hdr, hdrlen);
347
348 return s;
349 }
350
351 /* Transmit secure transport packet over specified channel */
352 void
353 sec_send_to_channel(STREAM s, uint32 flags, uint16 channel)
354 {
355 int datalen;
356
357 s_pop_layer(s, sec_hdr);
358 if (!g_licence_issued || (flags & SEC_ENCRYPT))
359 out_uint32_le(s, flags);
360
361 if (flags & SEC_ENCRYPT)
362 {
363 flags &= ~SEC_ENCRYPT;
364 datalen = s->end - s->p - 8;
365
366 #if WITH_DEBUG
367 DEBUG(("Sending encrypted packet:\n"));
368 hexdump(s->p + 8, datalen);
369 #endif
370
371 sec_sign(s->p, 8, sec_sign_key, rc4_key_len, s->p + 8, datalen);
372 sec_encrypt(s->p + 8, datalen);
373 }
374
375 mcs_send_to_channel(s, channel);
376 }
377
378 /* Transmit secure transport packet */
379
380 void
381 sec_send(STREAM s, uint32 flags)
382 {
383 sec_send_to_channel(s, flags, MCS_GLOBAL_CHANNEL);
384 }
385
386
387 /* Transfer the client random to the server */
388 static void
389 sec_establish_key(void)
390 {
391 uint32 length = SEC_MODULUS_SIZE + SEC_PADDING_SIZE;
392 uint32 flags = SEC_CLIENT_RANDOM;
393 STREAM s;
394
395 s = sec_init(flags, 76);
396
397 out_uint32_le(s, length);
398 out_uint8p(s, sec_crypted_random, SEC_MODULUS_SIZE);
399 out_uint8s(s, SEC_PADDING_SIZE);
400
401 s_mark_end(s);
402 sec_send(s, flags);
403 }
404
405 /* Output connect initial data blob */
406 static void
407 sec_out_mcs_data(STREAM s)
408 {
409 int hostlen = 2 * strlen(g_hostname);
410 int length = 158 + 76 + 12 + 4;
411 unsigned int i;
412
413 if (g_num_channels > 0)
414 length += g_num_channels * 12 + 8;
415
416 if (hostlen > 30)
417 hostlen = 30;
418
419 /* Generic Conference Control (T.124) ConferenceCreateRequest */
420 out_uint16_be(s, 5);
421 out_uint16_be(s, 0x14);
422 out_uint8(s, 0x7c);
423 out_uint16_be(s, 1);
424
425 out_uint16_be(s, (length | 0x8000)); /* remaining length */
426
427 out_uint16_be(s, 8); /* length? */
428 out_uint16_be(s, 16);
429 out_uint8(s, 0);
430 out_uint16_le(s, 0xc001);
431 out_uint8(s, 0);
432
433 out_uint32_le(s, 0x61637544); /* OEM ID: "Duca", as in Ducati. */
434 out_uint16_be(s, ((length - 14) | 0x8000)); /* remaining length */
435
436 /* Client information */
437 out_uint16_le(s, SEC_TAG_CLI_INFO);
438 out_uint16_le(s, 212); /* length */
439 out_uint16_le(s, g_use_rdp5 ? 4 : 1); /* RDP version. 1 == RDP4, 4 == RDP5. */
440 out_uint16_le(s, 8);
441 out_uint16_le(s, g_width);
442 out_uint16_le(s, g_height);
443 out_uint16_le(s, 0xca01);
444 out_uint16_le(s, 0xaa03);
445 out_uint32_le(s, g_keylayout);
446 out_uint32_le(s, 2600); /* Client build. We are now 2600 compatible :-) */
447
448 /* Unicode name of client, padded to 32 bytes */
449 rdp_out_unistr(s, g_hostname, hostlen);
450 out_uint8s(s, 30 - hostlen);
451
452 /* See
453 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceddk40/html/cxtsksupportingremotedesktopprotocol.asp */
454 out_uint32_le(s, g_keyboard_type);
455 out_uint32_le(s, g_keyboard_subtype);
456 out_uint32_le(s, g_keyboard_functionkeys);
457 out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */
458 out_uint16_le(s, 0xca01); /* colour depth? */
459 out_uint16_le(s, 1);
460
461 out_uint32(s, 0);
462 out_uint8(s, g_server_bpp);
463 out_uint16_le(s, 0x0700);
464 out_uint8(s, 0);
465 out_uint32_le(s, 1);
466 out_uint8s(s, 64); /* End of client info */
467
468 out_uint16_le(s, SEC_TAG_CLI_4);
469 out_uint16_le(s, 12);
470 out_uint32_le(s, g_console_session ? 0xb : 9);
471 out_uint32(s, 0);
472
473 /* Client encryption settings */
474 out_uint16_le(s, SEC_TAG_CLI_CRYPT);
475 out_uint16_le(s, 12); /* length */
476 out_uint32_le(s, g_encryption ? 0x3 : 0); /* encryption supported, 128-bit supported */
477 out_uint32(s, 0); /* Unknown */
478
479 DEBUG_RDP5(("g_num_channels is %d\n", g_num_channels));
480 if (g_num_channels > 0)
481 {
482 out_uint16_le(s, SEC_TAG_CLI_CHANNELS);
483 out_uint16_le(s, g_num_channels * 12 + 8); /* length */
484 out_uint32_le(s, g_num_channels); /* number of virtual channels */
485 for (i = 0; i < g_num_channels; i++)
486 {
487 DEBUG_RDP5(("Requesting channel %s\n", g_channels[i].name));
488 out_uint8a(s, g_channels[i].name, 8);
489 out_uint32_be(s, g_channels[i].flags);
490 }
491 }
492
493 s_mark_end(s);
494 }
495
496 /* Parse a public key structure */
497 static BOOL
498 sec_parse_public_key(STREAM s, uint8 ** modulus, uint8 ** exponent)
499 {
500 uint32 magic, modulus_len;
501
502 in_uint32_le(s, magic);
503 if (magic != SEC_RSA_MAGIC)
504 {
505 error("RSA magic 0x%x\n", magic);
506 return False;
507 }
508
509 in_uint32_le(s, modulus_len);
510 if (modulus_len != SEC_MODULUS_SIZE + SEC_PADDING_SIZE)
511 {
512 error("modulus len 0x%x\n", modulus_len);
513 return False;
514 }
515
516 in_uint8s(s, 8); /* modulus_bits, unknown */
517 in_uint8p(s, *exponent, SEC_EXPONENT_SIZE);
518 in_uint8p(s, *modulus, SEC_MODULUS_SIZE);
519 in_uint8s(s, SEC_PADDING_SIZE);
520
521 return s_check(s);
522 }
523
524 static BOOL
525 sec_parse_x509_key(X509 * cert)
526 {
527 EVP_PKEY *epk = NULL;
528 /* By some reason, Microsoft sets the OID of the Public RSA key to
529 the oid for "MD5 with RSA Encryption" instead of "RSA Encryption"
530
531 Kudos to Richard Levitte for the following (. intiutive .)
532 lines of code that resets the OID and let's us extract the key. */
533 if (OBJ_obj2nid(cert->cert_info->key->algor->algorithm) == NID_md5WithRSAEncryption)
534 {
535 DEBUG_RDP5(("Re-setting algorithm type to RSA in server certificate\n"));
536 cert->cert_info->key->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption);
537 }
538 epk = X509_get_pubkey(cert);
539 if (NULL == epk)
540 {
541 error("Failed to extract public key from certificate\n");
542 return False;
543 }
544
545 server_public_key = (RSA *) epk->pkey.ptr;
546
547 return True;
548 }
549
550
551 /* Parse a crypto information structure */
552 static BOOL
553 sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
554 uint8 ** server_random, uint8 ** modulus, uint8 ** exponent)
555 {
556 uint32 crypt_level, random_len, rsa_info_len;
557 uint32 cacert_len, cert_len, flags;
558 X509 *cacert, *server_cert;
559 uint16 tag, length;
560 uint8 *next_tag, *end;
561
562 in_uint32_le(s, *rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */
563 in_uint32_le(s, crypt_level); /* 1 = low, 2 = medium, 3 = high */
564 if (crypt_level == 0) /* no encryption */
565 return False;
566 in_uint32_le(s, random_len);
567 in_uint32_le(s, rsa_info_len);
568
569 if (random_len != SEC_RANDOM_SIZE)
570 {
571 error("random len %d, expected %d\n", random_len, SEC_RANDOM_SIZE);
572 return False;
573 }
574
575 in_uint8p(s, *server_random, random_len);
576
577 /* RSA info */
578 end = s->p + rsa_info_len;
579 if (end > s->end)
580 return False;
581
582 in_uint32_le(s, flags); /* 1 = RDP4-style, 0x80000002 = X.509 */
583 if (flags & 1)
584 {
585 DEBUG_RDP5(("We're going for the RDP4-style encryption\n"));
586 in_uint8s(s, 8); /* unknown */
587
588 while (s->p < end)
589 {
590 in_uint16_le(s, tag);
591 in_uint16_le(s, length);
592
593 next_tag = s->p + length;
594
595 switch (tag)
596 {
597 case SEC_TAG_PUBKEY:
598 if (!sec_parse_public_key(s, modulus, exponent))
599 return False;
600 DEBUG_RDP5(("Got Public key, RDP4-style\n"));
601
602 break;
603
604 case SEC_TAG_KEYSIG:
605 /* Is this a Microsoft key that we just got? */
606 /* Care factor: zero! */
607 /* Actually, it would probably be a good idea to check if the public key is signed with this key, and then store this
608 key as a known key of the hostname. This would prevent some MITM-attacks. */
609 break;
610
611 default:
612 unimpl("crypt tag 0x%x\n", tag);
613 }
614
615 s->p = next_tag;
616 }
617 }
618 else
619 {
620 uint32 certcount;
621
622 DEBUG_RDP5(("We're going for the RDP5-style encryption\n"));
623 in_uint32_le(s, certcount); /* Number of certificates */
624
625 if (certcount < 2)
626 {
627 error("Server didn't send enough X509 certificates\n");
628 return False;
629 }
630
631 for (; certcount > 2; certcount--)
632 { /* ignore all the certificates between the root and the signing CA */
633 uint32 ignorelen;
634 X509 *ignorecert;
635
636 DEBUG_RDP5(("Ignored certs left: %d\n", certcount));
637
638 in_uint32_le(s, ignorelen);
639 DEBUG_RDP5(("Ignored Certificate length is %d\n", ignorelen));
640 ignorecert = d2i_X509(NULL, &(s->p), ignorelen);
641
642 if (ignorecert == NULL)
643 { /* XXX: error out? */
644 DEBUG_RDP5(("got a bad cert: this will probably screw up the rest of the communication\n"));
645 }
646
647 #ifdef WITH_DEBUG_RDP5
648 DEBUG_RDP5(("cert #%d (ignored):\n", certcount));
649 X509_print_fp(stdout, ignorecert);
650 #endif
651 }
652
653 /* Do da funky X.509 stuffy
654
655 "How did I find out about this? I looked up and saw a
656 bright light and when I came to I had a scar on my forehead
657 and knew about X.500"
658 - Peter Gutman in a early version of
659 http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
660 */
661
662 in_uint32_le(s, cacert_len);
663 DEBUG_RDP5(("CA Certificate length is %d\n", cacert_len));
664 cacert = d2i_X509(NULL, &(s->p), cacert_len);
665 /* Note: We don't need to move s->p here - d2i_X509 is
666 "kind" enough to do it for us */
667 if (NULL == cacert)
668 {
669 error("Couldn't load CA Certificate from server\n");
670 return False;
671 }
672
673 /* Currently, we don't use the CA Certificate.
674 FIXME:
675 *) Verify the server certificate (server_cert) with the
676 CA certificate.
677 *) Store the CA Certificate with the hostname of the
678 server we are connecting to as key, and compare it
679 when we connect the next time, in order to prevent
680 MITM-attacks.
681 */
682
683 in_uint32_le(s, cert_len);
684 DEBUG_RDP5(("Certificate length is %d\n", cert_len));
685 server_cert = d2i_X509(NULL, &(s->p), cert_len);
686 if (NULL == server_cert)
687 {
688 error("Couldn't load Certificate from server\n");
689 return False;
690 }
691
692 in_uint8s(s, 16); /* Padding */
693
694 /* Note: Verifying the server certificate must be done here,
695 before sec_parse_public_key since we'll have to apply
696 serious violence to the key after this */
697
698 if (!sec_parse_x509_key(server_cert))
699 {
700 DEBUG_RDP5(("Didn't parse X509 correctly\n"));
701 return False;
702 }
703 return True; /* There's some garbage here we don't care about */
704 }
705 return s_check_end(s);
706 }
707
708 /* Process crypto information blob */
709 static void
710 sec_process_crypt_info(STREAM s)
711 {
712 uint8 *server_random, *modulus, *exponent;
713 uint8 client_random[SEC_RANDOM_SIZE];
714 uint32 rc4_key_size;
715 uint8 inr[SEC_MODULUS_SIZE];
716
717 if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, &modulus, &exponent))
718 {
719 DEBUG(("Failed to parse crypt info\n"));
720 return;
721 }
722
723 DEBUG(("Generating client random\n"));
724 /* Generate a client random, and hence determine encryption keys */
725 /* This is what the MS client do: */
726 memset(inr, 0, SEC_RANDOM_SIZE);
727 /* *ARIGL!* Plaintext attack, anyone?
728 I tried doing:
729 generate_random(inr);
730 ..but that generates connection errors now and then (yes,
731 "now and then". Something like 0 to 3 attempts needed before a
732 successful connection. Nice. Not!
733 */
734
735 generate_random(client_random);
736 if (NULL != server_public_key)
737 { /* Which means we should use
738 RDP5-style encryption */
739
740 memcpy(inr + SEC_RANDOM_SIZE, client_random, SEC_RANDOM_SIZE);
741 reverse(inr + SEC_RANDOM_SIZE, SEC_RANDOM_SIZE);
742
743 RSA_public_encrypt(SEC_MODULUS_SIZE,
744 inr, sec_crypted_random, server_public_key, RSA_NO_PADDING);
745
746 reverse(sec_crypted_random, SEC_MODULUS_SIZE);
747
748 }
749 else
750 { /* RDP4-style encryption */
751 sec_rsa_encrypt(sec_crypted_random,
752 client_random, SEC_RANDOM_SIZE, modulus, exponent);
753 }
754 sec_generate_keys(client_random, server_random, rc4_key_size);
755 }
756
757
758 /* Process SRV_INFO, find RDP version supported by server */
759 static void
760 sec_process_srv_info(STREAM s)
761 {
762 in_uint16_le(s, g_server_rdp_version);
763 DEBUG_RDP5(("Server RDP version is %d\n", g_server_rdp_version));
764 if (1 == g_server_rdp_version)
765 {
766 g_use_rdp5 = 0;
767 g_server_bpp = 8;
768 }
769 }
770
771
772 /* Process connect response data blob */
773 void
774 sec_process_mcs_data(STREAM s)
775 {
776 uint16 tag, length;
777 uint8 *next_tag;
778 uint8 len;
779
780 in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */
781 in_uint8(s, len);
782 if (len & 0x80)
783 in_uint8(s, len);
784
785 while (s->p < s->end)
786 {
787 in_uint16_le(s, tag);
788 in_uint16_le(s, length);
789
790 if (length <= 4)
791 return;
792
793 next_tag = s->p + length - 4;
794
795 switch (tag)
796 {
797 case SEC_TAG_SRV_INFO:
798 sec_process_srv_info(s);
799 break;
800
801 case SEC_TAG_SRV_CRYPT:
802 sec_process_crypt_info(s);
803 break;
804
805 case SEC_TAG_SRV_CHANNELS:
806 /* FIXME: We should parse this information and
807 use it to map RDP5 channels to MCS
808 channels */
809 break;
810
811 default:
812 unimpl("response tag 0x%x\n", tag);
813 }
814
815 s->p = next_tag;
816 }
817 }
818
819 /* Receive secure transport packet */
820 STREAM
821 sec_recv(uint8 * rdpver)
822 {
823 uint32 sec_flags;
824 uint16 channel;
825 STREAM s;
826
827 while ((s = mcs_recv(&channel, rdpver)) != NULL)
828 {
829 if (rdpver != NULL)
830 {
831 if (*rdpver != 3)
832 {
833 if (*rdpver & 0x80)
834 {
835 in_uint8s(s, 8); /* signature */
836 sec_decrypt(s->p, s->end - s->p);
837 }
838 return s;
839 }
840 }
841 if (g_encryption || !g_licence_issued)
842 {
843 in_uint32_le(s, sec_flags);
844
845 if (sec_flags & SEC_ENCRYPT)
846 {
847 in_uint8s(s, 8); /* signature */
848 sec_decrypt(s->p, s->end - s->p);
849 }
850
851 if (sec_flags & SEC_LICENCE_NEG)
852 {
853 licence_process(s);
854 continue;
855 }
856 }
857
858 if (channel != MCS_GLOBAL_CHANNEL)
859 {
860 channel_process(s, channel);
861 *rdpver = 0xff;
862 return s;
863 }
864
865 return s;
866 }
867
868 return NULL;
869 }
870
871 /* Establish a secure connection */
872 BOOL
873 sec_connect(char *server, char *username)
874 {
875 struct stream mcs_data;
876
877 /* We exchange some RDP data during the MCS-Connect */
878 mcs_data.size = 512;
879 mcs_data.p = mcs_data.data = (uint8 *) xmalloc(mcs_data.size);
880 sec_out_mcs_data(&mcs_data);
881
882 if (!mcs_connect(server, &mcs_data, username))
883 return False;
884
885 /* sec_process_mcs_data(&mcs_data); */
886 if (g_encryption)
887 sec_establish_key();
888 xfree(mcs_data.data);
889 return True;
890 }
891
892 /* Disconnect a connection */
893 void
894 sec_disconnect(void)
895 {
896 mcs_disconnect();
897 }

  ViewVC Help
Powered by ViewVC 1.1.26