~ubuntu-branches/ubuntu/utopic/moonshot-gss-eap/utopic-backports

« back to all changes in this revision

Viewing changes to mech_eap/unwrap_iov.c

  • Committer: Package Import Robot
  • Author(s): Sam Hartman
  • Date: 2014-09-16 08:38:39 UTC
  • Revision ID: package-import@ubuntu.com-20140916083839-ipqco3thb1wcwvs0
Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2011, JANET(UK)
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * 1. Redistributions of source code must retain the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer.
 
11
 *
 
12
 * 2. Redistributions in binary form must reproduce the above copyright
 
13
 *    notice, this list of conditions and the following disclaimer in the
 
14
 *    documentation and/or other materials provided with the distribution.
 
15
 *
 
16
 * 3. Neither the name of JANET(UK) nor the names of its contributors
 
17
 *    may be used to endorse or promote products derived from this software
 
18
 *    without specific prior written permission.
 
19
 *
 
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
21
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
23
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
30
 * SUCH DAMAGE.
 
31
 */
 
32
/*
 
33
 * Copyright 2008 by the Massachusetts Institute of Technology.
 
34
 * All Rights Reserved.
 
35
 *
 
36
 * Export of this software from the United States of America may
 
37
 *   require a specific license from the United States Government.
 
38
 *   It is the responsibility of any person or organization contemplating
 
39
 *   export to obtain such a license before exporting.
 
40
 *
 
41
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 
42
 * distribute this software and its documentation for any purpose and
 
43
 * without fee is hereby granted, provided that the above copyright
 
44
 * notice appear in all copies and that both that copyright notice and
 
45
 * this permission notice appear in supporting documentation, and that
 
46
 * the name of M.I.T. not be used in advertising or publicity pertaining
 
47
 * to distribution of the software without specific, written prior
 
48
 * permission.  Furthermore if you modify this software you must label
 
49
 * your software as modified software and not distribute it in such a
 
50
 * fashion that it might be confused with the original M.I.T. software.
 
51
 * M.I.T. makes no representations about the suitability of
 
52
 * this software for any purpose.  It is provided "as is" without express
 
53
 * or implied warranty.
 
54
 */
 
55
 
 
56
/*
 
57
 * Message protection services: unwrap with scatter-gather API.
 
58
 */
 
59
 
 
60
#include "gssapiP_eap.h"
 
61
 
 
62
/*
 
63
 * Caller must provide TOKEN | DATA | PADDING | TRAILER, except
 
64
 * for DCE in which case it can just provide TOKEN | DATA (must
 
65
 * guarantee that DATA is padded)
 
66
 */
 
67
OM_uint32
 
68
unwrapToken(OM_uint32 *minor,
 
69
            gss_ctx_id_t ctx,
 
70
#ifdef HAVE_HEIMDAL_VERSION
 
71
            krb5_crypto krbCrypto,
 
72
#else
 
73
            krb5_keyblock *unused GSSEAP_UNUSED,
 
74
#endif
 
75
            int *conf_state,
 
76
            gss_qop_t *qop_state,
 
77
            gss_iov_buffer_desc *iov,
 
78
            int iov_count,
 
79
            enum gss_eap_token_type toktype)
 
