1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 2009 by the Massachusetts Institute of Technology.
4 * All Rights Reserved.
5 *
6 * Export of this software from the United States of America may
7 * require a specific license from the United States Government.
8 * It is the responsibility of any person or organization contemplating
9 * export to obtain such a license before exporting.
10 *
11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12 * distribute this software and its documentation for any purpose and
13 * without fee is hereby granted, provided that the above copyright
14 * notice appear in all copies and that both that copyright notice and
15 * this permission notice appear in supporting documentation, and that
16 * the name of M.I.T. not be used in advertising or publicity pertaining
17 * to distribution of the software without specific, written prior
18 * permission. Furthermore if you modify this software you must label
19 * your software as modified software and not distribute it in such a
20 * fashion that it might be confused with the original M.I.T. software.
21 * M.I.T. makes no representations about the suitability of
22 * this software for any purpose. It is provided "as is" without express
23 * or implied warranty.
24 */
25 #include "k5-int.h"
26 #include "k5-der.h"
27 #include "gssapiP_krb5.h"
28
29 /*
30 * IAKERB implementation
31 */
32
33 enum iakerb_state {
34 IAKERB_AS_REQ, /* acquiring ticket with initial creds */
35 IAKERB_TGS_REQ, /* acquiring ticket with TGT */
36 IAKERB_AP_REQ /* hand-off to normal GSS AP-REQ exchange */
37 };
38
39 struct _iakerb_ctx_id_rec {
40 krb5_magic magic; /* KG_IAKERB_CONTEXT */
41 krb5_context k5c;
42 gss_cred_id_t defcred; /* Initiator only */
43 enum iakerb_state state; /* Initiator only */
44 krb5_init_creds_context icc; /* Initiator only */
45 krb5_tkt_creds_context tcc; /* Initiator only */
46 gss_ctx_id_t gssc;
47 krb5_data conv; /* conversation for checksumming */
48 unsigned int count; /* number of round trips */
49 int initiate;
50 int established;
51 krb5_get_init_creds_opt *gic_opts;
52 };
53
54 #define IAKERB_MAX_HOPS ( 16 /* MAX_IN_TKT_LOOPS */ + KRB5_REFERRAL_MAXHOPS )
55
56 typedef struct _iakerb_ctx_id_rec iakerb_ctx_id_rec;
57 typedef iakerb_ctx_id_rec *iakerb_ctx_id_t;
58
59 /*
60 * Release an IAKERB context
61 */
62 static void
iakerb_release_context(iakerb_ctx_id_t ctx)63 iakerb_release_context(iakerb_ctx_id_t ctx)
64 {
65 OM_uint32 tmp;
66
67 if (ctx == NULL)
68 return;
69
70 krb5_gss_release_cred(&tmp, &ctx->defcred);
71 krb5_init_creds_free(ctx->k5c, ctx->icc);
72 krb5_tkt_creds_free(ctx->k5c, ctx->tcc);
73 krb5_gss_delete_sec_context(&tmp, &ctx->gssc, NULL);
74 krb5_free_data_contents(ctx->k5c, &ctx->conv);
75 krb5_get_init_creds_opt_free(ctx->k5c, ctx->gic_opts);
76 krb5_free_context(ctx->k5c);
77 free(ctx);
78 }
79
80 /*
81 * Create a IAKERB-FINISHED structure containing a checksum of
82 * the entire IAKERB exchange.
83 */
84 krb5_error_code
iakerb_make_finished(krb5_context context,krb5_key key,const krb5_data * conv,krb5_data ** finished)85 iakerb_make_finished(krb5_context context,
86 krb5_key key,
87 const krb5_data *conv,
88 krb5_data **finished)
89 {
90 krb5_error_code code;
91 krb5_iakerb_finished iaf;
92
93 *finished = NULL;
94
95 memset(&iaf, 0, sizeof(iaf));
96
97 if (key == NULL)
98 return KRB5KDC_ERR_NULL_KEY;
99
100 code = krb5_k_make_checksum(context, 0, key, KRB5_KEYUSAGE_IAKERB_FINISHED,
101 conv, &iaf.checksum);
102 if (code != 0)
103 return code;
104
105 code = encode_krb5_iakerb_finished(&iaf, finished);
106
107 krb5_free_checksum_contents(context, &iaf.checksum);
108
109 return code;
110 }
111
112 /*
113 * Verify a IAKERB-FINISHED structure submitted by the initiator
114 */
115 krb5_error_code
iakerb_verify_finished(krb5_context context,krb5_key key,const krb5_data * conv,const krb5_data * finished)116 iakerb_verify_finished(krb5_context context,
117 krb5_key key,
118 const krb5_data *conv,
119 const krb5_data *finished)
120 {
121 krb5_error_code code;
122 krb5_iakerb_finished *iaf;
123 krb5_boolean valid = FALSE;
124
125 if (key == NULL)
126 return KRB5KDC_ERR_NULL_KEY;
127
128 code = decode_krb5_iakerb_finished(finished, &iaf);
129 if (code != 0)
130 return code;
131
132 code = krb5_k_verify_checksum(context, key, KRB5_KEYUSAGE_IAKERB_FINISHED,
133 conv, &iaf->checksum, &valid);
134 if (code == 0 && valid == FALSE)
135 code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
136
137 krb5_free_iakerb_finished(context, iaf);
138
139 return code;
140 }
141
142 /*
143 * Save a token for future checksumming.
144 */
145 static krb5_error_code
iakerb_save_token(iakerb_ctx_id_t ctx,const gss_buffer_t token)146 iakerb_save_token(iakerb_ctx_id_t ctx, const gss_buffer_t token)
147 {
148 char *p;
149
150 p = realloc(ctx->conv.data, ctx->conv.length + token->length);
151 if (p == NULL)
152 return ENOMEM;
153
154 memcpy(p + ctx->conv.length, token->value, token->length);
155 ctx->conv.data = p;
156 ctx->conv.length += token->length;
157
158 return 0;
159 }
160
161 /*
162 * Parse a token into IAKERB-HEADER and KRB-KDC-REQ/REP
163 */
164 static krb5_error_code
iakerb_parse_token(iakerb_ctx_id_t ctx,int initialContextToken,const gss_buffer_t token,krb5_data * realm,krb5_data ** cookie,krb5_data * request)165 iakerb_parse_token(iakerb_ctx_id_t ctx,
166 int initialContextToken,
167 const gss_buffer_t token,
168 krb5_data *realm,
169 krb5_data **cookie,
170 krb5_data *request)
171 {
172 krb5_error_code code;
173 krb5_iakerb_header *iah = NULL;
174 unsigned int bodysize;
175 uint8_t *body;
176 int flags = 0;
177 krb5_data data;
178 struct k5input in, seq;
179
180 if (token == GSS_C_NO_BUFFER || token->length == 0) {
181 code = KRB5_BAD_MSIZE;
182 goto cleanup;
183 }
184
185 if (initialContextToken)
186 flags |= G_VFY_TOKEN_HDR_WRAPPER_REQUIRED;
187
188 body = token->value;
189 code = g_verify_token_header(gss_mech_iakerb, &bodysize, &body,
190 IAKERB_TOK_PROXY, token->length, flags);
191 if (code != 0)
192 goto cleanup;
193
194 /* Find the end of the DER sequence tag and decode it (with the tag) as the
195 * IAKERB jeader. */
196 k5_input_init(&in, body, bodysize);
197 if (!k5_der_get_value(&in, 0x30, &seq)) {
198 code = ASN1_BAD_ID;
199 goto cleanup;
200 }
201 data = make_data(body, seq.ptr + seq.len - body);
202 code = decode_krb5_iakerb_header(&data, &iah);
203 if (code != 0)
204 goto cleanup;
205
206 if (realm != NULL) {
207 *realm = iah->target_realm;
208 iah->target_realm.data = NULL;
209 }
210
211 if (cookie != NULL) {
212 *cookie = iah->cookie;
213 iah->cookie = NULL;
214 }
215
216 /* The remainder of the token body is the request. */
217 *request = make_data((uint8_t *)in.ptr, in.len);
218 assert(request->data + request->length ==
219 (char *)token->value + token->length);
220
221 cleanup:
222 krb5_free_iakerb_header(ctx->k5c, iah);
223
224 return code;
225 }
226
227 /*
228 * Create a token from IAKERB-HEADER and KRB-KDC-REQ/REP
229 */
230 static krb5_error_code
iakerb_make_token(iakerb_ctx_id_t ctx,krb5_data * realm,krb5_data * cookie,krb5_data * request,int initialContextToken,gss_buffer_t token)231 iakerb_make_token(iakerb_ctx_id_t ctx,
232 krb5_data *realm,
233 krb5_data *cookie,
234 krb5_data *request,
235 int initialContextToken,
236 gss_buffer_t token)
237 {
238 krb5_error_code code;
239 krb5_iakerb_header iah;
240 krb5_data *data = NULL;
241 char *p;
242 unsigned int tokenSize;
243 struct k5buf buf;
244
245 token->value = NULL;
246 token->length = 0;
247
248 /*
249 * Assemble the IAKERB-HEADER from the realm and cookie
250 */
251 iah.target_realm = *realm;
252 iah.cookie = cookie;
253
254 code = encode_krb5_iakerb_header(&iah, &data);
255 if (code != 0)
256 goto cleanup;
257
258 /*
259 * Concatenate Kerberos request.
260 */
261 p = realloc(data->data, data->length + request->length);
262 if (p == NULL) {
263 code = ENOMEM;
264 goto cleanup;
265 }
266 data->data = p;
267
268 if (request->length > 0)
269 memcpy(data->data + data->length, request->data, request->length);
270 data->length += request->length;
271
272 if (initialContextToken)
273 tokenSize = g_token_size(gss_mech_iakerb, data->length);
274 else
275 tokenSize = 2 + data->length;
276
277 token->value = gssalloc_malloc(tokenSize);
278 if (token->value == NULL) {
279 code = ENOMEM;
280 goto cleanup;
281 }
282 token->length = tokenSize;
283 k5_buf_init_fixed(&buf, token->value, token->length);
284
285 if (initialContextToken) {
286 g_make_token_header(&buf, gss_mech_iakerb, data->length,
287 IAKERB_TOK_PROXY);
288 } else {
289 k5_buf_add_uint16_be(&buf, IAKERB_TOK_PROXY);
290 }
291 k5_buf_add_len(&buf, data->data, data->length);
292 assert(buf.len == token->length);
293
294 cleanup:
295 krb5_free_data(ctx->k5c, data);
296
297 return code;
298 }
299
300 /*
301 * Parse the IAKERB token in input_token and send the contained KDC
302 * request to the KDC for the realm.
303 *
304 * Wrap the KDC reply in output_token.
305 */
306 static krb5_error_code
iakerb_acceptor_step(iakerb_ctx_id_t ctx,int initialContextToken,const gss_buffer_t input_token,gss_buffer_t output_token)307 iakerb_acceptor_step(iakerb_ctx_id_t ctx,
308 int initialContextToken,
309 const gss_buffer_t input_token,
310 gss_buffer_t output_token)
311 {
312 krb5_error_code code;
313 krb5_data request = empty_data(), reply = empty_data();
314 krb5_data realm = empty_data();
315 OM_uint32 tmp;
316 int tcp_only, use_primary;
317 krb5_ui_4 kdc_code;
318
319 output_token->length = 0;
320 output_token->value = NULL;
321
322 if (ctx->count >= IAKERB_MAX_HOPS) {
323 code = KRB5_KDC_UNREACH;
324 goto cleanup;
325 }
326
327 code = iakerb_parse_token(ctx, initialContextToken, input_token, &realm,
328 NULL, &request);
329 if (code != 0)
330 goto cleanup;
331
332 if (realm.length == 0 || request.length == 0) {
333 code = KRB5_BAD_MSIZE;
334 goto cleanup;
335 }
336
337 code = iakerb_save_token(ctx, input_token);
338 if (code != 0)
339 goto cleanup;
340
341 for (tcp_only = 0; tcp_only <= 1; tcp_only++) {
342 use_primary = 0;
343 code = krb5_sendto_kdc(ctx->k5c, &request, &realm,
344 &reply, &use_primary, tcp_only);
345 if (code == 0 && krb5_is_krb_error(&reply)) {
346 krb5_error *error;
347
348 code = decode_krb5_error(&reply, &error);
349 if (code != 0)
350 goto cleanup;
351 kdc_code = error->error;
352 krb5_free_error(ctx->k5c, error);
353 if (kdc_code == KRB_ERR_RESPONSE_TOO_BIG) {
354 krb5_free_data_contents(ctx->k5c, &reply);
355 reply = empty_data();
356 continue;
357 }
358 }
359 break;
360 }
361
362 if (code == KRB5_KDC_UNREACH || code == KRB5_REALM_UNKNOWN) {
363 krb5_error error;
364
365 memset(&error, 0, sizeof(error));
366 if (code == KRB5_KDC_UNREACH)
367 error.error = KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE;
368 else if (code == KRB5_REALM_UNKNOWN)
369 error.error = KRB_AP_ERR_IAKERB_KDC_NOT_FOUND;
370
371 code = krb5_mk_error(ctx->k5c, &error, &reply);
372 if (code != 0)
373 goto cleanup;
374 } else if (code != 0)
375 goto cleanup;
376
377 code = iakerb_make_token(ctx, &realm, NULL, &reply, 0, output_token);
378 if (code != 0)
379 goto cleanup;
380
381 code = iakerb_save_token(ctx, output_token);
382 if (code != 0)
383 goto cleanup;
384
385 ctx->count++;
386
387 cleanup:
388 if (code != 0)
389 gss_release_buffer(&tmp, output_token);
390 /* request is a pointer into input_token, no need to free */
391 krb5_free_data_contents(ctx->k5c, &realm);
392 krb5_free_data_contents(ctx->k5c, &reply);
393
394 return code;
395 }
396
397 /*
398 * Initialise the krb5_init_creds context for the IAKERB context
399 */
400 static krb5_error_code
iakerb_init_creds_ctx(iakerb_ctx_id_t ctx,krb5_gss_cred_id_t cred,OM_uint32 time_req)401 iakerb_init_creds_ctx(iakerb_ctx_id_t ctx,
402 krb5_gss_cred_id_t cred,
403 OM_uint32 time_req)
404 {
405 krb5_error_code code;
406
407 if (cred->iakerb_mech == 0) {
408 code = EINVAL;
409 goto cleanup;
410 }
411
412 assert(cred->name != NULL);
413 assert(cred->name->princ != NULL);
414
415 code = krb5_get_init_creds_opt_alloc(ctx->k5c, &ctx->gic_opts);
416 if (code != 0)
417 goto cleanup;
418
419 if (time_req != 0 && time_req != GSS_C_INDEFINITE)
420 krb5_get_init_creds_opt_set_tkt_life(ctx->gic_opts, time_req);
421
422 code = krb5_get_init_creds_opt_set_out_ccache(ctx->k5c, ctx->gic_opts,
423 cred->ccache);
424 if (code != 0)
425 goto cleanup;
426
427 code = krb5_init_creds_init(ctx->k5c,
428 cred->name->princ,
429 NULL, /* prompter */
430 NULL, /* data */
431 0, /* start_time */
432 ctx->gic_opts,
433 &ctx->icc);
434 if (code != 0)
435 goto cleanup;
436
437 if (cred->password != NULL) {
438 code = krb5_init_creds_set_password(ctx->k5c, ctx->icc,
439 cred->password);
440 } else if (cred->client_keytab != NULL) {
441 code = krb5_init_creds_set_keytab(ctx->k5c, ctx->icc,
442 cred->client_keytab);
443 } else {
444 code = KRB5_KT_NOTFOUND;
445 }
446 if (code != 0)
447 goto cleanup;
448
449 cleanup:
450 return code;
451 }
452
453 /*
454 * Initialise the krb5_tkt_creds context for the IAKERB context
455 */
456 static krb5_error_code
iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx,krb5_gss_cred_id_t cred,krb5_gss_name_t name,OM_uint32 time_req)457 iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx,
458 krb5_gss_cred_id_t cred,
459 krb5_gss_name_t name,
460 OM_uint32 time_req)
461
462 {
463 krb5_error_code code;
464 krb5_creds creds;
465 krb5_timestamp now;
466
467 assert(cred->name != NULL);
468 assert(cred->name->princ != NULL);
469
470 memset(&creds, 0, sizeof(creds));
471
472 creds.client = cred->name->princ;
473 creds.server = name->princ;
474
475 if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
476 code = krb5_timeofday(ctx->k5c, &now);
477 if (code != 0)
478 goto cleanup;
479
480 creds.times.endtime = ts_incr(now, time_req);
481 }
482
483 if (cred->name->ad_context != NULL) {
484 code = krb5_authdata_export_authdata(ctx->k5c,
485 cred->name->ad_context,
486 AD_USAGE_TGS_REQ,
487 &creds.authdata);
488 if (code != 0)
489 goto cleanup;
490 }
491
492 code = krb5_tkt_creds_init(ctx->k5c, cred->ccache, &creds, 0, &ctx->tcc);
493 if (code != 0)
494 goto cleanup;
495
496 cleanup:
497 krb5_free_authdata(ctx->k5c, creds.authdata);
498
499 return code;
500 }
501
502 /*
503 * Parse the IAKERB token in input_token and process the KDC
504 * response.
505 *
506 * Emit the next KDC request, if any, in output_token.
507 */
508 static krb5_error_code
iakerb_initiator_step(iakerb_ctx_id_t ctx,krb5_gss_cred_id_t cred,krb5_gss_name_t name,OM_uint32 time_req,const gss_buffer_t input_token,gss_buffer_t output_token)509 iakerb_initiator_step(iakerb_ctx_id_t ctx,
510 krb5_gss_cred_id_t cred,
511 krb5_gss_name_t name,
512 OM_uint32 time_req,
513 const gss_buffer_t input_token,
514 gss_buffer_t output_token)
515 {
516 krb5_error_code code = 0;
517 krb5_data in = empty_data(), out = empty_data(), realm = empty_data();
518 krb5_data *cookie = NULL;
519 OM_uint32 tmp;
520 unsigned int flags = 0;
521 krb5_ticket_times times;
522
523 output_token->length = 0;
524 output_token->value = NULL;
525
526 if (input_token != GSS_C_NO_BUFFER) {
527 code = iakerb_parse_token(ctx, 0, input_token, NULL, &cookie, &in);
528 if (code != 0)
529 goto cleanup;
530
531 code = iakerb_save_token(ctx, input_token);
532 if (code != 0)
533 goto cleanup;
534 }
535
536 switch (ctx->state) {
537 case IAKERB_AS_REQ:
538 if (ctx->icc == NULL) {
539 code = iakerb_init_creds_ctx(ctx, cred, time_req);
540 if (code != 0)
541 goto cleanup;
542 }
543
544 code = krb5_init_creds_step(ctx->k5c, ctx->icc, &in, &out, &realm,
545 &flags);
546 if (code != 0) {
547 if (cred->have_tgt) {
548 /* We were trying to refresh; keep going with current creds. */
549 ctx->state = IAKERB_TGS_REQ;
550 krb5_clear_error_message(ctx->k5c);
551 } else {
552 goto cleanup;
553 }
554 } else if (!(flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE)) {
555 krb5_init_creds_get_times(ctx->k5c, ctx->icc, ×);
556 kg_cred_set_initial_refresh(ctx->k5c, cred, ×);
557 cred->expire = times.endtime;
558
559 krb5_init_creds_free(ctx->k5c, ctx->icc);
560 ctx->icc = NULL;
561
562 ctx->state = IAKERB_TGS_REQ;
563 } else
564 break;
565 in = empty_data();
566 /* Done with AS request; fall through to TGS request. */
567 case IAKERB_TGS_REQ:
568 if (ctx->tcc == NULL) {
569 code = iakerb_tkt_creds_ctx(ctx, cred, name, time_req);
570 if (code != 0)
571 goto cleanup;
572 }
573
574 code = krb5_tkt_creds_step(ctx->k5c, ctx->tcc, &in, &out, &realm,
575 &flags);
576 if (code != 0)
577 goto cleanup;
578 if (!(flags & KRB5_TKT_CREDS_STEP_FLAG_CONTINUE)) {
579 krb5_tkt_creds_get_times(ctx->k5c, ctx->tcc, ×);
580 cred->expire = times.endtime;
581
582 krb5_tkt_creds_free(ctx->k5c, ctx->tcc);
583 ctx->tcc = NULL;
584
585 ctx->state = IAKERB_AP_REQ;
586 } else
587 break;
588 /* Done with TGS request; fall through to AP request. */
589 case IAKERB_AP_REQ:
590 break;
591 }
592
593 if (out.length != 0) {
594 assert(ctx->state != IAKERB_AP_REQ);
595
596 code = iakerb_make_token(ctx, &realm, cookie, &out,
597 (input_token == GSS_C_NO_BUFFER),
598 output_token);
599 if (code != 0)
600 goto cleanup;
601
602 /* Save the token for generating a future checksum */
603 code = iakerb_save_token(ctx, output_token);
604 if (code != 0)
605 goto cleanup;
606
607 ctx->count++;
608 }
609
610 cleanup:
611 if (code != 0)
612 gss_release_buffer(&tmp, output_token);
613 krb5_free_data(ctx->k5c, cookie);
614 krb5_free_data_contents(ctx->k5c, &out);
615 krb5_free_data_contents(ctx->k5c, &realm);
616
617 return code;
618 }
619
620 /*
621 * Determine the starting IAKERB state for a context. If we already
622 * have a ticket, we may not need to do IAKERB at all.
623 */
624 static krb5_error_code
iakerb_get_initial_state(iakerb_ctx_id_t ctx,krb5_gss_cred_id_t cred,krb5_gss_name_t target,OM_uint32 time_req,enum iakerb_state * state)625 iakerb_get_initial_state(iakerb_ctx_id_t ctx,
626 krb5_gss_cred_id_t cred,
627 krb5_gss_name_t target,
628 OM_uint32 time_req,
629 enum iakerb_state *state)
630 {
631 krb5_creds in_creds, *out_creds = NULL;
632 krb5_error_code code;
633
634 memset(&in_creds, 0, sizeof(in_creds));
635
636 in_creds.client = cred->name->princ;
637 in_creds.server = target->princ;
638
639 if (cred->name->ad_context != NULL) {
640 code = krb5_authdata_export_authdata(ctx->k5c,
641 cred->name->ad_context,
642 AD_USAGE_TGS_REQ,
643 &in_creds.authdata);
644 if (code != 0)
645 goto cleanup;
646 }
647
648 if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
649 krb5_timestamp now;
650
651 code = krb5_timeofday(ctx->k5c, &now);
652 if (code != 0)
653 goto cleanup;
654
655 in_creds.times.endtime = ts_incr(now, time_req);
656 }
657
658 /* Make an AS request if we have no creds or it's time to refresh them. */
659 if (cred->expire == 0 || kg_cred_time_to_refresh(ctx->k5c, cred)) {
660 *state = IAKERB_AS_REQ;
661 code = 0;
662 goto cleanup;
663 }
664
665 code = krb5_get_credentials(ctx->k5c, KRB5_GC_CACHED, cred->ccache,
666 &in_creds, &out_creds);
667 if (code == KRB5_CC_NOTFOUND || code == KRB5_CC_NOT_KTYPE) {
668 *state = cred->have_tgt ? IAKERB_TGS_REQ : IAKERB_AS_REQ;
669 code = 0;
670 } else if (code == 0) {
671 *state = IAKERB_AP_REQ;
672 krb5_free_creds(ctx->k5c, out_creds);
673 }
674
675 cleanup:
676 krb5_free_authdata(ctx->k5c, in_creds.authdata);
677
678 return code;
679 }
680
681 /*
682 * Allocate and initialise an IAKERB context
683 */
684 static krb5_error_code
iakerb_alloc_context(iakerb_ctx_id_t * pctx,int initiate)685 iakerb_alloc_context(iakerb_ctx_id_t *pctx, int initiate)
686 {
687 iakerb_ctx_id_t ctx;
688 krb5_error_code code;
689
690 *pctx = NULL;
691
692 ctx = k5alloc(sizeof(*ctx), &code);
693 if (ctx == NULL)
694 goto cleanup;
695 ctx->defcred = GSS_C_NO_CREDENTIAL;
696 ctx->magic = KG_IAKERB_CONTEXT;
697 ctx->state = IAKERB_AS_REQ;
698 ctx->count = 0;
699 ctx->initiate = initiate;
700 ctx->established = 0;
701
702 code = krb5_gss_init_context(&ctx->k5c);
703 if (code != 0)
704 goto cleanup;
705
706 *pctx = ctx;
707
708 cleanup:
709 if (code != 0)
710 iakerb_release_context(ctx);
711
712 return code;
713 }
714
715 OM_uint32 KRB5_CALLCONV
iakerb_gss_delete_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_buffer_t output_token)716 iakerb_gss_delete_sec_context(OM_uint32 *minor_status,
717 gss_ctx_id_t *context_handle,
718 gss_buffer_t output_token)
719 {
720 iakerb_ctx_id_t iakerb_ctx = (iakerb_ctx_id_t)*context_handle;
721
722 if (output_token != GSS_C_NO_BUFFER) {
723 output_token->length = 0;
724 output_token->value = NULL;
725 }
726
727 *minor_status = 0;
728 *context_handle = GSS_C_NO_CONTEXT;
729 iakerb_release_context(iakerb_ctx);
730
731 return GSS_S_COMPLETE;
732 }
733
734 static krb5_boolean
iakerb_is_iakerb_token(const gss_buffer_t token)735 iakerb_is_iakerb_token(const gss_buffer_t token)
736 {
737 krb5_error_code code;
738 unsigned int bodysize = token->length;
739 unsigned char *ptr = token->value;
740
741 code = g_verify_token_header(gss_mech_iakerb,
742 &bodysize, &ptr,
743 IAKERB_TOK_PROXY,
744 token->length, 0);
745
746 return (code == 0);
747 }
748
749 static void
iakerb_make_exts(iakerb_ctx_id_t ctx,krb5_gss_ctx_ext_rec * exts)750 iakerb_make_exts(iakerb_ctx_id_t ctx, krb5_gss_ctx_ext_rec *exts)
751 {
752 memset(exts, 0, sizeof(*exts));
753
754 if (ctx->conv.length != 0)
755 exts->iakerb.conv = &ctx->conv;
756 }
757
758 OM_uint32 KRB5_CALLCONV
iakerb_gss_accept_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_cred_id_t verifier_cred_handle,gss_buffer_t input_token,gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)759 iakerb_gss_accept_sec_context(OM_uint32 *minor_status,
760 gss_ctx_id_t *context_handle,
761 gss_cred_id_t verifier_cred_handle,
762 gss_buffer_t input_token,
763 gss_channel_bindings_t input_chan_bindings,
764 gss_name_t *src_name,
765 gss_OID *mech_type,
766 gss_buffer_t output_token,
767 OM_uint32 *ret_flags,
768 OM_uint32 *time_rec,
769 gss_cred_id_t *delegated_cred_handle)
770 {
771 OM_uint32 major_status = GSS_S_FAILURE;
772 OM_uint32 code;
773 iakerb_ctx_id_t ctx;
774 int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
775
776 if (initialContextToken) {
777 code = iakerb_alloc_context(&ctx, 0);
778 if (code != 0)
779 goto cleanup;
780
781 } else
782 ctx = (iakerb_ctx_id_t)*context_handle;
783
784 if (iakerb_is_iakerb_token(input_token)) {
785 if (ctx->gssc != GSS_C_NO_CONTEXT) {
786 /* We shouldn't get an IAKERB token now. */
787 code = G_WRONG_TOKID;
788 major_status = GSS_S_DEFECTIVE_TOKEN;
789 goto cleanup;
790 }
791 code = iakerb_acceptor_step(ctx, initialContextToken,
792 input_token, output_token);
793 if (code == (OM_uint32)KRB5_BAD_MSIZE)
794 major_status = GSS_S_DEFECTIVE_TOKEN;
795 if (code != 0)
796 goto cleanup;
797 if (initialContextToken) {
798 *context_handle = (gss_ctx_id_t)ctx;
799 ctx = NULL;
800 }
801 if (src_name != NULL)
802 *src_name = GSS_C_NO_NAME;
803 if (ret_flags != NULL)
804 *ret_flags = 0;
805 if (time_rec != NULL)
806 *time_rec = 0;
807 if (delegated_cred_handle != NULL)
808 *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
809 major_status = GSS_S_CONTINUE_NEEDED;
810 } else {
811 krb5_gss_ctx_ext_rec exts;
812
813 iakerb_make_exts(ctx, &exts);
814
815 major_status = krb5_gss_accept_sec_context_ext(&code,
816 &ctx->gssc,
817 verifier_cred_handle,
818 input_token,
819 input_chan_bindings,
820 src_name,
821 NULL,
822 output_token,
823 ret_flags,
824 time_rec,
825 delegated_cred_handle,
826 &exts);
827 if (major_status == GSS_S_COMPLETE)
828 ctx->established = 1;
829 }
830
831 if (mech_type != NULL)
832 *mech_type = gss_mech_iakerb;
833
834 cleanup:
835 if (initialContextToken && GSS_ERROR(major_status)) {
836 iakerb_release_context(ctx);
837 *context_handle = GSS_C_NO_CONTEXT;
838 }
839
840 *minor_status = code;
841 return major_status;
842 }
843
844 OM_uint32 KRB5_CALLCONV
iakerb_gss_init_sec_context(OM_uint32 * minor_status,gss_cred_id_t claimant_cred_handle,gss_ctx_id_t * context_handle,gss_name_t target_name,gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,gss_channel_bindings_t input_chan_bindings,gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)845 iakerb_gss_init_sec_context(OM_uint32 *minor_status,
846 gss_cred_id_t claimant_cred_handle,
847 gss_ctx_id_t *context_handle,
848 gss_name_t target_name,
849 gss_OID mech_type,
850 OM_uint32 req_flags,
851 OM_uint32 time_req,
852 gss_channel_bindings_t input_chan_bindings,
853 gss_buffer_t input_token,
854 gss_OID *actual_mech_type,
855 gss_buffer_t output_token,
856 OM_uint32 *ret_flags,
857 OM_uint32 *time_rec)
858 {
859 OM_uint32 major_status = GSS_S_FAILURE;
860 krb5_error_code code;
861 iakerb_ctx_id_t ctx;
862 krb5_gss_cred_id_t kcred;
863 krb5_gss_name_t kname;
864 krb5_boolean cred_locked = FALSE;
865 int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
866
867 if (initialContextToken) {
868 code = iakerb_alloc_context(&ctx, 1);
869 if (code != 0) {
870 *minor_status = code;
871 goto cleanup;
872 }
873 if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
874 major_status = iakerb_gss_acquire_cred(minor_status, NULL,
875 GSS_C_INDEFINITE,
876 GSS_C_NULL_OID_SET,
877 GSS_C_INITIATE,
878 &ctx->defcred, NULL, NULL);
879 if (GSS_ERROR(major_status))
880 goto cleanup;
881 claimant_cred_handle = ctx->defcred;
882 }
883 } else {
884 ctx = (iakerb_ctx_id_t)*context_handle;
885 if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
886 claimant_cred_handle = ctx->defcred;
887 }
888
889 kname = (krb5_gss_name_t)target_name;
890
891 major_status = kg_cred_resolve(minor_status, ctx->k5c,
892 claimant_cred_handle, target_name);
893 if (GSS_ERROR(major_status))
894 goto cleanup;
895 cred_locked = TRUE;
896 kcred = (krb5_gss_cred_id_t)claimant_cred_handle;
897
898 major_status = GSS_S_FAILURE;
899
900 if (initialContextToken) {
901 code = iakerb_get_initial_state(ctx, kcred, kname, time_req,
902 &ctx->state);
903 if (code != 0) {
904 *minor_status = code;
905 goto cleanup;
906 }
907 *context_handle = (gss_ctx_id_t)ctx;
908 }
909
910 if (ctx->state != IAKERB_AP_REQ) {
911 /* We need to do IAKERB. */
912 code = iakerb_initiator_step(ctx,
913 kcred,
914 kname,
915 time_req,
916 input_token,
917 output_token);
918 if (code == KRB5_BAD_MSIZE)
919 major_status = GSS_S_DEFECTIVE_TOKEN;
920 if (code != 0) {
921 *minor_status = code;
922 goto cleanup;
923 }
924 }
925
926 if (ctx->state == IAKERB_AP_REQ) {
927 krb5_gss_ctx_ext_rec exts;
928
929 if (cred_locked) {
930 k5_mutex_unlock(&kcred->lock);
931 cred_locked = FALSE;
932 }
933
934 iakerb_make_exts(ctx, &exts);
935
936 if (ctx->gssc == GSS_C_NO_CONTEXT)
937 input_token = GSS_C_NO_BUFFER;
938
939 /* IAKERB is finished, or we skipped to Kerberos directly. */
940 major_status = krb5_gss_init_sec_context_ext(minor_status,
941 (gss_cred_id_t) kcred,
942 &ctx->gssc,
943 target_name,
944 (gss_OID)gss_mech_iakerb,
945 req_flags,
946 time_req,
947 input_chan_bindings,
948 input_token,
949 NULL,
950 output_token,
951 ret_flags,
952 time_rec,
953 &exts);
954 if (major_status == GSS_S_COMPLETE)
955 ctx->established = 1;
956 } else {
957 if (ret_flags != NULL)
958 *ret_flags = 0;
959 if (time_rec != NULL)
960 *time_rec = 0;
961 major_status = GSS_S_CONTINUE_NEEDED;
962 }
963
964 if (actual_mech_type != NULL)
965 *actual_mech_type = gss_mech_iakerb;
966
967 cleanup:
968 if (cred_locked)
969 k5_mutex_unlock(&kcred->lock);
970 if (initialContextToken && GSS_ERROR(major_status)) {
971 iakerb_release_context(ctx);
972 *context_handle = GSS_C_NO_CONTEXT;
973 }
974
975 return major_status;
976 }
977
978 OM_uint32 KRB5_CALLCONV
iakerb_gss_unwrap(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state)979 iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
980 gss_buffer_t input_message_buffer,
981 gss_buffer_t output_message_buffer, int *conf_state,
982 gss_qop_t *qop_state)
983 {
984 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
985
986 if (ctx->gssc == GSS_C_NO_CONTEXT)
987 return GSS_S_NO_CONTEXT;
988
989 return krb5_gss_unwrap(minor_status, ctx->gssc, input_message_buffer,
990 output_message_buffer, conf_state, qop_state);
991 }
992
993 OM_uint32 KRB5_CALLCONV
iakerb_gss_wrap(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)994 iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
995 int conf_req_flag, gss_qop_t qop_req,
996 gss_buffer_t input_message_buffer, int *conf_state,
997 gss_buffer_t output_message_buffer)
998 {
999 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1000
1001 if (ctx->gssc == GSS_C_NO_CONTEXT)
1002 return GSS_S_NO_CONTEXT;
1003
1004 return krb5_gss_wrap(minor_status, ctx->gssc, conf_req_flag, qop_req,
1005 input_message_buffer, conf_state,
1006 output_message_buffer);
1007 }
1008
1009 OM_uint32 KRB5_CALLCONV
iakerb_gss_process_context_token(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_buffer_t token_buffer)1010 iakerb_gss_process_context_token(OM_uint32 *minor_status,
1011 const gss_ctx_id_t context_handle,
1012 const gss_buffer_t token_buffer)
1013 {
1014 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1015
1016 if (ctx->gssc == GSS_C_NO_CONTEXT)
1017 return GSS_S_DEFECTIVE_TOKEN;
1018
1019 return krb5_gss_process_context_token(minor_status, ctx->gssc,
1020 token_buffer);
1021 }
1022
1023 OM_uint32 KRB5_CALLCONV
iakerb_gss_context_time(OM_uint32 * minor_status,gss_ctx_id_t context_handle,OM_uint32 * time_rec)1024 iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1025 OM_uint32 *time_rec)
1026 {
1027 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1028
1029 if (ctx->gssc == GSS_C_NO_CONTEXT)
1030 return GSS_S_NO_CONTEXT;
1031
1032 return krb5_gss_context_time(minor_status, ctx->gssc, time_rec);
1033 }
1034
1035 #ifndef LEAN_CLIENT
1036
1037 OM_uint32 KRB5_CALLCONV
iakerb_gss_export_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_buffer_t interprocess_token)1038 iakerb_gss_export_sec_context(OM_uint32 *minor_status,
1039 gss_ctx_id_t *context_handle,
1040 gss_buffer_t interprocess_token)
1041 {
1042 OM_uint32 maj;
1043 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
1044
1045 /* We don't currently support exporting partially established contexts. */
1046 if (!ctx->established)
1047 return GSS_S_UNAVAILABLE;
1048
1049 maj = krb5_gss_export_sec_context(minor_status, &ctx->gssc,
1050 interprocess_token);
1051 if (ctx->gssc == GSS_C_NO_CONTEXT) {
1052 iakerb_release_context(ctx);
1053 *context_handle = GSS_C_NO_CONTEXT;
1054 }
1055 return maj;
1056 }
1057
1058 OM_uint32 KRB5_CALLCONV
iakerb_gss_import_sec_context(OM_uint32 * minor_status,gss_buffer_t interprocess_token,gss_ctx_id_t * context_handle)1059 iakerb_gss_import_sec_context(OM_uint32 *minor_status,
1060 gss_buffer_t interprocess_token,
1061 gss_ctx_id_t *context_handle)
1062 {
1063 OM_uint32 maj, tmpmin;
1064 krb5_error_code code;
1065 gss_ctx_id_t gssc;
1066 krb5_gss_ctx_id_t kctx;
1067 iakerb_ctx_id_t ctx;
1068
1069 maj = krb5_gss_import_sec_context(minor_status, interprocess_token, &gssc);
1070 if (maj != GSS_S_COMPLETE)
1071 return maj;
1072 kctx = (krb5_gss_ctx_id_t)gssc;
1073
1074 if (!kctx->established) {
1075 /* We don't currently support importing partially established
1076 * contexts. */
1077 krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
1078 return GSS_S_FAILURE;
1079 }
1080
1081 code = iakerb_alloc_context(&ctx, kctx->initiate);
1082 if (code != 0) {
1083 krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
1084 *minor_status = code;
1085 return GSS_S_FAILURE;
1086 }
1087
1088 ctx->gssc = gssc;
1089 ctx->established = 1;
1090 *context_handle = (gss_ctx_id_t)ctx;
1091 return GSS_S_COMPLETE;
1092 }
1093 #endif /* LEAN_CLIENT */
1094
1095 OM_uint32 KRB5_CALLCONV
iakerb_gss_inquire_context(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_name_t * src_name,gss_name_t * targ_name,OM_uint32 * lifetime_rec,gss_OID * mech_type,OM_uint32 * ctx_flags,int * initiate,int * opened)1096 iakerb_gss_inquire_context(OM_uint32 *minor_status,
1097 gss_ctx_id_t context_handle, gss_name_t *src_name,
1098 gss_name_t *targ_name, OM_uint32 *lifetime_rec,
1099 gss_OID *mech_type, OM_uint32 *ctx_flags,
1100 int *initiate, int *opened)
1101 {
1102 OM_uint32 ret;
1103 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1104
1105 if (src_name != NULL)
1106 *src_name = GSS_C_NO_NAME;
1107 if (targ_name != NULL)
1108 *targ_name = GSS_C_NO_NAME;
1109 if (lifetime_rec != NULL)
1110 *lifetime_rec = 0;
1111 if (mech_type != NULL)
1112 *mech_type = (gss_OID)gss_mech_iakerb;
1113 if (ctx_flags != NULL)
1114 *ctx_flags = 0;
1115 if (initiate != NULL)
1116 *initiate = ctx->initiate;
1117 if (opened != NULL)
1118 *opened = ctx->established;
1119
1120 if (ctx->gssc == GSS_C_NO_CONTEXT)
1121 return GSS_S_COMPLETE;
1122
1123 ret = krb5_gss_inquire_context(minor_status, ctx->gssc, src_name,
1124 targ_name, lifetime_rec, mech_type,
1125 ctx_flags, initiate, opened);
1126
1127 if (!ctx->established) {
1128 /* Report IAKERB as the mech OID until the context is established. */
1129 if (mech_type != NULL)
1130 *mech_type = (gss_OID)gss_mech_iakerb;
1131
1132 /* We don't support exporting partially-established contexts. */
1133 if (ctx_flags != NULL)
1134 *ctx_flags &= ~GSS_C_TRANS_FLAG;
1135 }
1136
1137 return ret;
1138 }
1139
1140 OM_uint32 KRB5_CALLCONV
iakerb_gss_wrap_size_limit(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size)1141 iakerb_gss_wrap_size_limit(OM_uint32 *minor_status,
1142 gss_ctx_id_t context_handle, int conf_req_flag,
1143 gss_qop_t qop_req, OM_uint32 req_output_size,
1144 OM_uint32 *max_input_size)
1145 {
1146 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1147
1148 if (ctx->gssc == GSS_C_NO_CONTEXT)
1149 return GSS_S_NO_CONTEXT;
1150
1151 return krb5_gss_wrap_size_limit(minor_status, ctx->gssc, conf_req_flag,
1152 qop_req, req_output_size, max_input_size);
1153 }
1154
1155 OM_uint32 KRB5_CALLCONV
iakerb_gss_get_mic(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_qop_t qop_req,gss_buffer_t message_buffer,gss_buffer_t message_token)1156 iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1157 gss_qop_t qop_req, gss_buffer_t message_buffer,
1158 gss_buffer_t message_token)
1159 {
1160 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1161
1162 if (ctx->gssc == GSS_C_NO_CONTEXT)
1163 return GSS_S_NO_CONTEXT;
1164
1165 return krb5_gss_get_mic(minor_status, ctx->gssc, qop_req, message_buffer,
1166 message_token);
1167 }
1168
1169 OM_uint32 KRB5_CALLCONV
iakerb_gss_verify_mic(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_buffer_t msg_buffer,gss_buffer_t token_buffer,gss_qop_t * qop_state)1170 iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1171 gss_buffer_t msg_buffer, gss_buffer_t token_buffer,
1172 gss_qop_t *qop_state)
1173 {
1174 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1175
1176 if (ctx->gssc == GSS_C_NO_CONTEXT)
1177 return GSS_S_NO_CONTEXT;
1178
1179 return krb5_gss_verify_mic(minor_status, ctx->gssc, msg_buffer,
1180 token_buffer, qop_state);
1181 }
1182
1183 OM_uint32 KRB5_CALLCONV
iakerb_gss_inquire_sec_context_by_oid(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID desired_object,gss_buffer_set_t * data_set)1184 iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
1185 const gss_ctx_id_t context_handle,
1186 const gss_OID desired_object,
1187 gss_buffer_set_t *data_set)
1188 {
1189 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1190
1191 if (ctx->gssc == GSS_C_NO_CONTEXT)
1192 return GSS_S_UNAVAILABLE;
1193
1194 return krb5_gss_inquire_sec_context_by_oid(minor_status, ctx->gssc,
1195 desired_object, data_set);
1196 }
1197
1198 OM_uint32 KRB5_CALLCONV
iakerb_gss_set_sec_context_option(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,const gss_OID desired_object,const gss_buffer_t value)1199 iakerb_gss_set_sec_context_option(OM_uint32 *minor_status,
1200 gss_ctx_id_t *context_handle,
1201 const gss_OID desired_object,
1202 const gss_buffer_t value)
1203 {
1204 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
1205
1206 if (ctx == NULL || ctx->gssc == GSS_C_NO_CONTEXT)
1207 return GSS_S_UNAVAILABLE;
1208
1209 return krb5_gss_set_sec_context_option(minor_status, &ctx->gssc,
1210 desired_object, value);
1211 }
1212
1213 OM_uint32 KRB5_CALLCONV
iakerb_gss_wrap_iov(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,int * conf_state,gss_iov_buffer_desc * iov,int iov_count)1214 iakerb_gss_wrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1215 int conf_req_flag, gss_qop_t qop_req, int *conf_state,
1216 gss_iov_buffer_desc *iov, int iov_count)
1217 {
1218 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1219
1220 if (ctx->gssc == GSS_C_NO_CONTEXT)
1221 return GSS_S_NO_CONTEXT;
1222
1223 return krb5_gss_wrap_iov(minor_status, ctx->gssc, conf_req_flag, qop_req,
1224 conf_state, iov, iov_count);
1225 }
1226
1227 OM_uint32 KRB5_CALLCONV
iakerb_gss_unwrap_iov(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int * conf_state,gss_qop_t * qop_state,gss_iov_buffer_desc * iov,int iov_count)1228 iakerb_gss_unwrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1229 int *conf_state, gss_qop_t *qop_state,
1230 gss_iov_buffer_desc *iov, int iov_count)
1231 {
1232 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1233
1234 if (ctx->gssc == GSS_C_NO_CONTEXT)
1235 return GSS_S_NO_CONTEXT;
1236
1237 return krb5_gss_unwrap_iov(minor_status, ctx->gssc, conf_state, qop_state,
1238 iov, iov_count);
1239 }
1240
1241 OM_uint32 KRB5_CALLCONV
iakerb_gss_wrap_iov_length(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,int * conf_state,gss_iov_buffer_desc * iov,int iov_count)1242 iakerb_gss_wrap_iov_length(OM_uint32 *minor_status,
1243 gss_ctx_id_t context_handle, int conf_req_flag,
1244 gss_qop_t qop_req, int *conf_state,
1245 gss_iov_buffer_desc *iov, int iov_count)
1246 {
1247 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1248
1249 if (ctx->gssc == GSS_C_NO_CONTEXT)
1250 return GSS_S_NO_CONTEXT;
1251
1252 return krb5_gss_wrap_iov_length(minor_status, ctx->gssc, conf_req_flag,
1253 qop_req, conf_state, iov, iov_count);
1254 }
1255
1256 OM_uint32 KRB5_CALLCONV
iakerb_gss_pseudo_random(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int prf_key,const gss_buffer_t prf_in,ssize_t desired_output_len,gss_buffer_t prf_out)1257 iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1258 int prf_key, const gss_buffer_t prf_in,
1259 ssize_t desired_output_len, gss_buffer_t prf_out)
1260 {
1261 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1262
1263 if (ctx->gssc == GSS_C_NO_CONTEXT)
1264 return GSS_S_NO_CONTEXT;
1265
1266 return krb5_gss_pseudo_random(minor_status, ctx->gssc, prf_key, prf_in,
1267 desired_output_len, prf_out);
1268 }
1269
1270 OM_uint32 KRB5_CALLCONV
iakerb_gss_get_mic_iov(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_qop_t qop_req,gss_iov_buffer_desc * iov,int iov_count)1271 iakerb_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1272 gss_qop_t qop_req, gss_iov_buffer_desc *iov,
1273 int iov_count)
1274 {
1275 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1276
1277 if (ctx->gssc == GSS_C_NO_CONTEXT)
1278 return GSS_S_NO_CONTEXT;
1279
1280 return krb5_gss_get_mic_iov(minor_status, ctx->gssc, qop_req, iov,
1281 iov_count);
1282 }
1283
1284 OM_uint32 KRB5_CALLCONV
iakerb_gss_verify_mic_iov(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_qop_t * qop_state,gss_iov_buffer_desc * iov,int iov_count)1285 iakerb_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1286 gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
1287 int iov_count)
1288 {
1289 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1290
1291 if (ctx->gssc == GSS_C_NO_CONTEXT)
1292 return GSS_S_NO_CONTEXT;
1293
1294 return krb5_gss_verify_mic_iov(minor_status, ctx->gssc, qop_state, iov,
1295 iov_count);
1296 }
1297
1298 OM_uint32 KRB5_CALLCONV
iakerb_gss_get_mic_iov_length(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_qop_t qop_req,gss_iov_buffer_desc * iov,int iov_count)1299 iakerb_gss_get_mic_iov_length(OM_uint32 *minor_status,
1300 gss_ctx_id_t context_handle, gss_qop_t qop_req,
1301 gss_iov_buffer_desc *iov, int iov_count)
1302 {
1303 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1304
1305 if (ctx->gssc == GSS_C_NO_CONTEXT)
1306 return GSS_S_NO_CONTEXT;
1307
1308 return krb5_gss_get_mic_iov_length(minor_status, ctx->gssc, qop_req, iov,
1309 iov_count);
1310 }
1311