~ubuntu-branches/ubuntu/hardy/wpasupplicant/hardy

« back to all changes in this revision

Viewing changes to src/eap_common/eap_sim_common.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * EAP peer: EAP-SIM/AKA shared routines
3
 
 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License version 2 as
7
 
 * published by the Free Software Foundation.
8
 
 *
9
 
 * Alternatively, this software may be distributed under the terms of BSD
10
 
 * license.
11
 
 *
12
 
 * See README and COPYING for more details.
13
 
 */
14
 
 
15
 
#include "includes.h"
16
 
 
17
 
#include "common.h"
18
 
#include "eap_common/eap_defs.h"
19
 
#include "sha1.h"
20
 
#include "crypto.h"
21
 
#include "aes_wrap.h"
22
 
#include "eap_common/eap_sim_common.h"
23
 
 
24
 
 
25
 
static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
26
 
{
27
 
        return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
28
 
}
29
 
 
30
 
 
31
 
void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
32
 
                       const u8 *nonce_mt, u16 selected_version,
33
 
                       const u8 *ver_list, size_t ver_list_len,
34
 
                       int num_chal, const u8 *kc, u8 *mk)
35
 
{
36
 
        u8 sel_ver[2];
37
 
        const unsigned char *addr[5];
38
 
        size_t len[5];
39
 
 
40
 
        addr[0] = identity;
41
 
        len[0] = identity_len;
42
 
        addr[1] = kc;
43
 
        len[1] = num_chal * EAP_SIM_KC_LEN;
44
 
        addr[2] = nonce_mt;
45
 
        len[2] = EAP_SIM_NONCE_MT_LEN;
46
 
        addr[3] = ver_list;
47
 
        len[3] = ver_list_len;
48
 
        addr[4] = sel_ver;
49
 
        len[4] = 2;
50
 
 
51
 
        WPA_PUT_BE16(sel_ver, selected_version);
52
 
 
53
 
        /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
54
 
        sha1_vector(5, addr, len, mk);
55
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
56
 
}
57
 
 
58
 
 
59
 
void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
60
 
                       const u8 *ik, const u8 *ck, u8 *mk)
61
 
{
62
 
        const u8 *addr[3];
63
 
        size_t len[3];
64
 
 
65
 
        addr[0] = identity;
66
 
        len[0] = identity_len;
67
 
        addr[1] = ik;
68
 
        len[1] = EAP_AKA_IK_LEN;
69
 
        addr[2] = ck;
70
 
        len[2] = EAP_AKA_CK_LEN;
71
 
 
72
 
        /* MK = SHA1(Identity|IK|CK) */
73
 
        sha1_vector(3, addr, len, mk);
74
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
75
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
76
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
77
 
}
78
 
 
79
 
 
80
 
int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
81
 
{
82
 
        u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
83
 
               EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
84
 
        if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
85
 
                wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
86
 
                return -1;
87
 
        }
88
 
        pos = buf;
89
 
        os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
90
 
        pos += EAP_SIM_K_ENCR_LEN;
91
 
        os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
92
 
        pos += EAP_SIM_K_AUT_LEN;
93
 
        os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
94
 
        pos += EAP_SIM_KEYING_DATA_LEN;
95
 
        os_memcpy(emsk, pos, EAP_EMSK_LEN);
96
 
 
97
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
98
 
                        k_encr, EAP_SIM_K_ENCR_LEN);
99
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
100
 
                        k_aut, EAP_SIM_K_AUT_LEN);
101
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
102
 
                        msk, EAP_SIM_KEYING_DATA_LEN);
103
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
104
 
        os_memset(buf, 0, sizeof(buf));
105
 
 
106
 
        return 0;
107
 
}
108
 
 
109
 
 
110
 
int eap_sim_derive_keys_reauth(u16 _counter,
111
 
                               const u8 *identity, size_t identity_len,
112
 
                               const u8 *nonce_s, const u8 *mk, u8 *msk,
113
 
                               u8 *emsk)
114
 
