VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.4/cssp.c@ 77807

Last change on this file since 77807 was 76779, checked in by vboxsync, 6 years ago

RDP: add client-1.8.4.
bugref:9356: Update rdesktop-vrdp to 1.8.4
client-1.8.4 is a Subversion copy of 1.8.3 with the upstream 1.8.3 to 1.8.4
patch applied and a couple of fixes and changes after review, namely:

  • Stopped disabling the new pointer data format for our build, as this is no

longer needed.

  • Adjusted some snprintf buffers to make GCC happy.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.2 KB
Line 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 CredSSP layer and kerberos support.
4 Copyright 2012-2013 Henrik Andersson <hean01@cendio.se> for Cendio AB
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 3 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, see <http://www.gnu.org/licenses/>.
18*/
19
20/*
21 * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
22 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
23 * the General Public License version 2 (GPLv2) at this time for any software where
24 * a choice of GPL license versions is made available with the language indicating
25 * that GPLv2 or any later version may be used, or where a choice of which version
26 * of the GPL is applied is otherwise unspecified.
27 */
28
29#include <gssapi/gssapi.h>
30#include "rdesktop.h"
31
32extern RD_BOOL g_use_password_as_pin;
33
34extern char *g_sc_csp_name;
35extern char *g_sc_reader_name;
36extern char *g_sc_card_name;
37extern char *g_sc_container_name;
38
39static gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc =
40 { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
41
42
43static void
44s_realloc(STREAM s, unsigned int size)
45{
46 unsigned char *data;
47
48 if (s->size >= size)
49 return;
50
51 data = s->data;
52 s->size = size;
53 s->data = xrealloc(data, size);
54 s->p = s->data + (s->p - data);
55 s->end = s->data + (s->end - data);
56 s->iso_hdr = s->data + (s->iso_hdr - data);
57 s->mcs_hdr = s->data + (s->mcs_hdr - data);
58 s->sec_hdr = s->data + (s->sec_hdr - data);
59 s->rdp_hdr = s->data + (s->rdp_hdr - data);
60 s->channel_hdr = s->data + (s->channel_hdr - data);
61}
62
63static void
64s_free(STREAM s)
65{
66 free(s->data);
67 free(s);
68}
69
70static STREAM
71ber_wrap_hdr_data(int tagval, STREAM in)
72{
73 STREAM out;
74 int size = s_length(in) + 16;
75
76 out = xmalloc(sizeof(struct stream));
77 memset(out, 0, sizeof(struct stream));
78 out->data = xmalloc(size);
79 out->size = size;
80 out->p = out->data;
81
82 ber_out_header(out, tagval, s_length(in));
83 out_uint8p(out, in->data, s_length(in));
84 s_mark_end(out);
85
86 return out;
87}
88
89
90static void
91cssp_gss_report_error(OM_uint32 code, char *str, OM_uint32 major_status, OM_uint32 minor_status)
92{
93 OM_uint32 msgctx = 0, ms;
94 gss_buffer_desc status_string;
95
96 error("GSS error [%d:%d:%d]: %s\n", (major_status & 0xff000000) >> 24, // Calling error
97 (major_status & 0xff0000) >> 16, // Routine error
98 major_status & 0xffff, // Supplementary info bits
99 str);
100
101 do
102 {
103 ms = gss_display_status(&minor_status, major_status,
104 code, GSS_C_NULL_OID, &msgctx, &status_string);
105 if (ms != GSS_S_COMPLETE)
106 continue;
107
108 error(" - %s\n", status_string.value);
109
110 }
111 while (ms == GSS_S_COMPLETE && msgctx);
112
113}
114
115
116static RD_BOOL
117cssp_gss_mech_available(gss_OID mech)
118{
119 int mech_found;
120 OM_uint32 major_status, minor_status;
121 gss_OID_set mech_set;
122
123 mech_found = 0;
124
125 if (mech == GSS_C_NO_OID)
126 return True;
127
128 major_status = gss_indicate_mechs(&minor_status, &mech_set);
129 if (!mech_set)
130 return False;
131
132 if (GSS_ERROR(major_status))
133 {
134 cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to get available mechs on system",
135 major_status, minor_status);
136 return False;
137 }
138
139 gss_test_oid_set_member(&minor_status, mech, mech_set, &mech_found);
140
141 if (GSS_ERROR(major_status))
142 {
143 cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to match mechanism in set",
144 major_status, minor_status);
145 return False;
146 }
147
148 if (!mech_found)
149 return False;
150
151 return True;
152}
153
154static RD_BOOL
155cssp_gss_get_service_name(char *server, gss_name_t * name)
156{
157 gss_buffer_desc output;
158 OM_uint32 major_status, minor_status;
159
160 const char service_name[] = "TERMSRV";
161
162 gss_OID type = (gss_OID) GSS_C_NT_HOSTBASED_SERVICE;
163 int size = (strlen(service_name) + 1 + strlen(server) + 1);
164
165 output.value = malloc(size);
166 snprintf(output.value, size, "%s@%s", service_name, server);
167 output.length = strlen(output.value) + 1;
168
169 major_status = gss_import_name(&minor_status, &output, type, name);
170
171 if (GSS_ERROR(major_status))
172 {
173 cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to create service principal name",
174 major_status, minor_status);
175 return False;
176 }
177
178 gss_release_buffer(&minor_status, &output);
179
180 return True;
181
182}
183
184static RD_BOOL
185cssp_gss_wrap(gss_ctx_id_t * ctx, STREAM in, STREAM out)
186{
187 int conf_state;
188 OM_uint32 major_status;
189 OM_uint32 minor_status;
190 gss_buffer_desc inbuf, outbuf;
191
192 inbuf.value = in->data;
193 inbuf.length = s_length(in);
194
195 major_status = gss_wrap(&minor_status, ctx, True,
196 GSS_C_QOP_DEFAULT, &inbuf, &conf_state, &outbuf);
197
198 if (major_status != GSS_S_COMPLETE)
199 {
200 cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to encrypt and sign message",
201 major_status, minor_status);
202 return False;
203 }
204
205 if (!conf_state)
206 {
207 error("GSS Confidentiality failed, no encryption of message performed.");
208 return False;
209 }
210
211 // write enc data to out stream
212 out->data = out->p = xmalloc(outbuf.length);
213 out->size = outbuf.length;
214 out_uint8p(out, outbuf.value, outbuf.length);
215 s_mark_end(out);
216
217 gss_release_buffer(&minor_status, &outbuf);
218
219 return True;
220}
221
222static RD_BOOL
223cssp_gss_unwrap(gss_ctx_id_t * ctx, STREAM in, STREAM out)
224{
225 OM_uint32 major_status;
226 OM_uint32 minor_status;
227 gss_qop_t qop_state;
228 gss_buffer_desc inbuf, outbuf;
229 int conf_state;
230
231 inbuf.value = in->data;
232 inbuf.length = s_length(in);
233
234 major_status = gss_unwrap(&minor_status, ctx, &inbuf, &outbuf, &conf_state, &qop_state);
235
236 if (major_status != GSS_S_COMPLETE)
237 {
238 cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to decrypt message",
239 major_status, minor_status);
240 return False;
241 }
242
243 out->data = out->p = xmalloc(outbuf.length);
244 out->size = outbuf.length;
245 out_uint8p(out, outbuf.value, outbuf.length);
246 s_mark_end(out);
247
248 gss_release_buffer(&minor_status, &outbuf);
249
250 return True;
251}
252
253#ifdef WITH_DEBUG_CREDSSP
254void
255streamsave(STREAM s, char *fn)
256{
257 FILE *f = fopen(fn, "wb");
258 fwrite(s->data, s_length(s), 1, f);
259 fclose(f);
260}
261#endif
262
263static STREAM
264cssp_encode_tspasswordcreds(char *username, char *password, char *domain)
265{
266 STREAM out, h1, h2;
267 struct stream tmp = { 0 };
268 struct stream message = { 0 };
269
270 memset(&tmp, 0, sizeof(tmp));
271 memset(&message, 0, sizeof(message));
272
273 // domainName [0]
274 s_realloc(&tmp, 4 + strlen(domain) * sizeof(uint16));
275 s_reset(&tmp);
276 rdp_out_unistr(&tmp, domain, strlen(domain) * sizeof(uint16));
277 s_mark_end(&tmp);
278 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
279 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
280 s_realloc(&message, s_length(&message) + s_length(h1));
281 out_uint8p(&message, h1->data, s_length(h1));
282 s_mark_end(&message);
283 s_free(h2);
284 s_free(h1);
285
286 // userName [1]
287 s_realloc(&tmp, 4 + strlen(username) * sizeof(uint16));
288 s_reset(&tmp);
289 rdp_out_unistr(&tmp, username, strlen(username) * sizeof(uint16));
290 s_mark_end(&tmp);
291
292 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
293 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
294 s_realloc(&message, s_length(&message) + s_length(h1));
295 out_uint8p(&message, h1->data, s_length(h1));
296 s_mark_end(&message);
297 s_free(h2);
298 s_free(h1);
299
300 // password [2]
301 s_realloc(&tmp, 4 + strlen(password) * sizeof(uint16));
302 s_reset(&tmp);
303 rdp_out_unistr(&tmp, password, strlen(password) * sizeof(uint16));
304 s_mark_end(&tmp);
305 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
306 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
307 s_realloc(&message, s_length(&message) + s_length(h1));
308 out_uint8p(&message, h1->data, s_length(h1));
309 s_mark_end(&message);
310 s_free(h2);
311 s_free(h1);
312
313 // build message
314 out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message);
315
316 // cleanup
317 xfree(tmp.data);
318 xfree(message.data);
319 return out;
320}
321
322/* KeySpecs from wincrypt.h */
323#define AT_KEYEXCHANGE 1
324#define AT_SIGNATURE 2
325
326static STREAM
327cssp_encode_tscspdatadetail(unsigned char keyspec, char *card, char *reader, char *container,
328 char *csp)
329{
330 STREAM out;
331 STREAM h1, h2;
332 struct stream tmp = { 0 };
333 struct stream message = { 0 };
334
335 // keySpec [0]
336 s_realloc(&tmp, sizeof(uint8));
337 s_reset(&tmp);
338 out_uint8(&tmp, keyspec);
339 s_mark_end(&tmp);
340 h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
341 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
342 s_realloc(&message, s_length(&message) + s_length(h1));
343 out_uint8p(&message, h1->data, s_length(h1));
344 s_mark_end(&message);
345 s_free(h2);
346 s_free(h1);
347
348 // cardName [1]
349 if (card)
350 {
351 s_realloc(&tmp, 4 + strlen(card) * sizeof(uint16));
352 s_reset(&tmp);
353 rdp_out_unistr(&tmp, card, strlen(card) * sizeof(uint16));
354 s_mark_end(&tmp);
355 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
356 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
357 s_realloc(&message, s_length(&message) + s_length(h1));
358 out_uint8p(&message, h1->data, s_length(h1));
359 s_mark_end(&message);
360 s_free(h2);
361 s_free(h1);
362 }
363
364 // readerName [2]
365 if (reader)
366 {
367 s_realloc(&tmp, 4 + strlen(reader) * sizeof(uint16));
368 s_reset(&tmp);
369 rdp_out_unistr(&tmp, reader, strlen(reader) * sizeof(uint16));
370 s_mark_end(&tmp);
371 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
372 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
373 s_realloc(&message, s_length(&message) + s_length(h1));
374 out_uint8p(&message, h1->data, s_length(h1));
375 s_mark_end(&message);
376 s_free(h2);
377 s_free(h1);
378 }
379
380 // containerName [3]
381 if (container)
382 {
383 s_realloc(&tmp, 4 + strlen(container) * sizeof(uint16));
384 s_reset(&tmp);
385 rdp_out_unistr(&tmp, container, strlen(container) * sizeof(uint16));
386 s_mark_end(&tmp);
387 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
388 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
389 s_realloc(&message, s_length(&message) + s_length(h1));
390 out_uint8p(&message, h1->data, s_length(h1));
391 s_mark_end(&message);
392 s_free(h2);
393 s_free(h1);
394 }
395
396 // cspName [4]
397 if (csp)
398 {
399 s_realloc(&tmp, 4 + strlen(csp) * sizeof(uint16));
400 s_reset(&tmp);
401 rdp_out_unistr(&tmp, csp, strlen(csp) * sizeof(uint16));
402 s_mark_end(&tmp);
403 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
404 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 4, h2);
405 s_realloc(&message, s_length(&message) + s_length(h1));
406 out_uint8p(&message, h1->data, s_length(h1));
407 s_mark_end(&message);
408 s_free(h2);
409 s_free(h1);
410 }
411
412 s_mark_end(&message);
413
414 // build message
415 out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message);
416
417 // cleanup
418 free(tmp.data);
419 free(message.data);
420 return out;
421}
422
423static STREAM
424cssp_encode_tssmartcardcreds(char *username, char *password, char *domain)
425{
426 STREAM out, h1, h2;
427 struct stream tmp = { 0 };
428 struct stream message = { 0 };
429
430 // pin [0]
431 s_realloc(&tmp, strlen(password) * sizeof(uint16));
432 s_reset(&tmp);
433 rdp_out_unistr(&tmp, password, strlen(password) * sizeof(uint16));
434 s_mark_end(&tmp);
435 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
436 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
437 s_realloc(&message, s_length(&message) + s_length(h1));
438 out_uint8p(&message, h1->data, s_length(h1));
439 s_mark_end(&message);
440 s_free(h2);
441 s_free(h1);
442
443 // cspData[1]
444 h2 = cssp_encode_tscspdatadetail(AT_KEYEXCHANGE, g_sc_card_name, g_sc_reader_name,
445 g_sc_container_name, g_sc_csp_name);
446 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
447 s_realloc(&message, s_length(&message) + s_length(h1));
448 out_uint8p(&message, h1->data, s_length(h1));
449 s_mark_end(&message);
450 s_free(h2);
451 s_free(h1);
452
453 // userHint [2]
454 if (username && strlen(username))
455 {
456 s_realloc(&tmp, strlen(username) * sizeof(uint16));
457 s_reset(&tmp);
458 rdp_out_unistr(&tmp, username, strlen(username) * sizeof(uint16));
459 s_mark_end(&tmp);
460 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
461 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
462 s_realloc(&message, s_length(&message) + s_length(h1));
463 out_uint8p(&message, h1->data, s_length(h1));
464 s_mark_end(&message);
465 s_free(h2);
466 s_free(h1);
467 }
468
469 // domainHint [3]
470 if (domain && strlen(domain))
471 {
472 s_realloc(&tmp, strlen(domain) * sizeof(uint16));
473 s_reset(&tmp);
474 rdp_out_unistr(&tmp, domain, strlen(domain) * sizeof(uint16));
475 s_mark_end(&tmp);
476 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
477 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
478 s_realloc(&message, s_length(&message) + s_length(h1));
479 out_uint8p(&message, h1->data, s_length(h1));
480 s_mark_end(&message);
481 s_free(h2);
482 s_free(h1);
483 }
484
485 s_mark_end(&message);
486
487 // build message
488 out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message);
489
490 // cleanup
491 free(tmp.data);
492 free(message.data);
493 return out;
494}
495
496STREAM
497cssp_encode_tscredentials(char *username, char *password, char *domain)
498{
499 STREAM out;
500 STREAM h1, h2, h3;
501 struct stream tmp = { 0 };
502 struct stream message = { 0 };
503
504 // credType [0]
505 s_realloc(&tmp, sizeof(uint8));
506 s_reset(&tmp);
507 if (g_use_password_as_pin == False)
508 {
509 out_uint8(&tmp, 1); // TSPasswordCreds
510 }
511 else
512 {
513 out_uint8(&tmp, 2); // TSSmartCardCreds
514 }
515
516 s_mark_end(&tmp);
517 h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
518 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
519 s_realloc(&message, s_length(&message) + s_length(h1));
520 out_uint8p(&message, h1->data, s_length(h1));
521 s_mark_end(&message);
522 s_free(h2);
523 s_free(h1);
524
525 // credentials [1]
526 if (g_use_password_as_pin == False)
527 {
528 h3 = cssp_encode_tspasswordcreds(username, password, domain);
529 }
530 else
531 {
532 h3 = cssp_encode_tssmartcardcreds(username, password, domain);
533 }
534
535 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, h3);
536 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
537 s_realloc(&message, s_length(&message) + s_length(h1));
538 out_uint8p(&message, h1->data, s_length(h1));
539 s_mark_end(&message);
540 s_free(h3);
541 s_free(h2);
542 s_free(h1);
543
544 // Construct ASN.1 message
545 out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message);
546
547#if WITH_DEBUG_CREDSSP
548 streamsave(out, "tscredentials.raw");
549 printf("Out TSCredentials %ld bytes\n", s_length(out));
550 hexdump(out->data, s_length(out));
551#endif
552
553 // cleanup
554 xfree(message.data);
555 xfree(tmp.data);
556
557 return out;
558}
559
560RD_BOOL
561cssp_send_tsrequest(STREAM token, STREAM auth, STREAM pubkey)
562{
563 STREAM s;
564 STREAM h1, h2, h3, h4, h5;
565
566 struct stream tmp = { 0 };
567 struct stream message = { 0 };
568
569 memset(&message, 0, sizeof(message));
570 memset(&tmp, 0, sizeof(tmp));
571
572 // version [0]
573 s_realloc(&tmp, sizeof(uint8));
574 s_reset(&tmp);
575 out_uint8(&tmp, 2);
576 s_mark_end(&tmp);
577 h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
578 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
579 s_realloc(&message, s_length(&message) + s_length(h1));
580 out_uint8p(&message, h1->data, s_length(h1));
581 s_mark_end(&message);
582 s_free(h2);
583 s_free(h1);
584
585 // negoToken [1]
586 if (token && s_length(token))
587 {
588 h5 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, token);
589 h4 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h5);
590 h3 = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, h4);
591 h2 = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, h3);
592 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
593 s_realloc(&message, s_length(&message) + s_length(h1));
594 out_uint8p(&message, h1->data, s_length(h1));
595 s_mark_end(&message);
596 s_free(h5);
597 s_free(h4);
598 s_free(h3);
599 s_free(h2);
600 s_free(h1);
601 }
602
603 // authInfo [2]
604 if (auth && s_length(auth))
605 {
606 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, auth);
607 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
608
609 s_realloc(&message, s_length(&message) + s_length(h1));
610 out_uint8p(&message, h1->data, s_length(h1));
611
612 s_free(h2);
613 s_free(h1);
614 }
615
616 // pubKeyAuth [3]
617 if (pubkey && s_length(pubkey))
618 {
619 h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, pubkey);
620 h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
621
622 s_realloc(&message, s_length(&message) + s_length(h1));
623 out_uint8p(&message, h1->data, s_length(h1));
624 s_mark_end(&message);
625 s_free(h2);
626 s_free(h1);
627 }
628 s_mark_end(&message);
629
630 // Construct ASN.1 Message
631 // Todo: can h1 be send directly instead of tcp_init() approach
632 h1 = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message);
633 s = tcp_init(s_length(h1));
634 out_uint8p(s, h1->data, s_length(h1));
635 s_mark_end(s);
636 s_free(h1);
637
638#if WITH_DEBUG_CREDSSP
639 streamsave(s, "tsrequest_out.raw");
640 printf("Out TSRequest %ld bytes\n", s_length(s));
641 hexdump(s->data, s_length(s));
642#endif
643
644 tcp_send(s);
645
646 // cleanup
647 xfree(message.data);
648 xfree(tmp.data);
649
650 return True;
651}
652
653
654RD_BOOL
655cssp_read_tsrequest(STREAM token, STREAM pubkey)
656{
657 STREAM s;
658 int length;
659 int tagval;
660 struct stream packet;
661
662 s = tcp_recv(NULL, 4);
663
664 if (s == NULL)
665 return False;
666
667 // verify ASN.1 header
668 if (s->p[0] != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
669 {
670 error("Expected BER_TAG_SEQUENCE|BER_TAG_CONSTRUCTED, got %x", s->p[0]);
671 return False;
672 }
673
674 // peek at first 4 bytes to get full message length
675 if (s->p[1] < 0x80)
676 length = s->p[1] - 2;
677 else if (s->p[1] == 0x81)
678 length = s->p[2] - 1;
679 else if (s->p[1] == 0x82)
680 length = (s->p[2] << 8) | s->p[3];
681 else
682 return False;
683
684 // receive the remainings of message
685 s = tcp_recv(s, length);
686 packet = *s;
687
688#if WITH_DEBUG_CREDSSP
689 streamsave(s, "tsrequest_in.raw");
690 printf("In TSRequest token %ld bytes\n", s_length(s));
691 hexdump(s->data, s_length(s));
692#endif
693
694 // parse the response and into nego token
695 if (!ber_in_header(s, &tagval, &length) ||
696 tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
697 return False;
698
699 // version [0]
700 if (!ber_in_header(s, &tagval, &length) ||
701 tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0))
702 return False;
703
704 if (!s_check_rem(s, length))
705 {
706 rdp_protocol_error("cssp_read_tsrequest(), consume of version from stream would overrun",
707 &packet);
708 }
709 in_uint8s(s, length);
710
711 // negoToken [1]
712 if (token)
713 {
714 if (!ber_in_header(s, &tagval, &length)
715 || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1))
716 return False;
717 if (!ber_in_header(s, &tagval, &length)
718 || tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
719 return False;
720 if (!ber_in_header(s, &tagval, &length)
721 || tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
722 return False;
723 if (!ber_in_header(s, &tagval, &length)
724 || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0))
725 return False;
726
727 if (!ber_in_header(s, &tagval, &length) || tagval != BER_TAG_OCTET_STRING)
728 return False;
729
730 if (!s_check_rem(s, length))
731 {
732 rdp_protocol_error("cssp_read_tsrequest(), consume of token from stream would overrun",
733 &packet);
734 }
735
736 s_realloc(token, length);
737 s_reset(token);
738 out_uint8p(token, s->p, length);
739 s_mark_end(token);
740 }
741
742 // pubKey [3]
743 if (pubkey)
744 {
745 if (!ber_in_header(s, &tagval, &length)
746 || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3))
747 return False;
748
749 if (!ber_in_header(s, &tagval, &length) || tagval != BER_TAG_OCTET_STRING)
750 return False;
751
752 pubkey->data = pubkey->p = s->p;
753 pubkey->end = pubkey->data + length;
754 pubkey->size = length;
755 }
756
757
758 return True;
759}
760
761RD_BOOL
762cssp_connect(char *server, char *user, char *domain, char *password, STREAM s)
763{
764 OM_uint32 actual_time;
765 gss_cred_id_t cred;
766 gss_buffer_desc input_tok, output_tok;
767 gss_name_t target_name;
768 OM_uint32 major_status, minor_status;
769 int context_established = 0;
770 gss_ctx_id_t gss_ctx;
771 gss_OID desired_mech = &_gss_spnego_krb5_mechanism_oid_desc;
772
773 STREAM ts_creds;
774 struct stream token = { 0 };
775 struct stream pubkey = { 0 };
776 struct stream pubkey_cmp = { 0 };
777
778 // Verify that system gss support spnego
779 if (!cssp_gss_mech_available(desired_mech))
780 {
781 warning("CredSSP: System doesn't have support for desired authentication mechanism.\n");
782 return False;
783 }
784
785 // Get service name
786 if (!cssp_gss_get_service_name(server, &target_name))
787 {
788 warning("CredSSP: Failed to get target service name.\n");
789 return False;
790 }
791
792 // Establish tls connection to server
793 if (!tcp_tls_connect())
794 {
795 warning("CredSSP: Failed to establish TLS connection.\n");
796 return False;
797 }
798
799 tcp_tls_get_server_pubkey(&pubkey);
800
801#ifdef WITH_DEBUG_CREDSSP
802 streamsave(&pubkey, "PubKey.raw");
803#endif
804
805 // Enter the spnego loop
806 OM_uint32 actual_services;
807 gss_OID actual_mech;
808 struct stream blob = { 0 };
809
810 gss_ctx = GSS_C_NO_CONTEXT;
811 cred = GSS_C_NO_CREDENTIAL;
812
813 input_tok.length = 0;
814 output_tok.length = 0;
815 minor_status = 0;
816
817 int i = 0;
818
819 do
820 {
821 major_status = gss_init_sec_context(&minor_status,
822 cred,
823 &gss_ctx,
824 target_name,
825 desired_mech,
826 GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG,
827 GSS_C_INDEFINITE,
828 GSS_C_NO_CHANNEL_BINDINGS,
829 &input_tok,
830 &actual_mech,
831 &output_tok, &actual_services, &actual_time);
832
833 if (GSS_ERROR(major_status))
834 {
835 if (i == 0)
836 error("CredSSP: Initialize failed, do you have correct kerberos tgt initialized ?\n");
837 else
838 error("CredSSP: Negotiation failed.\n");
839
840#ifdef WITH_DEBUG_CREDSSP
841 cssp_gss_report_error(GSS_C_GSS_CODE, "CredSSP: SPNEGO negotiation failed.",
842 major_status, minor_status);
843#endif
844 goto bail_out;
845 }
846
847 // validate required services
848 if (!(actual_services & GSS_C_CONF_FLAG))
849 {
850 error("CredSSP: Confidiality service required but is not available.\n");
851 goto bail_out;
852 }
853
854 // Send token to server
855 if (output_tok.length != 0)
856 {
857 if (output_tok.length > token.size)
858 s_realloc(&token, output_tok.length);
859 s_reset(&token);
860
861 out_uint8p(&token, output_tok.value, output_tok.length);
862 s_mark_end(&token);
863
864 if (!cssp_send_tsrequest(&token, NULL, NULL))
865 goto bail_out;
866
867 (void) gss_release_buffer(&minor_status, &output_tok);
868 }
869
870 // Read token from server
871 if (major_status & GSS_S_CONTINUE_NEEDED)
872 {
873 (void) gss_release_buffer(&minor_status, &input_tok);
874
875 if (!cssp_read_tsrequest(&token, NULL))
876 goto bail_out;
877
878 input_tok.value = token.data;
879 input_tok.length = s_length(&token);
880 }
881 else
882 {
883 // Send encrypted pubkey for verification to server
884 context_established = 1;
885
886 if (!cssp_gss_wrap(gss_ctx, &pubkey, &blob))
887 goto bail_out;
888
889 if (!cssp_send_tsrequest(NULL, NULL, &blob))
890 goto bail_out;
891
892 context_established = 1;
893 }
894
895 i++;
896
897 }
898 while (!context_established);
899
900 // read tsrequest response and decrypt for public key validation
901 if (!cssp_read_tsrequest(NULL, &blob))
902 goto bail_out;
903
904 if (!cssp_gss_unwrap(gss_ctx, &blob, &pubkey_cmp))
905 goto bail_out;
906
907 pubkey_cmp.data[0] -= 1;
908
909 // validate public key
910 if (memcmp(pubkey.data, pubkey_cmp.data, s_length(&pubkey)) != 0)
911 {
912 error("CredSSP: Cannot guarantee integrity of server connection, MITM ? "
913 "(public key data mismatch)\n");
914 goto bail_out;
915 }
916
917 // Send TSCredentials
918 ts_creds = cssp_encode_tscredentials(user, password, domain);
919
920 if (!cssp_gss_wrap(gss_ctx, ts_creds, &blob))
921 goto bail_out;
922
923 s_free(ts_creds);
924
925 if (!cssp_send_tsrequest(NULL, &blob, NULL))
926 goto bail_out;
927
928 return True;
929
930 bail_out:
931 xfree(token.data);
932 return False;
933}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette