xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/iakerb.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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, &times);
556             kg_cred_set_initial_refresh(ctx->k5c, cred, &times);
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, &times);
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