{
115
 
        u8 xkey[SHA1_MAC_LEN];
116
 
        u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
117
 
        u8 counter[2];
118
 
        const u8 *addr[4];
119
 
        size_t len[4];
120
 
 
121
 
        addr[0] = identity;
122
 
        len[0] = identity_len;
123
 
        addr[1] = counter;
124
 
        len[1] = 2;
125
 
        addr[2] = nonce_s;
126
 
        len[2] = EAP_SIM_NONCE_S_LEN;
127
 
        addr[3] = mk;
128
 
        len[3] = EAP_SIM_MK_LEN;
129
 
 
130
 
        WPA_PUT_BE16(counter, _counter);
131
 
 
132
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
133
 
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
134
 
                          identity, identity_len);
135
 
        wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
136
 
        wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
137
 
                    EAP_SIM_NONCE_S_LEN);
138
 
        wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
139
 
 
140
 
        /* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
141
 
        sha1_vector(4, addr, len, xkey);
142
 
        wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
143
 
 
144
 
        if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
145
 
                wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
146
 
                return -1;
147
 
        }
148
 
        if (msk) {
149
 
                os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
150
 
                wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
151
 
                            msk, EAP_SIM_KEYING_DATA_LEN);
152
 
        }
153
 
        if (emsk) {
154
 
                os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
155
 
                wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
156
 
        }
157
 
        os_memset(buf, 0, sizeof(buf));
158
 
 
159
 
        return 0;
160
 
}
161
 
 
162
 
 
163
 
int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
164
 
                       const u8 *mac, const u8 *extra, size_t extra_len)
165
 
{
166
 
        unsigned char hmac[SHA1_MAC_LEN];
167
 
        const u8 *addr[2];
168
 
        size_t len[2];
169
 
        u8 *tmp;
170
 
 
171
 
        if (mac == NULL || req_len < EAP_SIM_MAC_LEN || mac < req ||
172
 
            mac > req + req_len - EAP_SIM_MAC_LEN)
173
 
                return -1;
174
 
 
175
 
        tmp = os_malloc(req_len);
176
 
        if (tmp == NULL)
177
 
                return -1;
178
 
 
179
 
        addr[0] = tmp;
180
 
        len[0] = req_len;
181
 
        addr[1] = extra;
182
 
        len[1] = extra_len;
183
 
 
184
 
        /* HMAC-SHA1-128 */
185
 
        os_memcpy(tmp, req, req_len);
186
 
        os_memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
187
 
        wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg", tmp, req_len);
188
 
        wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
189
 
                    extra, extra_len);
190
 
        wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
191
 
                        k_aut, EAP_SIM_K_AUT_LEN);
192
 
        hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
193
 
        wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
194
 
                    hmac, EAP_SIM_MAC_LEN);
195
 
        os_free(tmp);
196
 
 
197
 
        return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
198
 
}
199
 
 
200
 
 
201
 
void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
202
 
                     const u8 *extra, size_t extra_len)
203
 
{
204
 
        unsigned char hmac[SHA1_MAC_LEN];
205
 
        const u8 *addr[2];
206
 
        size_t len[2];
207
 
 
208
 
        addr[0] = msg;
209
 
        len[0] = msg_len;
210
 
        addr[1] = extra;
211
 
        len[1] = extra_len;
212
 
 
213
 
        /* HMAC-SHA1-128 */
214
 
        os_memset(mac, 0, EAP_SIM_MAC_LEN);
215
 
        wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
216
 
        wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
217
 
                    extra, extra_len);
218
 
        wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
219
 
                        k_aut, EAP_SIM_K_AUT_LEN);
220
 
        hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
221
 
        os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
222
 
        wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
223
 
                    mac, EAP_SIM_MAC_LEN);
224
 
}
225
 
 
226
 
 
227
 
int eap_sim_parse_attr(const u8 *start, const u8 *end,
228
 
                       struct eap_sim_attrs *attr, int aka, int encr)
229
 
{
230
 
        const u8 *pos = start, *apos;
231
 
        size_t alen, plen, i, list_len;
232
 
 
233
 
        os_memset(attr, 0, sizeof(*attr));
234
 
        attr->id_req = NO_ID_REQ;
235
 
        attr->notification = -1;
236
 
        attr->counter = -1;
237
 
        attr->selected_version = -1;
238
 
        attr->client_error_code = -1;
239
 
 
240
 
        while (pos < end) {
241
 
                if (pos + 2 > end) {
242
 
                        wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
243
 
                        return -1;
244
 
                }
245
 
                wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
246
 
                           pos[0], pos[1] * 4);
247
 
                if (pos + pos[1] * 4 > end) {
248
 
                        wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
249
 
                                   "(pos=%p len=%d end=%p)",
250
 
                                   pos, pos[1] * 4, end);
251
 
                        return -1;
252
 
                }
