VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.3/cssp.c@ 72086

Last change on this file since 72086 was 55123, checked in by vboxsync, 10 years ago

rdesktop 1.8.3 modified for VBox

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.8 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 <[email protected]> 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
661 s = tcp_recv(NULL, 4);
662
663 if (s == NULL)
664 return False;
665
666 // verify ASN.1 header
667 if (s->p[0] != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
668 {
669 error("Expected BER_TAG_SEQUENCE|BER_TAG_CONSTRUCTED, got %x", s->p[0]);
670 return False;
671 }
672
673 // peek at first 4 bytes to get full message length
674 if (s->p[1] < 0x80)
675 length = s->p[1] - 2;
676 else if (s->p[1] == 0x81)
677 length = s->p[2] - 1;
678 else if (s->p[1] == 0x82)
679 length = (s->p[2] << 8) | s->p[3];
680 else
681 return False;
682
683 // receive the remainings of message
684 s = tcp_recv(s, length);
685
686#if WITH_DEBUG_CREDSSP
687 streamsave(s, "tsrequest_in.raw");
688 printf("In TSRequest token %ld bytes\n", s_length(s));
689 hexdump(s->data, s_length(s));
690#endif
691
692 // parse the response and into nego token
693 if (!ber_in_header(s, &tagval, &length) ||
694 tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
695 return False;
696
697 // version [0]
698 if (!ber_in_header(s, &tagval, &length) ||
699 tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0))
700 return False;
701 in_uint8s(s, length);
702
703 // negoToken [1]
704 if (token)
705 {
706 if (!ber_in_header(s, &tagval, &length)
707 || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1))
708 return False;
709 if (!ber_in_header(s, &tagval, &length)
710 || tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
711 return False;
712 if (!ber_in_header(s, &tagval, &length)
713 || tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
714 return False;
715 if (!ber_in_header(s, &tagval, &length)
716 || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0))
717 return False;
718
719 if (!ber_in_header(s, &tagval, &length) || tagval != BER_TAG_OCTET_STRING)
720 return False;
721
722 token->end = token->p = token->data;
723 out_uint8p(token, s->p, length);
724 s_mark_end(token);
725 }
726
727 // pubKey [3]
728 if (pubkey)
729 {
730 if (!ber_in_header(s, &tagval, &length)
731 || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3))
732 return False;
733
734 if (!ber_in_header(s, &tagval, &length) || tagval != BER_TAG_OCTET_STRING)
735 return False;
736
737 pubkey->data = pubkey->p = s->p;
738 pubkey->end = pubkey->data + length;
739 pubkey->size = length;
740 }
741
742
743 return True;
744}
745
746RD_BOOL
747cssp_connect(char *server, char *user, char *domain, char *password, STREAM s)
748{
749 OM_uint32 actual_time;
750 gss_cred_id_t cred;
751 gss_buffer_desc input_tok, output_tok;
752 gss_name_t target_name;
753 OM_uint32 major_status, minor_status;
754 int context_established = 0;
755 gss_ctx_id_t gss_ctx;
756 gss_OID desired_mech = &_gss_spnego_krb5_mechanism_oid_desc;
757
758 STREAM ts_creds;
759 struct stream token = { 0 };
760 struct stream pubkey = { 0 };
761 struct stream pubkey_cmp = { 0 };
762
763 // Verify that system gss support spnego
764 if (!cssp_gss_mech_available(desired_mech))
765 {
766 warning("CredSSP: System doesn't have support for desired authentication mechanism.\n");
767 return False;
768 }
769
770 // Get service name
771 if (!cssp_gss_get_service_name(server, &target_name))
772 {
773 warning("CredSSP: Failed to get target service name.\n");
774 return False;
775 }
776
777 // Establish tls connection to server
778 if (!tcp_tls_connect())
779 {
780 warning("CredSSP: Failed to establish TLS connection.\n");
781 return False;
782 }
783
784 tcp_tls_get_server_pubkey(&pubkey);
785
786#ifdef WITH_DEBUG_CREDSSP
787 streamsave(&pubkey, "PubKey.raw");
788#endif
789
790 // Enter the spnego loop
791 OM_uint32 actual_services;
792 gss_OID actual_mech;
793 struct stream blob = { 0 };
794
795 gss_ctx = GSS_C_NO_CONTEXT;
796 cred = GSS_C_NO_CREDENTIAL;
797
798 input_tok.length = 0;
799 output_tok.length = 0;
800 minor_status = 0;
801
802 int i = 0;
803
804 do
805 {
806 major_status = gss_init_sec_context(&minor_status,
807 cred,
808 &gss_ctx,
809 target_name,
810 desired_mech,
811 GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG,
812 GSS_C_INDEFINITE,
813 GSS_C_NO_CHANNEL_BINDINGS,
814 &input_tok,
815 &actual_mech,
816 &output_tok, &actual_services, &actual_time);
817
818 if (GSS_ERROR(major_status))
819 {
820 if (i == 0)
821 error("CredSSP: Initialize failed, do you have correct kerberos tgt initialized ?\n");
822 else
823 error("CredSSP: Negotiation failed.\n");
824
825#ifdef WITH_DEBUG_CREDSSP
826 cssp_gss_report_error(GSS_C_GSS_CODE, "CredSSP: SPNEGO negotiation failed.",
827 major_status, minor_status);
828#endif
829 goto bail_out;
830 }
831
832 // validate required services
833 if (!(actual_services & GSS_C_CONF_FLAG))
834 {
835 error("CredSSP: Confidiality service required but is not available.\n");
836 goto bail_out;
837 }
838
839 // Send token to server
840 if (output_tok.length != 0)
841 {
842 if (output_tok.length > token.size)
843 s_realloc(&token, output_tok.length);
844 s_reset(&token);
845
846 out_uint8p(&token, output_tok.value, output_tok.length);
847 s_mark_end(&token);
848
849 if (!cssp_send_tsrequest(&token, NULL, NULL))
850 goto bail_out;
851
852 (void) gss_release_buffer(&minor_status, &output_tok);
853 }
854
855 // Read token from server
856 if (major_status & GSS_S_CONTINUE_NEEDED)
857 {
858 (void) gss_release_buffer(&minor_status, &input_tok);
859
860 if (!cssp_read_tsrequest(&token, NULL))
861 goto bail_out;
862
863 input_tok.value = token.data;
864 input_tok.length = s_length(&token);
865 }
866 else
867 {
868 // Send encrypted pubkey for verification to server
869 context_established = 1;
870
871 if (!cssp_gss_wrap(gss_ctx, &pubkey, &blob))
872 goto bail_out;
873
874 if (!cssp_send_tsrequest(NULL, NULL, &blob))
875 goto bail_out;
876
877 context_established = 1;
878 }
879
880 i++;
881
882 }
883 while (!context_established);
884
885 // read tsrequest response and decrypt for public key validation
886 if (!cssp_read_tsrequest(NULL, &blob))
887 goto bail_out;
888
889 if (!cssp_gss_unwrap(gss_ctx, &blob, &pubkey_cmp))
890 goto bail_out;
891
892 pubkey_cmp.data[0] -= 1;
893
894 // validate public key
895 if (memcmp(pubkey.data, pubkey_cmp.data, s_length(&pubkey)) != 0)
896 {
897 error("CredSSP: Cannot guarantee integrity of server connection, MITM ? "
898 "(public key data mismatch)\n");
899 goto bail_out;
900 }
901
902 // Send TSCredentials
903 ts_creds = cssp_encode_tscredentials(user, password, domain);
904
905 if (!cssp_gss_wrap(gss_ctx, ts_creds, &blob))
906 goto bail_out;
907
908 s_free(ts_creds);
909
910 if (!cssp_send_tsrequest(NULL, &blob, NULL))
911 goto bail_out;
912
913 return True;
914
915 bail_out:
916 xfree(token.data);
917 return False;
918}
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