80
{
 
81
    OM_uint32 major = GSS_S_FAILURE, code;
 
82
    gss_iov_buffer_t header;
 
83
    gss_iov_buffer_t padding;
 
84
    gss_iov_buffer_t trailer;
 
85
    unsigned char flags;
 
86
    unsigned char *ptr = NULL;
 
87
    int keyUsage;
 
88
    size_t rrc, ec;
 
89
    size_t dataLen, assocDataLen;
 
90
    uint64_t seqnum;
 
91
    int valid = 0;
 
92
    int conf_flag = 0;
 
93
    krb5_context krbContext;
 
94
#ifdef HAVE_HEIMDAL_VERSION
 
95
    int freeCrypto = (krbCrypto == NULL);
 
96
#endif
 
97
 
 
98
    GSSEAP_KRB_INIT(&krbContext);
 
99
 
 
100
    *minor = 0;
 
101
 
 
102
    if (qop_state != NULL)
 
103
        *qop_state = GSS_C_QOP_DEFAULT;
 
104
 
 
105
    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
 
106
    GSSEAP_ASSERT(header != NULL);
 
107
 
 
108
    padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
 
109
    if (padding != NULL && padding->buffer.length != 0) {
 
110
        code = GSSEAP_BAD_PADDING_IOV;
 
111
        major = GSS_S_DEFECTIVE_TOKEN;
 
112
        goto cleanup;
 
113
    }
 
114
 
 
115
    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
 
116
 
 
117
    flags = rfc4121Flags(ctx, TRUE);
 
118
 
 
119
    if (toktype == TOK_TYPE_WRAP) {
 
120
        keyUsage = !CTX_IS_INITIATOR(ctx)
 
121
                   ? KEY_USAGE_INITIATOR_SEAL
 
122
                   : KEY_USAGE_ACCEPTOR_SEAL;
 
123
    } else {
 
124
        keyUsage = !CTX_IS_INITIATOR(ctx)
 
125
                   ? KEY_USAGE_INITIATOR_SIGN
 
126
                   : KEY_USAGE_ACCEPTOR_SIGN;
 
127
    }
 
128
 
 
129
    gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
 
130
 
 
131
    ptr = (unsigned char *)header->buffer.value;
 
132
 
 
133
    if (header->buffer.length < 16) {
 
134
        code = GSSEAP_TOK_TRUNC;
 
135
        major = GSS_S_DEFECTIVE_TOKEN;
 
136
        goto cleanup;
 
137
    }
 
138
 
 
139
    if ((ptr[2] & flags) != flags) {
 
140
        code = GSSEAP_BAD_DIRECTION;
 
141
        major = GSS_S_BAD_SIG;
 
142
        goto cleanup;
 
143
    }
 
144
 
 
145
#ifdef HAVE_HEIMDAL_VERSION
 
146
    if (krbCrypto == NULL) {
 
147
        code = krb5_crypto_init(krbContext, &ctx->rfc3961Key,
 
148
                                ETYPE_NULL, &krbCrypto);
 
149
        if (code != 0)
 
150
            goto cleanup;
 
151
    }
 
152
#endif
 
153
 
 
154
    if (toktype == TOK_TYPE_WRAP) {
 
155
        size_t krbTrailerLen;
 
156
 
 
157
        if (load_uint16_be(ptr) != TOK_TYPE_WRAP)
 
158
            goto defective;
 
159
        conf_flag = ((ptr[2] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
 
160
        if (ptr[3] != 0xFF)
 
161
            goto defective;
 
162
        ec = load_uint16_be(ptr + 4);
 
163
        rrc = load_uint16_be(ptr + 6);
 
164
        seqnum = load_uint64_be(ptr + 8);
 
165
 
 
166
        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
 
167
                               conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
 
168
                                           KRB5_CRYPTO_TYPE_CHECKSUM,
 
169
                               &krbTrailerLen);
 
170
        if (code != 0)
 
171
            goto cleanup;
 
172
 
 
173
        /* Deal with RRC */
 
174
        if (trailer == NULL) {
 
175
            size_t desired_rrc = krbTrailerLen;
 
176
 
 
177
            if (conf_flag) {
 
178
                desired_rrc += 16; /* E(Header) */
 
179
 
 
180
                if ((ctx->gssFlags & GSS_C_DCE_STYLE) == 0)
 
181
                    desired_rrc += ec;
 
182
            }
 
183
 
 
184
            /* According to MS, we only need to deal with a fixed RRC for DCE */
 
185
            if (rrc != desired_rrc)
 
186
                goto defective;
 
187
        } else if (rrc != 0) {
 
188
            goto defective;
 
189
        }
 
190
 
 
191
        if (conf_flag) {
 
192
            unsigned char *althdr;
 
193
 
 
194
            /* Decrypt */
 
195
            code = gssEapDecrypt(krbContext,
 
196
                                 ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
 
197
                                 ec, rrc, KRB_CRYPTO_CONTEXT(ctx), keyUsage,
 
198
                                 iov, iov_count);
 
199
            if (code != 0) {
 
200
                major = GSS_S_BAD_SIG;
 
201
                goto cleanup;
 
202
            }
 
203
 
 
204
            /* Validate header integrity */
 
205
            if (trailer == NULL)
 
206
                althdr = (unsigned char *)header->buffer.value + 16 + ec;
 
207
            else
 
208
                althdr = (unsigned char *)trailer->buffer.value + ec;
 
209
 
 
210
            if (load_uint16_be(althdr) != TOK_TYPE_WRAP
 
211
                || althdr[2] != ptr[2]
 
212
                || althdr[3] != ptr[3]
 
213
                || memcmp(althdr + 8, ptr + 8, 8) != 0) {
 
214
                code = GSSEAP_BAD_WRAP_TOKEN;
 
215
                major = GSS_S_BAD_SIG;
 
216
                goto cleanup;
 
217
            }
 
218
        } else {
 
219
            /* Verify checksum: note EC is checksum size here, not padding */
 
220
            if (ec != krbTrailerLen)
 
221
                goto defective;
 
222
 
 
223
            /* Zero EC, RRC before computing checksum */
 
224
            store_uint16_be(0, ptr + 4);
 
225
            store_uint16_be(0, ptr + 6);
 
226
 
 
227
            code = gssEapVerify(krbContext, ctx->checksumType, rrc,
 
228
                                KRB_CRYPTO_CONTEXT(ctx), keyUsage,
 
229
                                iov, iov_count, &valid);
 
230
            if (code != 0 || valid == FALSE) {
 
231
                major = GSS_S_BAD_SIG;
 
232
                goto cleanup;
 
233
            }
 
234
        }
 
235
 
 
236
        major = sequenceCheck(&code, &ctx->seqState, seqnum);
 
237
        if (GSS_ERROR(major))
 
238
            goto cleanup;
 
239
    } else if (toktype == TOK_TYPE_MIC) {
 
240
        if (load_uint16_be(ptr) != toktype)
 
241
            goto defective;
 
242
 
 
243
    verify_mic_1:
 
244
        if (ptr[3] != 0xFF)
 
245
            goto defective;
 
246
        seqnum = load_uint64_be(ptr + 8);
 
247
 
 
248
        /*
 
249
         * Although MIC tokens don't have a RRC, they are similarly
 
250
         * composed of a header and a checksum. So the verify_mic()
 
251
         * can be implemented with a single header buffer, fake the
 
252
         * RRC to the putative trailer length if no trailer buffer.
 
253
         */
 
254
        code = gssEapVerify(krbContext, ctx->checksumType,
 
255
                            trailer != NULL ? 0 : header->buffer.length - 16,
 
256
                            KRB_CRYPTO_CONTEXT(ctx), keyUsage,
 
257
                            iov, iov_count, &valid);
 
258
        if (code != 0 || valid == FALSE) {
 
259
            major = GSS_S_BAD_SIG;
 
260
            goto cleanup;
 
261
        }
 
262
        major = sequenceCheck(&code, &ctx->seqState, seqnum);
 
263
        if (GSS_ERROR(major))
 
264
            goto cleanup;
 
265
    } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
 
266
        if (load_uint16_be(ptr) != TOK_TYPE_DELETE_CONTEXT)
 
267
            goto defective;
 
268
        goto verify_mic_1;
 
269
    } else {
 
270
        goto defective;
 
271
    }
 
272
 
 
273
    if (conf_state != NULL)
 
274
        *conf_state = conf_flag;
 
275
 
 
276
    code = 0;
 
277
    major = GSS_S_COMPLETE;
 
278
    goto cleanup;
 
279
 
 
280
defective:
 
281
    code = GSSEAP_BAD_WRAP_TOKEN;
 
282
    major = GSS_S_DEFECTIVE_TOKEN;
 
283
 
 
284
cleanup:
 
285
    *minor = code;
 
286
#ifdef HAVE_HEIMDAL_VERSION
 
287
    if (freeCrypto && krbCrypto != NULL)
 
288
        krb5_crypto_destroy(krbContext, krbCrypto);
 
289
#endif
 
290
 
 
291
    return major;
 
292
}
 
293
 
 
294
int
 
295
rotateLeft(void *ptr, size_t bufsiz, size_t rc)
 
296
{
 
297
    void *tbuf;
 
298
 
 
299
    if (bufsiz == 0)
 
300
        return 0;
 
301
    rc = rc % bufsiz;
 
302
    if (rc == 0)
 
303
        return 0;
 
304
 
 
305
    tbuf = GSSEAP_MALLOC(rc);
 
306
    if (tbuf == NULL)
 
307
        return ENOMEM;
 
308
 
 
309
    memcpy(tbuf, ptr, rc);
 
310
    memmove(ptr, (char *)ptr + rc, bufsiz - rc);
 
311
    memcpy((char *)ptr + bufsiz - rc, tbuf, rc);
 
312
    GSSEAP_FREE(tbuf);
 
313
 
 
314
    return 0;
 
315
}
 
316
 
 
317
/*
 
318
 * Split a STREAM | SIGN_DATA | DATA into
 
319
 *         HEADER | SIGN_DATA | DATA | PADDING | TRAILER
 
320
 */
 
321
static OM_uint32
 
322
unwrapStream(OM_uint32 *minor,
 
323
             gss_ctx_id_t ctx,
 
324
             int *conf_state,
 
325
             gss_qop_t *qop_state,
 
326
             gss_iov_buffer_desc *iov,
 
327
             int iov_count,
 
328
             enum gss_eap_token_type toktype)
 
329
{
 
330
    unsigned char *ptr;
 
331
    OM_uint32 code = 0, major = GSS_S_FAILURE;
 
332
    krb5_context krbContext;
 
333
    int conf_req_flag;
 
334
    int i = 0, j;
 
335
    gss_iov_buffer_desc *tiov = NULL;
 
336
    gss_iov_buffer_t stream, data = NULL;
 
337
    gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;
 
338
#ifdef HAVE_HEIMDAL_VERSION
 
339
    krb5_crypto krbCrypto = NULL;
 
340
#endif
 
341
 
 
342
    GSSEAP_KRB_INIT(&krbContext);
 
343
 
 
344
    GSSEAP_ASSERT(toktype == TOK_TYPE_WRAP);
 
345
 
 
346
    if (toktype != TOK_TYPE_WRAP) {
 
347
        code = GSSEAP_WRONG_TOK_ID;
 
348
        goto cleanup;
 
349
    }
 
350
 
 
351
    stream = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM);
 
352
    GSSEAP_ASSERT(stream != NULL);
 
353
 
 
354
    if (stream->buffer.length < 16) {
 
355
        major = GSS_S_DEFECTIVE_TOKEN;
 
356
        goto cleanup;
 
357
    }
 
358
 
 
359
    ptr = (unsigned char *)stream->buffer.value;
 
360
    ptr += 2; /* skip token type */
 
361
 
 
362
    tiov = (gss_iov_buffer_desc *)GSSEAP_CALLOC((size_t)iov_count + 2,
 
363
                                                sizeof(gss_iov_buffer_desc));
 
364
    if (tiov == NULL) {
 
365
        code = ENOMEM;
 
366
        goto cleanup;
 
367
    }
 
368
 
 
369
    /* HEADER */
 
370
    theader = &tiov[i++];
 
371
    theader->type = GSS_IOV_BUFFER_TYPE_HEADER;
 
372
    theader->buffer.value = stream->buffer.value;
 
373
    theader->buffer.length = 16;
 
374
 
 
375
    /* n[SIGN_DATA] | DATA | m[SIGN_DATA] */
 
376
    for (j = 0; j < iov_count; j++) {
 
377
        OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[j].type);
 
378
 
 
379
        if (type == GSS_IOV_BUFFER_TYPE_DATA) {
 
380
            if (data != NULL) {
 
381
                /* only a single DATA buffer can appear */
 
382
                code = GSSEAP_BAD_STREAM_IOV;
 
383
                goto cleanup;
 
384
            }
 
385
 
 
386
            data = &iov[j];
 
387
            tdata = &tiov[i];
 
388
        }
 
389
        if (type == GSS_IOV_BUFFER_TYPE_DATA ||
 
390
            type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
 
391
            tiov[i++] = iov[j];
 
392
    }
 
393
 
 
394
    if (data == NULL) {
 
395
        /* a single DATA buffer must be present */
 
396
        code = GSSEAP_BAD_STREAM_IOV;
 
397
        goto cleanup;
 
398
    }
 
399
 
 
400
    /* PADDING | TRAILER */
 
401
    tpadding = &tiov[i++];
 
402
    tpadding->type = GSS_IOV_BUFFER_TYPE_PADDING;
 
403
    tpadding->buffer.length = 0;
 
404
    tpadding->buffer.value = NULL;
 
405
 
 
406
    ttrailer = &tiov[i++];
 
407
    ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER;
 
408
 
 
409
#ifdef HAVE_HEIMDAL_VERSION
 
410
    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
 
411
    if (code != 0)
 
412
        goto cleanup;
 
413
#endif
 
414
 
 
415
    {
 
416
        size_t ec, rrc;
 
417
        size_t krbHeaderLen = 0;
 
418
        size_t krbTrailerLen = 0;
 
419
 
 
420
        conf_req_flag = ((ptr[0] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
 
421
        ec = conf_req_flag ? load_uint16_be(ptr + 2) : 0;
 
422
        rrc = load_uint16_be(ptr + 4);
 
423
 
 
424
        if (rrc != 0) {
 
425
            code = rotateLeft((unsigned char *)stream->buffer.value + 16,
 
426
                              stream->buffer.length - 16, rrc);
 
427
            if (code != 0)
 
428
                goto cleanup;
 
429
            store_uint16_be(0, ptr + 4); /* set RRC to zero */
 
430
        }
 
431
 
 
432
        if (conf_req_flag) {
 
433
            code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
 
434
                                    KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
 
435
            if (code != 0)
 
436
                goto cleanup;
 
437
            theader->buffer.length += krbHeaderLen; /* length validated later */
 
438
        }
 
439
 
 
440
        /* no PADDING for CFX, EC is used instead */
 
441
        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
 
442
                               conf_req_flag
 
443
                                  ? KRB5_CRYPTO_TYPE_TRAILER
 
444
                                  : KRB5_CRYPTO_TYPE_CHECKSUM,
 
445
                               &krbTrailerLen);
 
446
        if (code != 0)
 
447
            goto cleanup;
 
448
 
 
449
        ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) +
 
450
                                  krbTrailerLen;
 
451
        ttrailer->buffer.value = (unsigned char *)stream->buffer.value +
 
452
            stream->buffer.length - ttrailer->buffer.length;
 
453
    }
 
454
 
 
455
    /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/
 
456
    /* CFX: GSS-Header | Kerb-Header | Data  |     | EC | E(Header) | Kerb-Trailer */
 
457
    /* GSS: -------GSS-HEADER--------+-DATA--+-PAD-+----------GSS-TRAILER----------*/
 
458
 
 
459
    /* validate lengths */
 
460
    if (stream->buffer.length < theader->buffer.length +
 
461
        tpadding->buffer.length +
 
462
        ttrailer->buffer.length) {
 
463
        major = GSS_S_DEFECTIVE_TOKEN;
 
464
        code = GSSEAP_TOK_TRUNC;
 
465
        goto cleanup;
 
466
    }
 
467
 
 
468
    /* setup data */
 
469
    tdata->buffer.length = stream->buffer.length - ttrailer->buffer.length -
 
470
        tpadding->buffer.length - theader->buffer.length;
 
471
 
 
472
    GSSEAP_ASSERT(data != NULL);
 
473
 
 
474
    if (data->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
 
475
        code = gssEapAllocIov(tdata, tdata->buffer.length);
 
476
        if (code != 0)
 
477
            goto cleanup;
 
478
 
 
479
        memcpy(tdata->buffer.value,
 
480
               (unsigned char *)stream->buffer.value + theader->buffer.length,
 
481
               tdata->buffer.length);
 
482
    } else {
 
483
        tdata->buffer.value = (unsigned char *)stream->buffer.value +
 
484
                              theader->buffer.length;
 
485
    }
 
486
 
 
487
    GSSEAP_ASSERT(i <= iov_count + 2);
 
488
 
 
489
    major = unwrapToken(&code, ctx, KRB_CRYPTO_CONTEXT(ctx),
 
490
                        conf_state, qop_state, tiov, i, toktype);
 
491
    if (major == GSS_S_COMPLETE) {
 
492
        *data = *tdata;
 
493
    } else if (tdata->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
 
494
        OM_uint32 tmp;
 
495
 
 
496
        gss_release_buffer(&tmp, &tdata->buffer);
 
497
        tdata->type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
 
498
    }
 
499
 
 
500
cleanup:
 
501
    if (tiov != NULL)
 
502
        GSSEAP_FREE(tiov);
 
503
#ifdef HAVE_HEIMDAL_VERSION
 
504
    if (krbCrypto != NULL)
 
505
        krb5_crypto_destroy(krbContext, krbCrypto);
 
506
#endif
 
507
 
 
508
    *minor = code;
 
509
 
 
510
    return major;
 
511
}
 
512
 
 
513
OM_uint32
 
514
gssEapUnwrapOrVerifyMIC(OM_uint32 *minor,
 
515
                        gss_ctx_id_t ctx,
 
516
                        int *conf_state,
 
517
                        gss_qop_t *qop_state,
 
518
                        gss_iov_buffer_desc *iov,
 
519
                        int iov_count,
 
520
                        enum gss_eap_token_type toktype)
 
521
{
 
522
    OM_uint32 major;
 
523
 
 
524
    if (ctx->encryptionType == ENCTYPE_NULL) {
 
525
        *minor = GSSEAP_KEY_UNAVAILABLE;
 
526
        return GSS_S_UNAVAILABLE;
 
527
    }
 
528
 
 
529
    if (gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) {
 
530
        major = unwrapStream(minor, ctx, conf_state, qop_state,
 
531
                             iov, iov_count, toktype);
 
532
    } else {
 
533
        major = unwrapToken(minor, ctx,
 
534
                            NULL, /* krbCrypto */
 
535
                            conf_state, qop_state,
 
536
                            iov, iov_count, toktype);
 
537
    }
 
538
 
 
539
    return major;
 
540
}
 
541
 
 
542
OM_uint32 GSSAPI_CALLCONV
 
543
gss_unwrap_iov(OM_uint32 *minor,
 
544
               gss_ctx_id_t ctx,
 
545
               int *conf_state,
 
546
               gss_qop_t *qop_state,
 
547
               gss_iov_buffer_desc *iov,
 
548
               int iov_count)
 
549
{
 
550
    OM_uint32 major;
 
551
 
 
552
    if (ctx == GSS_C_NO_CONTEXT) {
 
553
        *minor = EINVAL;
 
554
        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
 
555
    }
 
556
 
 
557
    *minor = 0;
 
558
 
 
559
    GSSEAP_MUTEX_LOCK(&ctx->mutex);
 
560
 
 
561
    if (!CTX_IS_ESTABLISHED(ctx)) {
 
562
        major = GSS_S_NO_CONTEXT;
 
563
        *minor = GSSEAP_CONTEXT_INCOMPLETE;
 
564
        goto cleanup;
 
565
    }
 
566
 
 
567
    major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state,
 
568
                                    iov, iov_count, TOK_TYPE_WRAP);
 
569
    if (GSS_ERROR(major))
 
570
        goto cleanup;
 
571
 
 
572
cleanup:
 
573
    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
 
574
 
 
575
    return major;
 
576
}