253
 
                apos = pos + 2;
254
 
                alen = pos[1] * 4 - 2;
255
 
                wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
256
 
                            apos, alen);
257
 
 
258
 
                switch (pos[0]) {
259
 
                case EAP_SIM_AT_RAND:
260
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
261
 
                        apos += 2;
262
 
                        alen -= 2;
263
 
                        if ((!aka && (alen % GSM_RAND_LEN)) ||
264
 
                            (aka && alen != EAP_AKA_RAND_LEN)) {
265
 
                                wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
266
 
                                           " (len %lu)",
267
 
                                           (unsigned long) alen);
268
 
                                return -1;
269
 
                        }
270
 
                        attr->rand = apos;
271
 
                        attr->num_chal = alen / GSM_RAND_LEN;
272
 
                        break;
273
 
                case EAP_SIM_AT_AUTN:
274
 
                        wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
275
 
                        if (!aka) {
276
 
                                wpa_printf(MSG_DEBUG, "EAP-SIM: "
277
 
                                           "Unexpected AT_AUTN");
278
 
                                return -1;
279
 
                        }
280
 
                        apos += 2;
281
 
                        alen -= 2;
282
 
                        if (alen != EAP_AKA_AUTN_LEN) {
283
 
                                wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
284
 
                                           " (len %lu)",
285
 
                                           (unsigned long) alen);
286
 
                                return -1;
287
 
                        }
288
 
                        attr->autn = apos;
289
 
                        break;
290
 
                case EAP_SIM_AT_PADDING:
291
 
                        if (!encr) {
292
 
                                wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
293
 
                                           "AT_PADDING");
294
 
                                return -1;
295
 
                        }
296
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
297
 
                        for (i = 2; i < alen; i++) {
298
 
                                if (apos[i] != 0) {
299
 
                                        wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
300
 
                                                   "AT_PADDING used a non-zero"
301
 
                                                   " padding byte");
302
 
                                        wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
303
 
                                                    "(encr) padding bytes",
304
 
                                                    apos + 2, alen - 2);
305
 
                                        return -1;
306
 
                                }
307
 
                        }
308
 
                        break;
309
 
                case EAP_SIM_AT_NONCE_MT:
310
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
311
 
                        if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
312
 
                                wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
313
 
                                           "AT_NONCE_MT length");
314
 
                                return -1;
315
 
                        }
316
 
                        attr->nonce_mt = apos + 2;
317
 
                        break;
318
 
                case EAP_SIM_AT_PERMANENT_ID_REQ:
319
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
320
 
                        attr->id_req = PERMANENT_ID;
321
 
                        break;
322
 
                case EAP_SIM_AT_MAC:
323
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
324
 
                        if (alen != 2 + EAP_SIM_MAC_LEN) {
325
 
                                wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
326
 
                                           "length");
327
 
                                return -1;
328
 
                        }
329
 
                        attr->mac = apos + 2;
330
 
                        break;
331
 
                case EAP_SIM_AT_NOTIFICATION:
332
 
                        if (alen != 2) {
333
 
                                wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
334
 
                                           "AT_NOTIFICATION length %lu",
335
 
                                           (unsigned long) alen);
336
 
                                return -1;
337
 
                        }
338
 
                        attr->notification = apos[0] * 256 + apos[1];
339
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
340
 
                                   attr->notification);
341
 
                        break;
342
 
                case EAP_SIM_AT_ANY_ID_REQ:
343
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
344
 
                        attr->id_req = ANY_ID;
345
 
                        break;
346
 
                case EAP_SIM_AT_IDENTITY:
347
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
348
 
                        attr->identity = apos + 2;
349
 
                        attr->identity_len = alen - 2;
350
 
                        break;
351
 
                case EAP_SIM_AT_VERSION_LIST:
352
 
                        if (aka) {
353
 
                                wpa_printf(MSG_DEBUG, "EAP-AKA: "
354
 
                                           "Unexpected AT_VERSION_LIST");
355
 
                                return -1;
356
 
                        }
357
 
                        list_len = apos[0] * 256 + apos[1];
