VirtualBox

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

最後變更 在這個檔案從55121是 55121,由 vboxsync 提交於 10 年 前

rdesktop 1.8.3 unmodified

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

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