~ubuntu-branches/ubuntu/maverick/krb5/maverick

« back to all changes in this revision

Viewing changes to src/lib/crypto/arcfour/arcfour_aead.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2009-05-07 16:16:34 UTC
  • mfrom: (13.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20090507161634-xqyk0s9na0le4flj
Tags: 1.7dfsg~beta1-4
When  decrypting the TGS response fails with the subkey, try with the
session key to work around Heimdal bug, Closes: #527353 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * lib/crypto/arcfour/arcfour_aead.c
 
3
 *
 
4
 * Copyright 2008 by the Massachusetts Institute of Technology.
 
5
 * All Rights Reserved.
 
6
 *
 
7
 * Export of this software from the United States of America may
 
8
 *   require a specific license from the United States Government.
 
9
 *   It is the responsibility of any person or organization contemplating
 
10
 *   export to obtain such a license before exporting.
 
11
 * 
 
12
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 
13
 * distribute this software and its documentation for any purpose and
 
14
 * without fee is hereby granted, provided that the above copyright
 
15
 * notice appear in all copies and that both that copyright notice and
 
16
 * this permission notice appear in supporting documentation, and that
 
17
 * the name of M.I.T. not be used in advertising or publicity pertaining
 
18
 * to distribution of the software without specific, written prior
 
19
 * permission.  Furthermore if you modify this software you must label
 
20
 * your software as modified software and not distribute it in such a
 
21
 * fashion that it might be confused with the original M.I.T. software.
 
22
 * M.I.T. makes no representations about the suitability of
 
23
 * this software for any purpose.  It is provided "as is" without express
 
24
 * or implied warranty.
 
25
 */
 
26
 
 
27
 
 
28
#include "k5-int.h"
 
29
#include "arcfour.h"
 
30
#include "arcfour-int.h"
 
31
#include "aead.h"
 
32
 
 
33
/* AEAD */
 
34
 
 
35
static krb5_error_code
 
36
krb5int_arcfour_crypto_length(const struct krb5_aead_provider *aead,
 
37
                              const struct krb5_enc_provider *enc,
 
38
                              const struct krb5_hash_provider *hash,
 
39
                              krb5_cryptotype type,
 
40
                              unsigned int *length)
 
41
{
 
42
    switch (type) {
 
43
    case KRB5_CRYPTO_TYPE_HEADER:
 
44
        *length = hash->hashsize + CONFOUNDERLENGTH;
 
45
        break;
 
46
    case KRB5_CRYPTO_TYPE_PADDING:
 
47
        *length = 0;
 
48
        break;
 
49
    case KRB5_CRYPTO_TYPE_TRAILER:
 
50
        *length = 0;
 
51
        break;
 
52
    case KRB5_CRYPTO_TYPE_CHECKSUM:
 
53
        *length = hash->hashsize;
 
54
        break;
 
55
    default:
 
56
        assert(0 && "invalid cryptotype passed to krb5int_arcfour_crypto_length");
 
57
        break;
 
58
    }
 
59
 
 
60
    return 0;
 
61
}
 
62
 
 
63
static krb5_error_code
 
64
alloc_derived_key(const struct krb5_enc_provider *enc,
 
65
                  krb5_keyblock *dst,
 
66
                  krb5_data *data,
 
67
                  const krb5_keyblock *src)
 
68
{
 
69
    data->length = enc->keybytes;
 
70
    data->data = malloc(data->length);
 
71
    if (data->data == NULL)
 
72
        return ENOMEM;
 
73
 
 
74
    *dst = *src;
 
75
    dst->length = data->length;
 
76
    dst->contents = (void *)data->data;
 
77
 
 
78
    return 0;
 
79
}
 
80
 
 
81
static krb5_error_code
 
82
krb5int_arcfour_encrypt_iov(const struct krb5_aead_provider *aead,
 
83
                            const struct krb5_enc_provider *enc,
 
84
                            const struct krb5_hash_provider *hash,
 
85
                            const krb5_keyblock *key,
 
86
                            krb5_keyusage usage,
 
87
                            const krb5_data *ivec,
 
88
                            krb5_crypto_iov *data,
 
89
                            size_t num_data)
 
90
{
 
91
    krb5_error_code ret;
 
92
    krb5_crypto_iov *header, *trailer;
 
93
    krb5_keyblock k1, k2, k3;
 
94
    krb5_data d1, d2, d3;
 
95
    krb5_data checksum, confounder, header_data;
 
96
    krb5_keyusage ms_usage;
 
97
    char salt_data[14];
 
98
    krb5_data salt;
 
99
    size_t i;
 
100
 
 
101
    d1.length = d2.length = d3.length = 0;
 
102
    d1.data = d2.data = d3.data = NULL;
 
103
 
 
104
    /*
 
105
     * Caller must have provided space for the header, padding
 
106
     * and trailer; per RFC 4757 we will arrange it as:
 
107
     *
 
108
     *      Checksum | E(Confounder | Plaintext) 
 
109
     */
 
110
 
 
111
    header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
 
112
    if (header == NULL ||
 
113
        header->data.length < hash->hashsize + CONFOUNDERLENGTH)
 
114
        return KRB5_BAD_MSIZE;
 
115
 
 
116
    header_data = header->data;
 
117
 
 
118
    /* Trailer may be absent */
 
119
    trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
 
120
    if (trailer != NULL)
 
121
        trailer->data.length = 0;
 
122
 
 
123
    /* Ensure that there is no padding */
 
124
    for (i = 0; i < num_data; i++) {
 
125
        if (data[i].flags == KRB5_CRYPTO_TYPE_PADDING)
 
126
            data[i].data.length = 0;
 
127
    }
 
128
 
 
129
    ret = alloc_derived_key(enc, &k1, &d1, key);
 
130
    if (ret != 0)
 
131
        goto cleanup;
 
132
 
 
133
    ret = alloc_derived_key(enc, &k2, &d2, key);
 
134
    if (ret != 0)
 
135
        goto cleanup;
 
136
 
 
137
    ret = alloc_derived_key(enc, &k3, &d3, key);
 
138
    if (ret != 0)
 
139
        goto cleanup;
 
140
 
 
141
    /* Begin the encryption, compute K1 */
 
142
    salt.data = salt_data;
 
143
    salt.length = sizeof(salt_data);
 
144
 
 
145
    ms_usage = krb5int_arcfour_translate_usage(usage);
 
146
 
 
147
    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
 
148
        strncpy(salt.data, krb5int_arcfour_l40, salt.length);
 
149
        store_32_le(ms_usage, salt.data + 10);
 
150
    } else {
 
151
        salt.length = 4;
 
152
        store_32_le(ms_usage, salt.data);
 
153
    }
 
154
    ret = krb5_hmac(hash, key, 1, &salt, &d1);
 
155
    if (ret != 0)
 
156
        goto cleanup;
 
157
 
 
158
    memcpy(k2.contents, k1.contents, k2.length);
 
159
 
 
160
    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
 
161
        memset(k1.contents + 7, 0xAB, 9);
 
162
 
 
163
    header->data.length = hash->hashsize + CONFOUNDERLENGTH;
 
164
 
 
165
    confounder.data = header->data.data + hash->hashsize;
 
166
    confounder.length = CONFOUNDERLENGTH;
 
167
 
 
168
    ret = krb5_c_random_make_octets(0, &confounder);
 
169
    if (ret != 0)
 
170
        goto cleanup;
 
171
 
 
172
    checksum.data = header->data.data;
 
173
    checksum.length = hash->hashsize;
 
174
 
 
175
    /* Adjust pointers so confounder is at start of header */
 
176
    header->data.length -= hash->hashsize;
 
177
    header->data.data   += hash->hashsize;
 
178
 
 
179
    ret = krb5int_hmac_iov(hash, &k2, data, num_data, &checksum);
 
180
    if (ret != 0)
 
181
        goto cleanup;
 
182
 
 
183
    ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
 
184
    if (ret != 0)
 
185
        goto cleanup;
 
186
 
 
187
    ret = enc->encrypt_iov(&k3, ivec, data, num_data);
 
188
    if (ret != 0)
 
189
        goto cleanup;
 
190
 
 
191
cleanup:
 
192
    header->data = header_data; /* restore header pointers */
 
193
 
 
194
    if (d1.data != NULL) {
 
195
        memset(d1.data, 0, d1.length);
 
196
        free(d1.data);
 
197
    }
 
198
    if (d2.data != NULL) {
 
199
        memset(d2.data, 0, d2.length);
 
200
        free(d2.data);
 
201
    }
 
202
    if (d3.data != NULL) {
 
203
        memset(d3.data, 0, d3.length);
 
204
        free(d3.data);
 
205
    }
 
206
 
 
207
    return ret;
 
208
}
 
