~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/gssapi/krb5/cfx.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2003, PADL Software Pty Ltd.
 
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 PADL Software 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 PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
 
21
 * 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 PADL SOFTWARE 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
#include "krb5/gsskrb5_locl.h"
 
34
 
 
35
RCSID("$Id$");
 
36
 
 
37
/*
 
38
 * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt
 
39
 */
 
40
 
 
41
#define CFXSentByAcceptor       (1 << 0)
 
42
#define CFXSealed               (1 << 1)
 
43
#define CFXAcceptorSubkey       (1 << 2)
 
44
 
 
45
krb5_error_code
 
46
_gsskrb5cfx_wrap_length_cfx(const gsskrb5_ctx context_handle,
 
47
                            krb5_context context,
 
48
                            krb5_crypto crypto,
 
49
                            int conf_req_flag,
 
50
                            size_t input_length,
 
51
                            size_t *output_length,
 
52
                            size_t *cksumsize,
 
53
                            uint16_t *padlength)
 
54
{
 
55
    krb5_error_code ret;
 
56
    krb5_cksumtype type;
 
57
 
 
58
    /* 16-byte header is always first */
 
59
    *output_length = sizeof(gss_cfx_wrap_token_desc);
 
60
    *padlength = 0;
 
61
 
 
62
    ret = krb5_crypto_get_checksum_type(context, crypto, &type);
 
63
    if (ret)
 
64
        return ret;
 
65
 
 
66
    ret = krb5_checksumsize(context, type, cksumsize);
 
67
    if (ret)
 
68
        return ret;
 
69
 
 
70
    if (conf_req_flag) {
 
71
        size_t padsize;
 
72
 
 
73
        /* Header is concatenated with data before encryption */
 
74
        input_length += sizeof(gss_cfx_wrap_token_desc);
 
75
 
 
76
        if (IS_DCE_STYLE(context_handle)) {
 
77
                ret = krb5_crypto_getblocksize(context, crypto, &padsize);
 
78
        } else {
 
79
                ret = krb5_crypto_getpadsize(context, crypto, &padsize);
 
80
        }
 
81
        if (ret) {
 
82
            return ret;
 
83
        }
 
84
        if (padsize > 1) {
 
85
            /* XXX check this */
 
86
            *padlength = padsize - (input_length % padsize);
 
87
 
 
88
            /* We add the pad ourselves (noted here for completeness only) */
 
89
            input_length += *padlength;
 
90
        }
 
91
 
 
92
        *output_length += krb5_get_wrapped_length(context,
 
93
                                                  crypto, input_length);
 
94
    } else {
 
95
        /* Checksum is concatenated with data */
 
96
        *output_length += input_length + *cksumsize;
 
97
    }
 
98
 
 
99
    assert(*output_length > input_length);
 
100
 
 
101
    return 0;
 
102
}
 
103
 
 
104
krb5_error_code
 
105
_gsskrb5cfx_max_wrap_length_cfx(krb5_context context,
 
106
                                krb5_crypto crypto,
 
107
                                int conf_req_flag,
 
108
                                size_t input_length,
 
109
                                OM_uint32 *output_length)
 
110
{
 
111
    krb5_error_code ret;
 
112
 
 
113
    *output_length = 0;
 
114
 
 
115
    /* 16-byte header is always first */
 
116
    if (input_length < 16)
 
117
        return 0;
 
118
    input_length -= 16;
 
119
 
 
120
    if (conf_req_flag) {
 
121
        size_t wrapped_size, sz;
 
122
 
 
123
        wrapped_size = input_length + 1;
 
124
        do {
 
125
            wrapped_size--;
 
126
            sz = krb5_get_wrapped_length(context,
 
127
                                         crypto, wrapped_size);
 
128
        } while (wrapped_size && sz > input_length);
 
129
        if (wrapped_size == 0) {
 
130
            *output_length = 0;
 
131
            return 0;
 
132
        }
 
133
 
 
134
        /* inner header */
 
135
        if (wrapped_size < 16) {
 
136
            *output_length = 0;
 
137
            return 0;
 
138
        }
 
139
        wrapped_size -= 16;
 
140
 
 
141
        *output_length = wrapped_size;
 
142
    } else {
 
143
        krb5_cksumtype type;
 
144
        size_t cksumsize;
 
145
 
 
146
        ret = krb5_crypto_get_checksum_type(context, crypto, &type);
 
147
        if (ret)
 
148
            return ret;
 
149
 
 
150
        ret = krb5_checksumsize(context, type, &cksumsize);
 
151
        if (ret)
 
152
            return ret;
 
153
 
 
154
        if (input_length < cksumsize)
 
155
            return 0;
 
156
 
 
157
        /* Checksum is concatenated with data */
 
158
        *output_length = input_length - cksumsize;
 
159
    }
 
160
 
 
161
    return 0;
 
162
}
 
163
 
 
164
 
 
165
OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
 
166
                                const gsskrb5_ctx context_handle,
 
167
                                krb5_context context,
 
168
                                int conf_req_flag,
 
169
                                gss_qop_t qop_req,
 
170
                                OM_uint32 req_output_size,
 
171
                                OM_uint32 *max_input_size,
 
172
                                krb5_keyblock *key)
 
173
{
 
174
    krb5_error_code ret;
 
175
    krb5_crypto crypto;
 
176
 
 
177
    ret = krb5_crypto_init(context, key, 0, &crypto);
 
178
    if (ret != 0) {
 
179
        *minor_status = ret;
 
180
        return GSS_S_FAILURE;
 
181
    }
 
182
 
 
183
    ret = _gsskrb5cfx_max_wrap_length_cfx(context, crypto, conf_req_flag,
 
184
                                          req_output_size, max_input_size);
 
185
    if (ret != 0) {
 
186
        *minor_status = ret;
 
187
        krb5_crypto_destroy(context, crypto);
 
188
        return GSS_S_FAILURE;
 
189
    }
 
190
 
 
191
    krb5_crypto_destroy(context, crypto);
 
192
 
 
193
    return GSS_S_COMPLETE;
 
194
}
 
195
 
 
196
/*
 
197
 * Rotate "rrc" bytes to the front or back
 
198
 */
 
199
 
 
200
static krb5_error_code
 
201
rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate)
 
202
{
 
203
    u_char *tmp, buf[256];
 
204
    size_t left;
 
205
 
 
206
    if (len == 0)
 
207
        return 0;
 
208
 
 
209
    rrc %= len;
 
210
 
 
211
    if (rrc == 0)
 
212
        return 0;
 
213
 
 
214
    left = len - rrc;
 
215
 
 
216
    if (rrc <= sizeof(buf)) {
 
217
        tmp = buf;
 
218
    } else {
 
219
        tmp = malloc(rrc);
 
220
        if (tmp == NULL)
 
221
            return ENOMEM;
 
222
    }
 
223
 
 
224
    if (unrotate) {
 
225
        memcpy(tmp, data, rrc);
 
226
        memmove(data, (u_char *)data + rrc, left);
 
227
        memcpy((u_char *)data + left, tmp, rrc);
 
228
    } else {
 
229
        memcpy(tmp, (u_char *)data + left, rrc);
 
230
        memmove((u_char *)data + rrc, data, left);
 
231
        memcpy(data, tmp, rrc);
 
232
    }
 
233
 
 
234
    if (rrc > sizeof(buf))
 
235
        free(tmp);
 
236
 
 
237
    return 0;
 
238
}
 
239
 
 
240
OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
 
241
                           const gsskrb5_ctx context_handle,
 
242
                           krb5_context context,
 
243
                           int conf_req_flag,
 
244
                           gss_qop_t qop_req,
 
245
                           const gss_buffer_t input_message_buffer,
 
246
                           int *conf_state,
 
247
                           gss_buffer_t output_message_buffer,
 
248
                           krb5_keyblock *key)
 
249
{
 
250
    krb5_crypto crypto;
 
251
    gss_cfx_wrap_token token;
 
252
    krb5_error_code ret;
 
253
    unsigned usage;
 
254
    krb5_data cipher;
 
255
    size_t wrapped_len, cksumsize;
 
256
    uint16_t padlength, rrc = 0;
 
257
    int32_t seq_number;
 
258
    u_char *p;
 
259
 
 
260
    ret = krb5_crypto_init(context, key, 0, &crypto);
 
261
    if (ret != 0) {
 
262
        *minor_status = ret;
 
263
        return GSS_S_FAILURE;
 
264
    }
 
265
 
 
266
    ret = _gsskrb5cfx_wrap_length_cfx(context_handle, context,
 
267
                                      crypto, conf_req_flag,
 
268
                                      input_message_buffer->length,
 
269
                                      &wrapped_len, &cksumsize, &padlength);
 
270
    if (ret != 0) {
 
271
        *minor_status = ret;
 
272
        krb5_crypto_destroy(context, crypto);
 
273
        return GSS_S_FAILURE;
 
274
    }
 
275
 
 
276
    /* Always rotate encrypted token (if any) and checksum to header */
 
277
    rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;
 
278
 
 
279
    output_message_buffer->length = wrapped_len;
 
280
    output_message_buffer->value = malloc(output_message_buffer->length);
 
281
    if (output_message_buffer->value == NULL) {
 
282
        *minor_status = ENOMEM;
 
283
        krb5_crypto_destroy(context, crypto);
 
284
        return GSS_S_FAILURE;
 
285
    }
 
286
 
 
287
    p = output_message_buffer->value;
 
288
    token = (gss_cfx_wrap_token)p;
 
289
    token->TOK_ID[0] = 0x05;
 
290
    token->TOK_ID[1] = 0x04;
 
291
    token->Flags     = 0;
 
292
    token->Filler    = 0xFF;
 
293
    if ((context_handle->more_flags & LOCAL) == 0)
 
294
        token->Flags |= CFXSentByAcceptor;
 
295
    if (context_handle->more_flags & ACCEPTOR_SUBKEY)
 
296
        token->Flags |= CFXAcceptorSubkey;
 
297
    if (conf_req_flag) {
 
298
        /*
 
299
         * In Wrap tokens with confidentiality, the EC field is
 
300
         * used to encode the size (in bytes) of the random filler.
 
301
         */
 
302
        token->Flags |= CFXSealed;
 
303
        token->EC[0] = (padlength >> 8) & 0xFF;
 
304
        token->EC[1] = (padlength >> 0) & 0xFF;
 
305
    } else {
 
306
        /*
 
307
         * In Wrap tokens without confidentiality, the EC field is
 
308
         * used to encode the size (in bytes) of the trailing
 
309
         * checksum.
 
310
         *
 
311
         * This is not used in the checksum calcuation itself,
 
312
         * because the checksum length could potentially vary
 
313
         * depending on the data length.
 
314
         */
 
315
        token->EC[0] = 0;
 
316
        token->EC[1] = 0;
 
317
    }
 
318
 
 
319
    /*
 
320
     * In Wrap tokens that provide for confidentiality, the RRC
 
321
     * field in the header contains the hex value 00 00 before
 
322
     * encryption.
 
323
     *
 
324
     * In Wrap tokens that do not provide for confidentiality,
 
325
     * both the EC and RRC fields in the appended checksum
 
326
     * contain the hex value 00 00 for the purpose of calculating
 
327
     * the checksum.
 
328
     */
 
329
    token->RRC[0] = 0;
 
330
    token->RRC[1] = 0;
 
331
 
 
332
    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 
333
    krb5_auth_con_getlocalseqnumber(context,
 
334
                                    context_handle->auth_context,
 
335
                                    &seq_number);
 
336
    _gsskrb5_encode_be_om_uint32(0,          &token->SND_SEQ[0]);
 
337
    _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
 
338
    krb5_auth_con_setlocalseqnumber(context,
 
339
                                    context_handle->auth_context,
 
340
                                    ++seq_number);
 
341
    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
342
 
 
343
    /*
 
344
     * If confidentiality is requested, the token header is
 
345
     * appended to the plaintext before encryption; the resulting
 
346
     * token is {"header" | encrypt(plaintext | pad | "header")}.
 
347
     *
 
348
     * If no confidentiality is requested, the checksum is
 
349
     * calculated over the plaintext concatenated with the
 
350
     * token header.
 
351
     */
 
352
    if (context_handle->more_flags & LOCAL) {
 
353
        usage = KRB5_KU_USAGE_INITIATOR_SEAL;
 
354
    } else {
 
355
        usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
 
356
    }
 
357
 
 
358
    if (conf_req_flag) {
 
359
        /*
 
360
         * Any necessary padding is added here to ensure that the
 
361
         * encrypted token header is always at the end of the
 
362
         * ciphertext.
 
363
         *
 
364
         * The specification does not require that the padding
 
365
         * bytes are initialized.
 
366
         */
 
367
        p += sizeof(*token);
 
368
        memcpy(p, input_message_buffer->value, input_message_buffer->length);
 
369
        memset(p + input_message_buffer->length, 0xFF, padlength);
 
370
        memcpy(p + input_message_buffer->length + padlength,
 
371
               token, sizeof(*token));
 
372
 
 
373
        ret = krb5_encrypt(context, crypto,
 
374
                           usage, p,
 
375
                           input_message_buffer->length + padlength +
 
376
                                sizeof(*token),
 
377
                           &cipher);
 
378
        if (ret != 0) {
 
379
            *minor_status = ret;
 
380
            krb5_crypto_destroy(context, crypto);
 
381
            _gsskrb5_release_buffer(minor_status, output_message_buffer);
 
382
            return GSS_S_FAILURE;
 
383
        }
 
384
        assert(sizeof(*token) + cipher.length == wrapped_len);
 
385
        token->RRC[0] = (rrc >> 8) & 0xFF;
 
386
        token->RRC[1] = (rrc >> 0) & 0xFF;
 
387
 
 
388
        /*
 
389
         * this is really ugly, but needed against windows
 
390
         * for DCERPC, as windows rotates by EC+RRC.
 
391
         */
 
392
        if (IS_DCE_STYLE(context_handle)) {
 
393
                ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);
 
394
        } else {
 
395
                ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
 
396
        }
 
397
        if (ret != 0) {
 
398
            *minor_status = ret;
 
399
            krb5_crypto_destroy(context, crypto);
 
400
            _gsskrb5_release_buffer(minor_status, output_message_buffer);
 
401
            return GSS_S_FAILURE;
 
402
        }
 
403
        memcpy(p, cipher.data, cipher.length);
 
404
        krb5_data_free(&cipher);
 
405
    } else {
 
406
        char *buf;
 
407
        Checksum cksum;
 
408
 
 
409
        buf = malloc(input_message_buffer->length + sizeof(*token));
 
410
        if (buf == NULL) {
 
411
            *minor_status = ENOMEM;
 
412
            krb5_crypto_destroy(context, crypto);
 
413
            _gsskrb5_release_buffer(minor_status, output_message_buffer);
 
414
            return GSS_S_FAILURE;
 
415
        }
 
416
        memcpy(buf, input_message_buffer->value, input_message_buffer->length);
 
417
        memcpy(buf + input_message_buffer->length, token, sizeof(*token));
 
418
 
 
419
        ret = krb5_create_checksum(context, crypto,
 
420
                                   usage, 0, buf,
 
421
                                   input_message_buffer->length +
 
422
                                        sizeof(*token),
 
423
                                   &cksum);
 
424
        if (ret != 0) {
 
425
            *minor_status = ret;
 
426
            krb5_crypto_destroy(context, crypto);
 
427
            _gsskrb5_release_buffer(minor_status, output_message_buffer);
 
428
            free(buf);
 
429
            return GSS_S_FAILURE;
 
430
        }
 
431
 
 
432
        free(buf);
 
433
 
 
434
        assert(cksum.checksum.length == cksumsize);
 
435
        token->EC[0] =  (cksum.checksum.length >> 8) & 0xFF;
 
436
        token->EC[1] =  (cksum.checksum.length >> 0) & 0xFF;
 
437
        token->RRC[0] = (rrc >> 8) & 0xFF;
 
438
        token->RRC[1] = (rrc >> 0) & 0xFF;
 
439
 
 
440
        p += sizeof(*token);
 
441
        memcpy(p, input_message_buffer->value, input_message_buffer->length);
 
442
        memcpy(p + input_message_buffer->length,
 
443
               cksum.checksum.data, cksum.checksum.length);
 
444
 
 
445
        ret = rrc_rotate(p,
 
446
            input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
 
447
        if (ret != 0) {
 
448
            *minor_status = ret;
 
449
            krb5_crypto_destroy(context, crypto);
 
450
            _gsskrb5_release_buffer(minor_status, output_message_buffer);
 
451
            free_Checksum(&cksum);
 
452
            return GSS_S_FAILURE;
 
453
        }
 
454
        free_Checksum(&cksum);
 
455
    }
 
456
 
 
457
    krb5_crypto_destroy(context, crypto);
 
458
 
 
459
    if (conf_state != NULL) {
 
460
        *conf_state = conf_req_flag;
 
461
    }
 
462
 
 
463
    *minor_status = 0;
 
464
    return GSS_S_COMPLETE;
 
465
}
 
466
 
 
467
OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
 
468
                             const gsskrb5_ctx context_handle,
 
469
                             krb5_context context,
 
470
                             const gss_buffer_t input_message_buffer,
 
471
                             gss_buffer_t output_message_buffer,
 
472
                             int *conf_state,
 
473
                             gss_qop_t *qop_state,
 
474
                             krb5_keyblock *key)
 
475
{
 
476
    krb5_crypto crypto;
 
477
    gss_cfx_wrap_token token;
 
478
    u_char token_flags;
 
479
    krb5_error_code ret;
 
480
    unsigned usage;
 
481
    krb5_data data;
 
482
    uint16_t ec, rrc;
 
483
    OM_uint32 seq_number_lo, seq_number_hi;
 
484
    size_t len;
 
485
    u_char *p;
 
486
 
 
487
    *minor_status = 0;
 
488
 
 
489
    if (input_message_buffer->length < sizeof(*token)) {
 
490
        return GSS_S_DEFECTIVE_TOKEN;
 
491
    }
 
492
 
 
493
    p = input_message_buffer->value;
 
494
 
 
495
    token = (gss_cfx_wrap_token)p;
 
496
 
 
497
    if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
 
498
        return GSS_S_DEFECTIVE_TOKEN;
 
499
    }
 
500
 
 
501
    /* Ignore unknown flags */
 
502
    token_flags = token->Flags &
 
503
        (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
 
504
 
 
505
    if (token_flags & CFXSentByAcceptor) {
 
506
        if ((context_handle->more_flags & LOCAL) == 0)
 
507
            return GSS_S_DEFECTIVE_TOKEN;
 
508
    }
 
509
 
 
510
    if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
 
511
        if ((token_flags & CFXAcceptorSubkey) == 0)
 
512
            return GSS_S_DEFECTIVE_TOKEN;
 
513
    } else {
 
514
        if (token_flags & CFXAcceptorSubkey)
 
515
            return GSS_S_DEFECTIVE_TOKEN;
 
516
    }
 
517
 
 
518
    if (token->Filler != 0xFF) {
 
519
        return GSS_S_DEFECTIVE_TOKEN;
 
520
    }
 
521
 
 
522
    if (conf_state != NULL) {
 
523
        *conf_state = (token_flags & CFXSealed) ? 1 : 0;
 
524
    }
 
525
 
 
526
    ec  = (token->EC[0]  << 8) | token->EC[1];
 
527
    rrc = (token->RRC[0] << 8) | token->RRC[1];
 
528
 
 
529
    /*
 
530
     * Check sequence number
 
531
     */
 
532
    _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
 
533
    _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
 
534
    if (seq_number_hi) {
 
535
        /* no support for 64-bit sequence numbers */
 
536
        *minor_status = ERANGE;
 
537
        return GSS_S_UNSEQ_TOKEN;
 
538
    }
 
539
 
 
540
    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 
541
    ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
 
542
    if (ret != 0) {
 
543
        *minor_status = 0;
 
544
        HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
545
        _gsskrb5_release_buffer(minor_status, output_message_buffer);
 
546
        return ret;
 
547
    }
 
548
    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
549
 
 
550
    /*
 
551
     * Decrypt and/or verify checksum
 
552
     */
 
553
    ret = krb5_crypto_init(context, key, 0, &crypto);
 
554
    if (ret != 0) {
 
555
        *minor_status = ret;
 
556
        return GSS_S_FAILURE;
 
557
    }
 
558
 
 
559
    if (context_handle->more_flags & LOCAL) {
 
560
        usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
 
561
    } else {
 
562
        usage = KRB5_KU_USAGE_INITIATOR_SEAL;
 
563
    }
 
564
 
 
565
    p += sizeof(*token);
 
566
    len = input_message_buffer->length;
 
567
    len -= (p - (u_char *)input_message_buffer->value);
 
568
 
 
569
    if (token_flags & CFXSealed) {
 
570
        /*
 
571
         * this is really ugly, but needed against windows
 
572
         * for DCERPC, as windows rotates by EC+RRC.
 
573
         */
 
574
        if (IS_DCE_STYLE(context_handle)) {
 
575
                *minor_status = rrc_rotate(p, len, rrc+ec, TRUE);
 
576
        } else {
 
577
                *minor_status = rrc_rotate(p, len, rrc, TRUE);
 
578
        }
 
579
        if (*minor_status != 0) {
 
580
            krb5_crypto_destroy(context, crypto);
 
581
            return GSS_S_FAILURE;
 
582
        }
 
583
 
 
584
        ret = krb5_decrypt(context, crypto, usage,
 
585
            p, len, &data);
 
586
        if (ret != 0) {
 
587
            *minor_status = ret;
 
588
            krb5_crypto_destroy(context, crypto);
 
589
            return GSS_S_BAD_MIC;
 
590
        }
 
591
 
 
592
        /* Check that there is room for the pad and token header */
 
593
        if (data.length < ec + sizeof(*token)) {
 
594
            krb5_crypto_destroy(context, crypto);
 
595
            krb5_data_free(&data);
 
596
            return GSS_S_DEFECTIVE_TOKEN;
 
597
        }
 
598
        p = data.data;
 
599
        p += data.length - sizeof(*token);
 
600
 
 
601
        /* RRC is unprotected; don't modify input buffer */
 
602
        ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
 
603
        ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
 
604
 
 
605
        /* Check the integrity of the header */
 
606
        if (memcmp(p, token, sizeof(*token)) != 0) {
 
607
            krb5_crypto_destroy(context, crypto);
 
608
            krb5_data_free(&data);
 
609
            return GSS_S_BAD_MIC;
 
610
        }
 
611
 
 
612
        output_message_buffer->value = data.data;
 
613
        output_message_buffer->length = data.length - ec - sizeof(*token);
 
614
    } else {
 
615
        Checksum cksum;
 
616
 
 
617
        /* Rotate by RRC; bogus to do this in-place XXX */
 
618
        *minor_status = rrc_rotate(p, len, rrc, TRUE);
 
619
        if (*minor_status != 0) {
 
620
            krb5_crypto_destroy(context, crypto);
 
621
            return GSS_S_FAILURE;
 
622
        }
 
623
 
 
624
        /* Determine checksum type */
 
625
        ret = krb5_crypto_get_checksum_type(context,
 
626
                                            crypto, &cksum.cksumtype);
 
627
        if (ret != 0) {
 
628
            *minor_status = ret;
 
629
            krb5_crypto_destroy(context, crypto);
 
630
            return GSS_S_FAILURE;
 
631
        }
 
632
 
 
633
        cksum.checksum.length = ec;
 
634
 
 
635
        /* Check we have at least as much data as the checksum */
 
636
        if (len < cksum.checksum.length) {
 
637
            *minor_status = ERANGE;
 
638
            krb5_crypto_destroy(context, crypto);
 
639
            return GSS_S_BAD_MIC;
 
640
        }
 
641
 
 
642
        /* Length now is of the plaintext only, no checksum */
 
643
        len -= cksum.checksum.length;
 
644
        cksum.checksum.data = p + len;
 
645
 
 
646
        output_message_buffer->length = len; /* for later */
 
647
        output_message_buffer->value = malloc(len + sizeof(*token));
 
648
        if (output_message_buffer->value == NULL) {
 
649
            *minor_status = ENOMEM;
 
650
            krb5_crypto_destroy(context, crypto);
 
651
            return GSS_S_FAILURE;
 
652
        }
 
653
 
 
654
        /* Checksum is over (plaintext-data | "header") */
 
655
        memcpy(output_message_buffer->value, p, len);
 
656
        memcpy((u_char *)output_message_buffer->value + len,
 
657
               token, sizeof(*token));
 
658
 
 
659
        /* EC is not included in checksum calculation */
 
660
        token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +
 
661
                                     len);
 
662
        token->EC[0]  = 0;
 
663
        token->EC[1]  = 0;
 
664
        token->RRC[0] = 0;
 
665
        token->RRC[1] = 0;
 
666
 
 
667
        ret = krb5_verify_checksum(context, crypto,
 
668
                                   usage,
 
669
                                   output_message_buffer->value,
 
670
                                   len + sizeof(*token),
 
671
                                   &cksum);
 
672
        if (ret != 0) {
 
673
            *minor_status = ret;
 
674
            krb5_crypto_destroy(context, crypto);
 
675
            _gsskrb5_release_buffer(minor_status, output_message_buffer);
 
676
            return GSS_S_BAD_MIC;
 
677
        }
 
678
    }
 
679
 
 
680
    krb5_crypto_destroy(context, crypto);
 
681
 
 
682
    if (qop_state != NULL) {
 
683
        *qop_state = GSS_C_QOP_DEFAULT;
 
684
    }
 
685
 
 
686
    *minor_status = 0;
 
687
    return GSS_S_COMPLETE;
 
688
}
 
689
 
 
690
OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
 
691
                          const gsskrb5_ctx context_handle,
 
692
                          krb5_context context,
 
693
                          gss_qop_t qop_req,
 
694
                          const gss_buffer_t message_buffer,
 
695
                          gss_buffer_t message_token,
 
696
                          krb5_keyblock *key)
 
697
{
 
698
    krb5_crypto crypto;
 
699
    gss_cfx_mic_token token;
 
700
    krb5_error_code ret;
 
701
    unsigned usage;
 
702
    Checksum cksum;
 
703
    u_char *buf;
 
704
    size_t len;
 
705
    int32_t seq_number;
 
706
 
 
707
    ret = krb5_crypto_init(context, key, 0, &crypto);
 
708
    if (ret != 0) {
 
709
        *minor_status = ret;
 
710
        return GSS_S_FAILURE;
 
711
    }
 
712
 
 
713
    len = message_buffer->length + sizeof(*token);
 
714
    buf = malloc(len);
 
715
    if (buf == NULL) {
 
716
        *minor_status = ENOMEM;
 
717
        krb5_crypto_destroy(context, crypto);
 
718
        return GSS_S_FAILURE;
 
719
    }
 
720
 
 
721
    memcpy(buf, message_buffer->value, message_buffer->length);
 
722
 
 
723
    token = (gss_cfx_mic_token)(buf + message_buffer->length);
 
724
    token->TOK_ID[0] = 0x04;
 
725
    token->TOK_ID[1] = 0x04;
 
726
    token->Flags = 0;
 
727
    if ((context_handle->more_flags & LOCAL) == 0)
 
728
        token->Flags |= CFXSentByAcceptor;
 
729
    if (context_handle->more_flags & ACCEPTOR_SUBKEY)
 
730
        token->Flags |= CFXAcceptorSubkey;
 
731
    memset(token->Filler, 0xFF, 5);
 
732
 
 
733
    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 
734
    krb5_auth_con_getlocalseqnumber(context,
 
735
                                    context_handle->auth_context,
 
736
                                    &seq_number);
 
737
    _gsskrb5_encode_be_om_uint32(0,          &token->SND_SEQ[0]);
 
738
    _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
 
739
    krb5_auth_con_setlocalseqnumber(context,
 
740
                                    context_handle->auth_context,
 
741
                                    ++seq_number);
 
742
    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
743
 
 
744
    if (context_handle->more_flags & LOCAL) {
 
745
        usage = KRB5_KU_USAGE_INITIATOR_SIGN;
 
746
    } else {
 
747
        usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
 
748
    }
 
749
 
 
750
    ret = krb5_create_checksum(context, crypto,
 
751
        usage, 0, buf, len, &cksum);
 
752
    if (ret != 0) {
 
753
        *minor_status = ret;
 
754
        krb5_crypto_destroy(context, crypto);
 
755
        free(buf);
 
756
        return GSS_S_FAILURE;
 
757
    }
 
758
    krb5_crypto_destroy(context, crypto);
 
759
 
 
760
    /* Determine MIC length */
 
761
    message_token->length = sizeof(*token) + cksum.checksum.length;
 
762
    message_token->value = malloc(message_token->length);
 
763
    if (message_token->value == NULL) {
 
764
        *minor_status = ENOMEM;
 
765
        free_Checksum(&cksum);
 
766
        free(buf);
 
767
        return GSS_S_FAILURE;
 
768
    }
 
769
 
 
770
    /* Token is { "header" | get_mic("header" | plaintext-data) } */
 
771
    memcpy(message_token->value, token, sizeof(*token));
 
772
    memcpy((u_char *)message_token->value + sizeof(*token),
 
773
           cksum.checksum.data, cksum.checksum.length);
 
774
 
 
775
    free_Checksum(&cksum);
 
776
    free(buf);
 
777
 
 
778
    *minor_status = 0;
 
779
    return GSS_S_COMPLETE;
 
780
}
 
781
 
 
782
OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
 
783
                                 const gsskrb5_ctx context_handle,
 
784
                                 krb5_context context,
 
785
                                 const gss_buffer_t message_buffer,
 
786
                                 const gss_buffer_t token_buffer,
 
787
                                 gss_qop_t *qop_state,
 
788
                                 krb5_keyblock *key)
 
789
{
 
790
    krb5_crypto crypto;
 
791
    gss_cfx_mic_token token;
 
792
    u_char token_flags;
 
793
    krb5_error_code ret;
 
794
    unsigned usage;
 
795
    OM_uint32 seq_number_lo, seq_number_hi;
 
796
    u_char *buf, *p;
 
797
    Checksum cksum;
 
798
 
 
799
    *minor_status = 0;
 
800
 
 
801
    if (token_buffer->length < sizeof(*token)) {
 
802
        return GSS_S_DEFECTIVE_TOKEN;
 
803
    }
 
804
 
 
805
    p = token_buffer->value;
 
806
 
 
807
    token = (gss_cfx_mic_token)p;
 
808
 
 
809
    if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
 
810
        return GSS_S_DEFECTIVE_TOKEN;
 
811
    }
 
812
 
 
813
    /* Ignore unknown flags */
 
814
    token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
 
815
 
 
816
    if (token_flags & CFXSentByAcceptor) {
 
817
        if ((context_handle->more_flags & LOCAL) == 0)
 
818
            return GSS_S_DEFECTIVE_TOKEN;
 
819
    }
 
820
    if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
 
821
        if ((token_flags & CFXAcceptorSubkey) == 0)
 
822
            return GSS_S_DEFECTIVE_TOKEN;
 
823
    } else {
 
824
        if (token_flags & CFXAcceptorSubkey)
 
825
            return GSS_S_DEFECTIVE_TOKEN;
 
826
    }
 
827
 
 
828
    if (memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) {
 
829
        return GSS_S_DEFECTIVE_TOKEN;
 
830
    }
 
831
 
 
832
    /*
 
833
     * Check sequence number
 
834
     */
 
835
    _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
 
836
    _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
 
837
    if (seq_number_hi) {
 
838
        *minor_status = ERANGE;
 
839
        return GSS_S_UNSEQ_TOKEN;
 
840
    }
 
841
 
 
842
    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 
843
    ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
 
844
    if (ret != 0) {
 
845
        *minor_status = 0;
 
846
        HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
847
        return ret;
 
848
    }
 
849
    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
850
 
 
851
    /*
 
852
     * Verify checksum
 
853
     */
 
854
    ret = krb5_crypto_init(context, key, 0, &crypto);
 
855
    if (ret != 0) {
 
856
        *minor_status = ret;
 
857
        return GSS_S_FAILURE;
 
858
    }
 
859
 
 
860
    ret = krb5_crypto_get_checksum_type(context, crypto,
 
861
                                        &cksum.cksumtype);
 
862
    if (ret != 0) {
 
863
        *minor_status = ret;
 
864
        krb5_crypto_destroy(context, crypto);
 
865
        return GSS_S_FAILURE;
 
866
    }
 
867
 
 
868
    cksum.checksum.data = p + sizeof(*token);
 
869
    cksum.checksum.length = token_buffer->length - sizeof(*token);
 
870
 
 
871
    if (context_handle->more_flags & LOCAL) {
 
872
        usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
 
873
    } else {
 
874
        usage = KRB5_KU_USAGE_INITIATOR_SIGN;
 
875
    }
 
876
 
 
877
    buf = malloc(message_buffer->length + sizeof(*token));
 
878
    if (buf == NULL) {
 
879
        *minor_status = ENOMEM;
 
880
        krb5_crypto_destroy(context, crypto);
 
881
        return GSS_S_FAILURE;
 
882
    }
 
883
    memcpy(buf, message_buffer->value, message_buffer->length);
 
884
    memcpy(buf + message_buffer->length, token, sizeof(*token));
 
885
 
 
886
    ret = krb5_verify_checksum(context, crypto,
 
887
                               usage,
 
888
                               buf,
 
889
                               sizeof(*token) + message_buffer->length,
 
890
                               &cksum);
 
891
    krb5_crypto_destroy(context, crypto);
 
892
    if (ret != 0) {
 
893
        *minor_status = ret;
 
894
        free(buf);
 
895
        return GSS_S_BAD_MIC;
 
896
    }
 
897
 
 
898
    free(buf);
 
899
 
 
900
    if (qop_state != NULL) {
 
901
        *qop_state = GSS_C_QOP_DEFAULT;
 
902
    }
 
903
 
 
904
    return GSS_S_COMPLETE;
 
905
}