358
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
359
 
                        if (list_len < 2 || list_len > alen - 2) {
360
 
                                wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
361
 
                                           "AT_VERSION_LIST (list_len=%lu "
362
 
                                           "attr_len=%lu)",
363
 
                                           (unsigned long) list_len,
364
 
                                           (unsigned long) alen);
365
 
                                return -1;
366
 
                        }
367
 
                        attr->version_list = apos + 2;
368
 
                        attr->version_list_len = list_len;
369
 
                        break;
370
 
                case EAP_SIM_AT_SELECTED_VERSION:
371
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
372
 
                        if (alen != 2) {
373
 
                                wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
374
 
                                           "AT_SELECTED_VERSION length %lu",
375
 
                                           (unsigned long) alen);
376
 
                                return -1;
377
 
                        }
378
 
                        attr->selected_version = apos[0] * 256 + apos[1];
379
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
380
 
                                   "%d", attr->selected_version);
381
 
                        break;
382
 
                case EAP_SIM_AT_FULLAUTH_ID_REQ:
383
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
384
 
                        attr->id_req = FULLAUTH_ID;
385
 
                        break;
386
 
                case EAP_SIM_AT_COUNTER:
387
 
                        if (!encr) {
388
 
                                wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
389
 
                                           "AT_COUNTER");
390
 
                                return -1;
391
 
                        }
392
 
                        if (alen != 2) {
393
 
                                wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
394
 
                                           "AT_COUNTER (alen=%lu)",
395
 
                                           (unsigned long) alen);
396
 
                                return -1;
397
 
                        }
398
 
                        attr->counter = apos[0] * 256 + apos[1];
399
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
400
 
                                   attr->counter);
401
 
                        break;
402
 
                case EAP_SIM_AT_COUNTER_TOO_SMALL:
403
 
                        if (!encr) {
404
 
                                wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
405
 
                                           "AT_COUNTER_TOO_SMALL");
406
 
                                return -1;
407
 
                        }
408
 
                        if (alen != 2) {
409
 
                                wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
410
 
                                           "AT_COUNTER_TOO_SMALL (alen=%lu)",
411
 
                                           (unsigned long) alen);
412
 
                                return -1;
413
 
                        }
414
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
415
 
                                   "AT_COUNTER_TOO_SMALL");
416
 
                        attr->counter_too_small = 1;
417
 
                        break;
418
 
                case EAP_SIM_AT_NONCE_S:
419
 
                        if (!encr) {
420
 
                                wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
421
 
                                           "AT_NONCE_S");
422
 
                                return -1;
423
 
                        }
424
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
425
 
                                   "AT_NONCE_S");
426
 
                        if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
427
 
                                wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
428
 
                                           "AT_NONCE_S (alen=%lu)",
429
 
                                           (unsigned long) alen);
430
 
                                return -1;
431
 
                        }
432
 
                        attr->nonce_s = apos + 2;
433
 
                        break;
434
 
                case EAP_SIM_AT_CLIENT_ERROR_CODE:
435
 
                        if (alen != 2) {
436
 
                                wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
437
 
                                           "AT_CLIENT_ERROR_CODE length %lu",
438
 
                                           (unsigned long) alen);
439
 
                                return -1;
440
 
                        }
441
 
                        attr->client_error_code = apos[0] * 256 + apos[1];
442
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
443
 
                                   "%d", attr->client_error_code);
444
 
                        break;
445
 
                case EAP_SIM_AT_IV:
446
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
447
 
                        if (alen != 2 + EAP_SIM_MAC_LEN) {
448
 
                                wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
449
 
                                           "length %lu", (unsigned long) alen);
450
 
                                return -1;
451
 
                        }
452
 
                        attr->iv = apos + 2;
453
 
                        break;
454
 
                case EAP_SIM_AT_ENCR_DATA:
455
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
456
 
                        attr->encr_data = apos + 2;
457
 
                        attr->encr_data_len = alen - 2;
458
 
                        if (attr->encr_data_len % 16) {
459
 
                                wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
460
 
                                           "AT_ENCR_DATA length %lu",
461
 
                                           (unsigned long)
462
 
                                           attr->encr_data_len);
463
 
                                return -1;
464
 
                        }
465
 
                        break;
466
 
                case EAP_SIM_AT_NEXT_PSEUDONYM:
467
 
                        if (!encr) {
468
 
                                wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
469
 
                                           "AT_NEXT_PSEUDONYM");
470
 
                                return -1;
471
 
                        }
472
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
473
 
                                   "AT_NEXT_PSEUDONYM");
474
 
                        plen = apos[0] * 256 + apos[1];
475
 
                        if (plen > alen - 2) {
476
 
                                wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
477
 
                                           " AT_NEXT_PSEUDONYM (actual"
478
 
                                           " len %lu, attr len %lu)",
479
 
                                           (unsigned long) plen,
480
 
                                           (unsigned long) alen);
481
 
                                return -1;
482
 
                        }
483
 
                        attr->next_pseudonym = pos + 4;
484
 
                        attr->next_pseudonym_len = plen;
485
 
                        break;
486
 
                case EAP_SIM_AT_NEXT_REAUTH_ID:
487
 
                        if (!encr) {
488
 
                                wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
489
 
                                           "AT_NEXT_REAUTH_ID");
490
 
                                return -1;
491
 
                        }
492
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
493
 
                                   "AT_NEXT_REAUTH_ID");
494
 
                        plen = apos[0] * 256 + apos[1];
495
 
                        if (plen > alen - 2) {
496
 
                                wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
497
 
                                           " AT_NEXT_REAUTH_ID (actual"
498
 
                                           " len %lu, attr len %lu)",
499
 
                                           (unsigned long) plen,
500
 
                                           (unsigned long) alen);
501
 
                                return -1;
502
 
                        }
503
 
                        attr->next_reauth_id = pos + 4;
504
 
                        attr->next_reauth_id_len = plen;
505
 
                        break;
506
 
                case EAP_SIM_AT_RES:
507
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
508
 
                        apos += 2;
509
 
                        alen -= 2;
510
 
                        if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
511
 
                            alen > EAP_AKA_MAX_RES_LEN) {
512
 
                                wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
513
 
                                           "(len %lu)",
514
 
                                           (unsigned long) alen);
515
 
                                return -1;
516
 
                        }
517
 
                        attr->res = apos;
518
 
                        attr->res_len = alen;
519
 
                        break;
520
 
                case EAP_SIM_AT_AUTS:
521
 
                        wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
522
 
                        if (!aka) {
523
 
                                wpa_printf(MSG_DEBUG, "EAP-SIM: "
524
 
                                           "Unexpected AT_AUTS");
525
 
                                return -1;
526
 
                        }
527
 
                        if (alen != EAP_AKA_AUTS_LEN) {
528
 
                                wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
529
 
                                           " (len %lu)",
530
 
                                           (unsigned long) alen);
531
 
                                return -1;
532
 
                        }
533
 
                        attr->auts = apos;
534
 
                        break;
535
 
                default:
536
 
                        if (pos[0] < 128) {
537
 
                                wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
538
 
                                           "non-skippable attribute %d",
539
 
                                           pos[0]);
540
 
                                return -1;
541
 
                        }
542
 
 
543
 
                        wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
544
 
                                   " attribute %d ignored", pos[0]);
545
 
                        break;
546
 
                }
547
 
 
548
 
                pos += pos[1] * 4;
549
 
        }
550
 
 
551
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
552
 
                   "(aka=%d encr=%d)", aka, encr);
553
 
 
554
 
        return 0;
555
 
}
556
 
 
557
 
 
558
 
u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
559
 
                        size_t encr_data_len, const u8 *iv,
560
 
                        struct eap_sim_attrs *attr, int aka)
561
 
{
562
 
        u8 *decrypted;
563
 
 
564
 
        if (!iv) {
565
 
                wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
566
 
                return NULL;
567
 
        }
568
 
 
569
 
        decrypted = os_malloc(encr_data_len);
570
 
        if (decrypted == NULL)
571
 
                return NULL;
572
 
        os_memcpy(decrypted, encr_data, encr_data_len);
573
 
 
574
 
        aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len);
575
 
        wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
576
 
                    decrypted, encr_data_len);
577
 
 
578
 
        if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
579
 
                               aka, 1)) {
580
 
                wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
581
 
                           "decrypted AT_ENCR_DATA");
582
 
                os_free(decrypted);
583
 
                return NULL;
584
 
        }
585
 
 
586
 
        return decrypted;
587
 
}
588
 
 
589
 
 
590
 
#define EAP_SIM_INIT_LEN 128
591
 
 
592
 
struct eap_sim_msg {
593
 
        u8 *buf;
594
 
        size_t buf_len, used;
595
 
        size_t mac, iv, encr; /* index from buf */
596
 
};
597
 
 
598
 
 
599
 
struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
600
 
{
601
 
        struct eap_sim_msg *msg;
602
 
        struct eap_hdr *eap;
603
 
        u8 *pos;
604
 
 
605
 
        msg = os_zalloc(sizeof(*msg));
606
 
        if (msg == NULL)
607
 
                return NULL;
608
 
 
609
 
        msg->buf = os_zalloc(EAP_SIM_INIT_LEN);
610
 
        if (msg->buf == NULL) {
611
 
                os_free(msg);
612
 
                return NULL;
613
 
        }
614
 
        msg->buf_len = EAP_SIM_INIT_LEN;
615
 
        eap = (struct eap_hdr *) msg->buf;
616
 
        eap->code = code;
617
 
        eap->identifier = id;
618
 
        msg->used = sizeof(*eap);
619
 
 
620
 
        pos = (u8 *) (eap + 1);
621
 
        *pos++ = type;
622
 
        *pos++ = subtype;
623
 
        *pos++ = 0; /* Reserved */
624
 
        *pos++ = 0; /* Reserved */
625
 
        msg->used += 4;
626
 
 
627
 
        return msg;
628
 
}
629
 
 
630
 
 
631
 
u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
632
 
                        const u8 *extra, size_t extra_len)
633
 
{
634
 
        struct eap_hdr *eap;
635
 
        u8 *buf;
636
 
 
637
 
        if (msg == NULL)
638
 
                return NULL;
639
 
 
640
 
        eap = (struct eap_hdr *) msg->buf;
641
 
        eap->length = host_to_be16(msg->used);
642
 
 
643
 
        if (k_aut && msg->mac) {
644
 
                eap_sim_add_mac(k_aut, msg->buf, msg->used,
645
 
                                msg->buf + msg->mac, extra, extra_len);
646
 
        }
647
 
 
648
 
        *len = msg->used;
649
 
        buf = msg->buf;
650
 
        os_free(msg);
651
 
        return buf;
652
 
}
653
 
 
654
 
 
655
 
void eap_sim_msg_free(struct eap_sim_msg *msg)
656
 
{
657
 
        if (msg) {
658
 
                os_free(msg->buf);
659
 
                os_free(msg);
660
 
        }
661
 
}
662
 
 
663
 
 
664
 
static int eap_sim_msg_resize(struct eap_sim_msg *msg, size_t add_len)
665
 
{
666
 
        if (msg->used + add_len > msg->buf_len) {
667
 
                u8 *nbuf = os_realloc(msg->buf, msg->used + add_len);
668
 
                if (nbuf == NULL)
669
 
                        return -1;
670
 
                msg->buf = nbuf;
671
 
                msg->buf_len = msg->used + add_len;
672
 
        }
673
 
        return 0;
674
 
}
675
 
 
676
 
 
677
 
u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
678
 
                          const u8 *data, size_t len)
679
 
{
680
 
        int attr_len = 2 + len;
681
 
        int pad_len;
682
 
        u8 *start, *pos;
683
 
 
684
 
        if (msg == NULL)
685
 
                return NULL;
686
 
 
687
 
        pad_len = (4 - attr_len % 4) % 4;
688
 
        attr_len += pad_len;
689
 
        if (eap_sim_msg_resize(msg, attr_len))
690
 
                return NULL;
691
 
        start = pos = msg->buf + msg->used;
692
 
        *pos++ = attr;
693
 
        *pos++ = attr_len / 4;
694
 
        os_memcpy(pos, data, len);
695
 
        if (pad_len) {
696
 
                pos += len;
697
 
                os_memset(pos, 0, pad_len);
698
 
        }
699
 
        msg->used += attr_len;
700
 
        return start;
701
 
}
702
 
 
703
 
 
704
 
u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
705
 
                     const u8 *data, size_t len)
706
 
{
707
 
        int attr_len = 4 + len;
708
 
        int pad_len;
709
 
        u8 *start, *pos;
710
 
 
711
 
        if (msg == NULL)
712
 
                return NULL;
713
 
 
714
 
        pad_len = (4 - attr_len % 4) % 4;
715
 
        attr_len += pad_len;
716
 
        if (eap_sim_msg_resize(msg, attr_len))
717
 
                return NULL;
718
 
        start = pos = msg->buf + msg->used;
719
 
        *pos++ = attr;
720
 
        *pos++ = attr_len / 4;
721
 
        WPA_PUT_BE16(pos, value);
722
 
        pos += 2;
723
 
        if (data)
724
 
                os_memcpy(pos, data, len);
725
 
        if (pad_len) {
726
 
                pos += len;
727
 
                os_memset(pos, 0, pad_len);
728
 
        }
729
 
        msg->used += attr_len;
730
 
        return start;
731
 
}
732
 
 
733
 
 
734
 
u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
735
 
{
736
 
        u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
737
 
        if (pos)
738
 
                msg->mac = (pos - msg->buf) + 4;
739
 
        return pos;
740
 
}
741
 
 
742
 
 
743
 
int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
744
 
                               u8 attr_encr)
745
 
{
746
 
        u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
747
 
        if (pos == NULL)
748
 
                return -1;
749
 
        msg->iv = (pos - msg->buf) + 4;
750
 
        if (hostapd_get_rand(msg->buf + msg->iv, EAP_SIM_IV_LEN)) {
751
 
                msg->iv = 0;
752
 
                return -1;
753
 
        }
754
 
 
755
 
        pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
756
 
        if (pos == NULL) {
757
 
                msg->iv = 0;
758
 
                return -1;
759
 
        }
760
 
        msg->encr = pos - msg->buf;
761
 
 
762
 
        return 0;
763
 
}
764
 
 
765
 
 
766
 
int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
767
 
{
768
 
        size_t encr_len;
769
 
 
770
 
        if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
771
 
                return -1;
772
 
 
773
 
        encr_len = msg->used - msg->encr - 4;
774
 
        if (encr_len % 16) {
775
 
                u8 *pos;
776
 
                int pad_len = 16 - (encr_len % 16);
777
 
                if (pad_len < 4) {
778
 
                        wpa_printf(MSG_WARNING, "EAP-SIM: "
779
 
                                   "eap_sim_msg_add_encr_end - invalid pad_len"
780
 
                                   " %d", pad_len);
781
 
                        return -1;
782
 
                }
783
 
                wpa_printf(MSG_DEBUG, "   *AT_PADDING");
784
 
                pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
785
 
                if (pos == NULL)
786
 
                        return -1;
787
 
                os_memset(pos + 4, 0, pad_len - 4);
788
 
                encr_len += pad_len;
789
 
        }
790
 
        wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
791
 
                   (unsigned long) encr_len);
792
 
        msg->buf[msg->encr + 1] = encr_len / 4 + 1;
793
 
        aes_128_cbc_encrypt(k_encr, msg->buf + msg->iv,
794
 
                            msg->buf + msg->encr + 4, encr_len);
795
 
 
796
 
        return 0;
797
 
}
798
 
 
799
 
 
800
 
void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
801
 
{
802
 
#ifndef CONFIG_NO_STDOUT_DEBUG
803
 
        const char *type = aka ? "AKA" : "SIM";
804
 
#endif /* CONFIG_NO_STDOUT_DEBUG */
805
 
 
806
 
        switch (notification) {
807
 
        case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
808
 
                wpa_printf(MSG_WARNING, "EAP-%s: General failure "
809
 
                           "notification (after authentication)", type);
810
 
                break;
811
 
        case EAP_SIM_TEMPORARILY_DENIED:
812
 
                wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
813
 
                           "User has been temporarily denied access to the "
814
 
                           "requested service", type);
815
 
                break;
816
 
        case EAP_SIM_NOT_SUBSCRIBED:
817
 
                wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
818
 
                           "User has not subscribed to the requested service",
819
 
                           type);
820
 
                break;
821
 
        case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
822
 
                wpa_printf(MSG_WARNING, "EAP-%s: General failure "
823
 
                           "notification (before authentication)", type);
824
 
                break;
825
 
        case EAP_SIM_SUCCESS:
826
 
                wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
827
 
                           "notification", type);
828
 
                break;
829
 
        default:
830
 
                if (notification >= 32768) {
831
 
                        wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
832
 
                                   "non-failure notification %d",
833
 
                                   type, notification);
834
 
                } else {
835
 
                        wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
836
 
                                   "failure notification %d",
837
 
                                   type, notification);
838
 
                }
839
 
        }
840
 
}