/[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 540 - (show annotations)
Fri Oct 31 20:34:26 2003 UTC (20 years, 6 months ago) by astrand
File MIME type: text/plain
File size: 20460 byte(s)
Replaced C++ comments with C-style

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

  ViewVC Help
Powered by ViewVC 1.1.26