Fill in some blanks on our crypto header. Change to tsstud again for protodiff.
[rdpsrv] / mcs.c
1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Protocol services - Multipoint Communications Service
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 uint16 g_mcs_userid;
24 extern VCHANNEL g_channels[];
25 extern unsigned int g_num_channels;
26
27 /* Parse an ASN.1 BER header */
28 static BOOL
29 ber_parse_header(STREAM s, int tagval, int *length)
30 {
31         int tag, len;
32
33         if (tagval > 0xff)
34         {
35                 in_uint16_be(s, tag);
36         }
37         else
38         {
39         in_uint8(s, tag)}
40
41         if (tag != tagval)
42         {
43                 error("expected tag %d, got %d\n", tagval, tag);
44                 return False;
45         }
46
47         in_uint8(s, len);
48
49         if (len & 0x80)
50         {
51                 len &= ~0x80;
52                 *length = 0;
53                 while (len--)
54                         next_be(s, *length);
55         }
56         else
57                 *length = len;
58
59         return s_check(s);
60 }
61
62 /* Output an ASN.1 BER header */
63 static void
64 ber_out_header(STREAM s, int tagval, int length)
65 {
66         if (tagval > 0xff)
67         {
68                 out_uint16_be(s, tagval);
69         }
70         else
71         {
72                 out_uint8(s, tagval);
73         }
74
75         if (length >= 0x80)
76         {
77                 out_uint8(s, 0x82);
78                 out_uint16_be(s, length);
79         }
80         else
81                 out_uint8(s, length);
82 }
83
84 /* Output an ASN.1 BER integer */
85 static void
86 ber_out_integer(STREAM s, int value)
87 {
88         ber_out_header(s, BER_TAG_INTEGER, 2);
89         out_uint16_be(s, value);
90 }
91
92 static void
93 ber_out_uint8(STREAM s, uint8 value)
94 {
95         ber_out_header(s, BER_TAG_INTEGER, 1);
96         out_uint8(s, value);
97 }
98
99 static void
100 ber_in_integer(STREAM s, int *value)
101 {
102         int length;
103         ber_parse_header(s, BER_TAG_INTEGER, &length);
104         in_uint16_be(s, *value);
105 }
106
107 /* Output a DOMAIN_PARAMS structure (ASN.1 BER) */
108 static void
109 mcs_out_domain_params(STREAM s, int max_channels, int max_users, int max_tokens, int max_pdusize)
110 {
111         ber_out_header(s, MCS_TAG_DOMAIN_PARAMS, 26);
112         ber_out_uint8(s, 34); // max_channels
113         ber_out_uint8(s, 3);  // max_users
114         ber_out_uint8(s, 0);  // max_tokens
115         ber_out_uint8(s, 1);  // num_priorities 
116         ber_out_uint8(s, 0);  // min_throughput
117         ber_out_uint8(s, 1);  // max_height
118         ber_out_header(s, BER_TAG_INTEGER, 3); // pdu size
119         out_uint8(s, 0x00);
120         out_uint8(s, 0xff);
121         out_uint8(s, 0xf8);
122         ber_out_uint8(s, 2);  // ver_protocol
123 }
124
125 /* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */
126 static BOOL
127 mcs_parse_domain_params(STREAM s)
128 {
129         int length;
130         int max_channels, max_users, max_tokens, max_pdusize;
131         int num_priorities, min_throughput, max_height;
132         int ver_protocol;
133
134         ber_parse_header(s, MCS_TAG_DOMAIN_PARAMS, &length);
135         printf("MCS_TAG_DOMAIN_PARAMS, len %u (expected 32)\n", length);
136         if (length == 32) {
137                 ber_in_integer(s, &max_channels);
138                 ber_in_integer(s, &max_users);
139                 ber_in_integer(s, &max_tokens);
140                 ber_in_integer(s, &num_priorities);
141                 ber_in_integer(s, &min_throughput);
142                 ber_in_integer(s, &max_height);
143                 ber_in_integer(s, &max_pdusize);
144                 ber_in_integer(s, &ver_protocol);
145
146                 printf("max_channels=%u\n", max_channels);
147                 printf("max_users=%u\n", max_users);
148                 printf("max_tokens=%u\n", max_tokens);
149                 printf("num_priorities=%u\n", num_priorities);
150                 printf("min_throughput=%u\n", min_throughput);
151                 printf("max_pdusize=%u\n", max_pdusize);
152                 printf("ver_protocol=%u\n", ver_protocol);
153         } else {
154                 hexdump(s->p, length);
155                 in_uint8s(s, length);
156         }
157         
158         return s_check(s);
159 }
160
161 /* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */
162 BOOL
163 mcs_recv_connect_initial()
164 {
165         uint8 result;
166         int length;
167         STREAM s;
168         char *buf;
169
170         s = iso_recv();
171         if (s == NULL)
172                 return False;
173
174         ber_parse_header(s, MCS_CONNECT_INITIAL, &length);
175         printf("parsing MCS_CONNECT_INITIAL (len=%u)\n", length);
176         ber_parse_header(s, BER_TAG_OCTET_STRING, &length);   /* calling domain */
177         in_uint8(s, result);
178         ber_parse_header(s, BER_TAG_OCTET_STRING, &length);   /* called domain */
179         in_uint8(s, result);
180         
181         ber_parse_header(s, BER_TAG_BOOLEAN, &length);
182         in_uint8(s, result);
183
184         mcs_parse_domain_params(s);
185         mcs_parse_domain_params(s);
186         mcs_parse_domain_params(s);
187
188         ber_parse_header(s, BER_TAG_OCTET_STRING, &length);
189         in_uint8p(s, buf, length);
190
191         printf("Data from MCS connect: '%*s'\n", length, buf);
192         
193         return s_check_end(s);
194 }
195
196 /* key generated with "openssl genrsa 512 | openssl rsa -text":
197  
198 modulus:
199     00:b1:e0:36:2f:fd:dd:8b:d6:64:e9:2b:14:f8:b9:
200     0b:ba:3b:b7:0a:f1:f3:97:56:93:38:01:2f:d1:31:
201     2d:70:59:de:97:6a:61:3f:cb:a4:b4:12:05:89:14:
202     d9:b0:8a:70:03:b6:f1:ad:c5:b9:19:9b:b9:8f:03:
203     51:bf:fe:f8:e5
204 publicExponent: 65537 (0x10001)
205 privateExponent:
206     00:a4:86:68:58:97:8d:f6:2c:06:06:8d:ac:c6:2a:
207     12:a8:dd:56:ff:2e:b0:4b:08:ee:fe:dc:4a:28:4a:
208     3e:67:2d:8e:08:6b:5f:87:69:a4:c5:a0:e7:50:1a:
209     f0:71:03:46:f2:52:7c:e6:09:40:40:61:51:76:32:
210     f8:28:72:99:41
211 prime1:
212     00:db:46:d9:34:10:ce:0d:f6:f7:48:30:0f:2b:f6:
213     4d:66:40:27:00:97:db:48:77:cd:96:b5:a6:51:81:
214     a1:7c:ad
215 prime2:
216     00:cf:aa:5c:d3:8a:0d:d4:91:a6:40:92:ff:2c:31:
217     d6:f9:08:8d:e8:d2:a8:2f:89:a6:88:2c:61:68:8e:
218     ee:7c:19
219 */
220 unsigned char my_modulus[SEC_MODULUS_SIZE] = {
221         0xe5, 0xf8, 0xfe, 0xbf, 0x51,
222         0x03, 0x8f, 0xb9, 0x9b, 0x19, 0xb9, 0xc5, 0xad, 0xf1, 0xb6, 0x03, 0x70, 0x8a, 0xb0, 0xd9,
223         0x14, 0x89, 0x05, 0x12, 0xb4, 0xa4, 0xcb, 0x3f, 0x61, 0x6a, 0x97, 0xde, 0x59, 0x70, 0x2d,
224         0x31, 0xd1, 0x2f, 0x01, 0x38, 0x93, 0x56, 0x97, 0xf3, 0xf1, 0x0a, 0xb7, 0x3b, 0xba, 0x0b,
225         0xb9, 0xf8, 0x14, 0x2b, 0xe9, 0x64, 0xd6, 0x8b, 0xdd, 0xfd, 0x2f, 0x36, 0xe0, 0xb1
226 };
227 unsigned char my_exponent[SEC_EXPONENT_SIZE] = {
228         0x01, 0x00, 0x01, 0x00
229 };
230 unsigned char my_private_exponent[] = {
231         0x41, 0x99, 0x72, 0x28, 0xf8,
232         0x32, 0x76, 0x51, 0x61, 0x40, 0x40, 0x09, 0xe6, 0x7c, 0x52, 0xf2, 0x46, 0x03, 0x71, 0xf0,
233         0x1a, 0x50, 0xe7, 0xa0, 0xc5, 0xa4, 0x69, 0x87, 0x5f, 0x6b, 0x08, 0x8e, 0x2d, 0x67, 0x3e,
234         0x4a, 0x28, 0x4a, 0xdc, 0xfe, 0xee, 0x08, 0x4b, 0xb0, 0x2e, 0xff, 0x56, 0xdd, 0xa8, 0x12,
235         0x2a, 0xc6, 0xac, 0x8d, 0x06, 0x06, 0x2c, 0xf6, 0x8d, 0x97, 0x58, 0x68, 0x86, 0xa4
236 };
237
238  
239 void
240 mcs_send_connect_response()
241 {
242         STREAM s;
243         int i, length;
244
245         s = iso_init(250);
246         printf("INITLEN: %u\n", s->p - s->iso_hdr);
247
248         ber_out_header(s, MCS_CONNECT_RESPONSE, 245);
249         ber_out_header(s, BER_TAG_RESULT, 1);
250         out_uint8(s, 0);
251
252         ber_out_header(s, BER_TAG_INTEGER, 1);
253         out_uint8(s, 0);  // connect id
254         
255         mcs_out_domain_params(s, 34, 2, 0, 0xffff);  // dumdidum?
256
257         ber_out_header(s, BER_TAG_OCTET_STRING, 207);
258
259         // some unknown header of sorts
260         out_uint8(s, 0x00);
261         out_uint8(s, 0x05);
262         out_uint8(s, 0x00);
263         out_uint8(s, 0x14);
264         out_uint8(s, 0x7c);
265         out_uint8(s, 0x00);
266         out_uint8(s, 0x01);
267         out_uint8(s, 0x2a);
268         out_uint8(s, 0x14);
269         out_uint8(s, 0x76);
270         out_uint8(s, 0x0a); 
271         out_uint8(s, 0x01);
272         out_uint8(s, 0x01);
273         out_uint8(s, 0x00);
274         out_uint8(s, 0x01);
275         out_uint8(s, 0xc0);
276         out_uint8(s, 0x00);
277         out_uint8(s, 0x4d);
278         out_uint8(s, 0x63);
279         out_uint8(s, 0x44);
280         out_uint8(s, 0x6e);
281
282         length = 184;
283         
284         // two bytes of length
285         out_uint8(s, 0x80 | (length >> 7));
286         out_uint8(s, length & 0x7f);
287
288         // server info -- we claim to support RDP5
289         out_uint16_le(s, SEC_TAG_SRV_INFO);
290         out_uint16_le(s, 8);  // length
291         out_uint16_le(s, 4);  // version
292         out_uint16_le(s, 8);  // unknown
293
294         // channel info -- open a few channels
295         out_uint16_le(s, SEC_TAG_SRV_CHANNELS);
296         out_uint16_le(s, 16); // length
297         out_uint16_le(s, 1003);
298         out_uint16_le(s, 3);
299         out_uint16_le(s, 1004);
300         out_uint16_le(s, 1005);
301         out_uint16_le(s, 1006);
302         out_uint16_le(s, 0);
303         
304         // crypto info
305         out_uint16_le(s, SEC_TAG_SRV_CRYPT);
306         out_uint16_le(s, 156); // length
307         out_uint32_le(s, 2); // 128-bit
308         out_uint32_le(s, 3); // high
309
310         out_uint32_le(s, SEC_RANDOM_SIZE); // random_len
311         out_uint32_le(s, 92);              // rsa_info_len
312         out_uint8s(s, SEC_RANDOM_SIZE);    // server_random
313         out_uint32_le(s, 1);               // RDP4-style
314         // unknown
315         out_uint32_le(s, 1);            
316         out_uint32_le(s, 1);
317
318         out_uint16_le(s, SEC_TAG_PUBKEY);
319         out_uint16_le(s, 92);
320         out_uint32_le(s, SEC_RSA_MAGIC);
321         out_uint32_le(s, SEC_MODULUS_SIZE + SEC_PADDING_SIZE);  // modulus_len
322         out_uint32_le(s, SEC_MODULUS_SIZE * 8);                 // modulus_bits
323         out_uint32_le(s, 0x3f);                                 // unknown
324         out_uint8p(s, my_exponent, SEC_EXPONENT_SIZE);
325         out_uint8p(s, my_modulus, SEC_MODULUS_SIZE);
326         out_uint8s(s, SEC_PADDING_SIZE);
327         
328         s_mark_end(s);
329         iso_send(s);
330
331 }
332
333 /* Send an EDrq message (ASN.1 PER) */
334 static void
335 mcs_send_edrq(void)
336 {
337         STREAM s;
338
339         s = iso_init(5);
340
341         out_uint8(s, (MCS_EDRQ << 2));
342         out_uint16_be(s, 1);    /* height */
343         out_uint16_be(s, 1);    /* interval */
344
345         s_mark_end(s);
346         iso_send(s);
347 }
348
349 /* Send an AUrq message (ASN.1 PER) */
350 static void
351 mcs_send_aurq(void)
352 {
353         STREAM s;
354
355         s = iso_init(1);
356
357         out_uint8(s, (MCS_AURQ << 2));
358
359         s_mark_end(s);
360         iso_send(s);
361 }
362
363 /* Send a AUcf message (ASN.1 PER) */
364 static void
365 mcs_send_aucf(uint16 mcs_userid)
366 {
367         STREAM s;
368
369         s = iso_init(4);
370
371         out_uint8(s, (MCS_AUCF << 2) | 2);  // | 2 = send user ID
372         out_uint8(s, 0);  // success
373         out_uint16_be(s, 6);
374         
375         s_mark_end(s);
376         iso_send(s);
377 }
378
379 /* Send a CJrq message (ASN.1 PER) */
380 static void
381 mcs_send_cjrq(uint16 chanid)
382 {
383         STREAM s;
384
385         DEBUG_RDP5(("Sending CJRQ for channel #%d\n", chanid));
386
387         s = iso_init(5);
388
389         out_uint8(s, (MCS_CJRQ << 2));
390         out_uint16_be(s, g_mcs_userid);
391         out_uint16_be(s, chanid);
392
393         s_mark_end(s);
394         iso_send(s);
395 }
396
397 /* Expect a CJcf message (ASN.1 PER) */
398 static void
399 mcs_send_cjcf(uint16 userid, uint16 chanid)
400 {
401         STREAM s;
402
403         s = iso_init(8);
404
405         out_uint8(s, (MCS_CJCF << 2) | 2);
406         out_uint8(s, 0); // success
407         out_uint16_be(s, 6);
408         out_uint16_be(s, chanid);
409         out_uint16_be(s, chanid);
410
411         s_mark_end(s);
412         iso_send(s);
413 }
414
415 /* Initialise an MCS transport data packet */
416 STREAM
417 mcs_init(int length)
418 {
419         STREAM s;
420
421         s = iso_init(length + 8);
422         s_push_layer(s, mcs_hdr, 8);
423
424         return s;
425 }
426
427 /* Send an MCS transport data packet to a specific channel */
428 void
429 mcs_send_to_channel(STREAM s, uint16 channel)
430 {
431         uint16 length;
432
433         s_pop_layer(s, mcs_hdr);
434         length = s->end - s->p - 8;
435         length |= 0x8000;
436
437         out_uint8(s, (MCS_SDIN << 2));
438         out_uint16_be(s, g_mcs_userid);
439         out_uint16_be(s, channel);
440         out_uint8(s, 0x70);     /* flags */
441         out_uint16_be(s, length);
442
443         iso_send(s);
444 }
445
446 /* Send an MCS transport data packet to the global channel */
447 void
448 mcs_send(STREAM s)
449 {
450         mcs_send_to_channel(s, MCS_GLOBAL_CHANNEL);
451 }
452
453 /* Receive an MCS transport data packet */
454 STREAM
455 mcs_recv(uint16 * channel)
456 {
457         uint8 opcode, appid, length, userid;
458         STREAM s;
459
460         s = iso_recv();
461         if (s == NULL)
462                 return NULL;
463
464         in_uint8(s, opcode);
465         appid = opcode >> 2;
466
467         switch (appid) {
468         case MCS_SDRQ:
469                 in_uint8s(s, 2);        /* userid */
470                 in_uint16_be(s, *channel);
471                 in_uint8s(s, 1);        /* flags */
472                 in_uint8(s, length);
473                 if (length & 0x80)
474                         in_uint8s(s, 1);        /* second byte of length */
475
476                 return s;
477         case MCS_DPUM:
478                 printf("Received DPUM (?)\n");
479                 return NULL;
480         case MCS_EDRQ:
481                 // Erect Domain (ignore)
482                 printf("Received EDrq\n");
483                 return NULL;
484         case MCS_AURQ:
485                 // Attach User Request, respond with AUcf (Attach User Confirm)
486                 printf("Received AUrq, sending AUcf\n");
487                 mcs_send_aucf(0);
488                 return NULL;
489         case MCS_CJRQ:
490                 // Channel Join Request, respond with CJcf (Channel Join Confirm);
491                 in_uint16_be(s, userid);
492                 in_uint16_be(s, *channel);
493                 printf("Received CJrq for channel %hu, sending CJcf\n", *channel);
494                 mcs_send_cjcf(userid, *channel);
495                 return NULL;
496         default:
497                 error("expected data, got %d\n", opcode);
498                 return NULL;
499         }
500
501 }
502
503 /* Disconnect from the MCS layer */
504 void
505 mcs_disconnect(void)
506 {
507         iso_disconnect();
508 }