209
 
 
210
static krb5_error_code
 
211
krb5int_arcfour_decrypt_iov(const struct krb5_aead_provider *aead,
 
212
                            const struct krb5_enc_provider *enc,
 
213
                            const struct krb5_hash_provider *hash,
 
214
                            const krb5_keyblock *key,
 
215
                            krb5_keyusage usage,
 
216
                            const krb5_data *ivec,
 
217
                            krb5_crypto_iov *data,
 
218
                            size_t num_data)
 
219
{
 
220
    krb5_error_code ret;
 
221
    krb5_crypto_iov *header, *trailer;
 
222
    krb5_keyblock k1, k2, k3;
 
223
    krb5_data d1, d2, d3;
 
224
    krb5_data checksum, header_data;
 
225
    krb5_keyusage ms_usage;
 
226
    char salt_data[14];
 
227
    krb5_data salt;
 
228
 
 
229
    d1.length = d2.length = d3.length = 0;
 
230
    d1.data = d2.data = d3.data = NULL;
 
231
 
 
232
    header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
 
233
    if (header == NULL ||
 
234
        header->data.length != hash->hashsize + CONFOUNDERLENGTH)
 
235
        return KRB5_BAD_MSIZE;
 
236
 
 
237
    header_data = header->data;
 
238
 
 
239
    trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
 
240
    if (trailer != NULL && trailer->data.length != 0)
 
241
        return KRB5_BAD_MSIZE;
 
242
    
 
243
    ret = alloc_derived_key(enc, &k1, &d1, key);
 
244
    if (ret != 0)
 
245
        goto cleanup;
 
246
 
 
247
    ret = alloc_derived_key(enc, &k2, &d2, key);
 
248
    if (ret != 0)
 
249
        goto cleanup;
 
250
 
 
251
    ret = alloc_derived_key(enc, &k3, &d3, key);
 
252
    if (ret != 0)
 
253
        goto cleanup;
 
254
 
 
255
    /* Begin the decryption, compute K1 */
 
256
    salt.data = salt_data;
 
257
    salt.length = sizeof(salt_data);
 
258
 
 
259
    ms_usage = krb5int_arcfour_translate_usage(usage);
 
260
 
 
261
    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
 
262
        strncpy(salt.data, krb5int_arcfour_l40, salt.length);
 
263
        store_32_le(ms_usage, (unsigned char *)salt.data + 10);
 
264
    } else {
 
265
        salt.length = 4;
 
266
        store_32_le(ms_usage, (unsigned char *)salt.data);
 
267
    }
 
268
    ret = krb5_hmac(hash, key, 1, &salt, &d1);
 
269
    if (ret != 0)
 
270
        goto cleanup;
 
271
 
 
272
    memcpy(k2.contents, k1.contents, k2.length);
 
273
 
 
274
    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
 
275
        memset(k1.contents + 7, 0xAB, 9);
 
276
 
 
277
    checksum.data = header->data.data;
 
278
    checksum.length = hash->hashsize;
 
279
 
 
280
    /* Adjust pointers so confounder is at start of header */
 
281
    header->data.length -= hash->hashsize;
 
282
    header->data.data   += hash->hashsize;
 
283
 
 
284
    ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
 
285
    if (ret != 0)
 
286
        goto cleanup;
 
287
 
 
288
    ret = enc->decrypt_iov(&k3, ivec, data, num_data);
 
289
    if (ret != 0)
 
290
        goto cleanup;
 
291
 
 
292
    ret = krb5int_hmac_iov(hash, &k2, data, num_data, &d1);
 
293
    if (ret != 0)
 
294
        goto cleanup;
 
295
 
 
296
    if (memcmp(checksum.data, d1.data, hash->hashsize) != 0) {
 
297
        ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
 
298
        goto cleanup;
 
299
    }
 
300
 
 
301
cleanup:
 
302
    header->data = header_data; /* restore header pointers */
 
303
 
 
304
    if (d1.data != NULL) {
 
305
        memset(d1.data, 0, d1.length);
 
306
        free(d1.data);
 
307
    }
 
308
    if (d2.data != NULL) {
 
309
        memset(d2.data, 0, d2.length);
 
310
        free(d2.data);
 
311
    }
 
312
    if (d3.data != NULL) {
 
313
        memset(d3.data, 0, d3.length);
 
314
        free(d3.data);
 
315
    }
 
316
 
 
317
    return ret;
 
318
}
 
319
 
 
320
const struct krb5_aead_provider krb5int_aead_arcfour = {
 
321
    krb5int_arcfour_crypto_length,
 
322
    krb5int_arcfour_encrypt_iov,
 
323
    krb5int_arcfour_decrypt_iov
 
324
};
 
325