9d1bf2ccdfb29084b52c965b197ba3fb07744aa6
[libeap.git] / src / eap_common / eap_sim_common.c
1 /*
2  * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
3  * Copyright (c) 2004-2008, 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 "sha256.h"
21 #include "crypto.h"
22 #include "aes_wrap.h"
23 #include "wpabuf.h"
24 #include "eap_common/eap_sim_common.h"
25
26
27 static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
28 {
29         return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
30 }
31
32
33 void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
34                        const u8 *nonce_mt, u16 selected_version,
35                        const u8 *ver_list, size_t ver_list_len,
36                        int num_chal, const u8 *kc, u8 *mk)
37 {
38         u8 sel_ver[2];
39         const unsigned char *addr[5];
40         size_t len[5];
41
42         addr[0] = identity;
43         len[0] = identity_len;
44         addr[1] = kc;
45         len[1] = num_chal * EAP_SIM_KC_LEN;
46         addr[2] = nonce_mt;
47         len[2] = EAP_SIM_NONCE_MT_LEN;
48         addr[3] = ver_list;
49         len[3] = ver_list_len;
50         addr[4] = sel_ver;
51         len[4] = 2;
52
53         WPA_PUT_BE16(sel_ver, selected_version);
54
55         /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
56         sha1_vector(5, addr, len, mk);
57         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
58 }
59
60
61 void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
62                        const u8 *ik, const u8 *ck, u8 *mk)
63 {
64         const u8 *addr[3];
65         size_t len[3];
66
67         addr[0] = identity;
68         len[0] = identity_len;
69         addr[1] = ik;
70         len[1] = EAP_AKA_IK_LEN;
71         addr[2] = ck;
72         len[2] = EAP_AKA_CK_LEN;
73
74         /* MK = SHA1(Identity|IK|CK) */
75         sha1_vector(3, addr, len, mk);
76         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
77         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
78         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
79 }
80
81
82 int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
83 {
84         u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
85                EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
86         if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
87                 wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
88                 return -1;
89         }
90         pos = buf;
91         os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
92         pos += EAP_SIM_K_ENCR_LEN;
93         os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
94         pos += EAP_SIM_K_AUT_LEN;
95         os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
96         pos += EAP_SIM_KEYING_DATA_LEN;
97         os_memcpy(emsk, pos, EAP_EMSK_LEN);
98
99         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
100                         k_encr, EAP_SIM_K_ENCR_LEN);
101         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
102                         k_aut, EAP_SIM_K_AUT_LEN);
103         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
104                         msk, EAP_SIM_KEYING_DATA_LEN);
105         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
106         os_memset(buf, 0, sizeof(buf));
107
108         return 0;
109 }
110
111
112 int eap_sim_derive_keys_reauth(u16 _counter,
113                                const u8 *identity, size_t identity_len,
114                                const u8 *nonce_s, const u8 *mk, u8 *msk,
115                                u8 *emsk)
116 {
117         u8 xkey[SHA1_MAC_LEN];
118         u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
119         u8 counter[2];
120         const u8 *addr[4];
121         size_t len[4];
122
123         while (identity_len > 0 && identity[identity_len - 1] == 0) {
124                 wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop null "
125                            "character from the end of identity");
126                 identity_len--;
127         }
128         addr[0] = identity;
129         len[0] = identity_len;
130         addr[1] = counter;
131         len[1] = 2;
132         addr[2] = nonce_s;
133         len[2] = EAP_SIM_NONCE_S_LEN;
134         addr[3] = mk;
135         len[3] = EAP_SIM_MK_LEN;
136
137         WPA_PUT_BE16(counter, _counter);
138
139         wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
140         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
141                           identity, identity_len);
142         wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
143         wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
144                     EAP_SIM_NONCE_S_LEN);
145         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
146
147         /* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
148         sha1_vector(4, addr, len, xkey);
149         wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
150
151         if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
152                 wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
153                 return -1;
154         }
155         if (msk) {
156                 os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
157                 wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
158                             msk, EAP_SIM_KEYING_DATA_LEN);
159         }
160         if (emsk) {
161                 os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
162                 wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
163         }
164         os_memset(buf, 0, sizeof(buf));
165
166         return 0;
167 }
168
169
170 int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
171                        const u8 *mac, const u8 *extra, size_t extra_len)
172 {
173         unsigned char hmac[SHA1_MAC_LEN];
174         const u8 *addr[2];
175         size_t len[2];
176         u8 *tmp;
177
178         if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
179             mac < wpabuf_head_u8(req) ||
180             mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
181                 return -1;
182
183         tmp = os_malloc(wpabuf_len(req));
184         if (tmp == NULL)
185                 return -1;
186
187         addr[0] = tmp;
188         len[0] = wpabuf_len(req);
189         addr[1] = extra;
190         len[1] = extra_len;
191
192         /* HMAC-SHA1-128 */
193         os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
194         os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
195         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg",
196                     tmp, wpabuf_len(req));
197         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
198                     extra, extra_len);
199         wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
200                         k_aut, EAP_SIM_K_AUT_LEN);
201         hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
202         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
203                     hmac, EAP_SIM_MAC_LEN);
204         os_free(tmp);
205
206         return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
207 }
208
209
210 void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac,
211                      const u8 *extra, size_t extra_len)
212 {
213         unsigned char hmac[SHA1_MAC_LEN];
214         const u8 *addr[2];
215         size_t len[2];
216
217         addr[0] = msg;
218         len[0] = msg_len;
219         addr[1] = extra;
220         len[1] = extra_len;
221
222         /* HMAC-SHA1-128 */
223         os_memset(mac, 0, EAP_SIM_MAC_LEN);
224         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
225         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
226                     extra, extra_len);
227         wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
228                         k_aut, EAP_SIM_K_AUT_LEN);
229         hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
230         os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
231         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
232                     mac, EAP_SIM_MAC_LEN);
233 }
234
235
236 #ifdef EAP_AKA_PRIME
237 static void prf_prime(const u8 *k, const char *seed1,
238                       const u8 *seed2, size_t seed2_len,
239                       const u8 *seed3, size_t seed3_len,
240                       u8 *res, size_t res_len)
241 {
242         const u8 *addr[5];
243         size_t len[5];
244         u8 hash[SHA256_MAC_LEN];
245         u8 iter;
246
247         /*
248          * PRF'(K,S) = T1 | T2 | T3 | T4 | ...
249          * T1 = HMAC-SHA-256 (K, S | 0x01)
250          * T2 = HMAC-SHA-256 (K, T1 | S | 0x02)
251          * T3 = HMAC-SHA-256 (K, T2 | S | 0x03)
252          * T4 = HMAC-SHA-256 (K, T3 | S | 0x04)
253          * ...
254          */
255
256         addr[0] = hash;
257         len[0] = 0;
258         addr[1] = (const u8 *) seed1;
259         len[1] = os_strlen(seed1);
260         addr[2] = seed2;
261         len[2] = seed2_len;
262         addr[3] = seed3;
263         len[3] = seed3_len;
264         addr[4] = &iter;
265         len[4] = 1;
266
267         iter = 0;
268         while (res_len) {
269                 size_t hlen;
270                 iter++;
271                 hmac_sha256_vector(k, 32, 5, addr, len, hash);
272                 len[0] = SHA256_MAC_LEN;
273                 hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len;
274                 os_memcpy(res, hash, hlen);
275                 res += hlen;
276                 res_len -= hlen;
277         }
278 }
279
280
281 void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
282                                const u8 *ik, const u8 *ck, u8 *k_encr,
283                                u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk)
284 {
285         u8 key[EAP_AKA_IK_LEN + EAP_AKA_CK_LEN];
286         u8 keys[EAP_SIM_K_ENCR_LEN + EAP_AKA_PRIME_K_AUT_LEN +
287                 EAP_AKA_PRIME_K_RE_LEN + EAP_MSK_LEN + EAP_EMSK_LEN];
288         u8 *pos;
289
290         /*
291          * MK = PRF'(IK'|CK',"EAP-AKA'"|Identity)
292          * K_encr = MK[0..127]
293          * K_aut  = MK[128..383]
294          * K_re   = MK[384..639]
295          * MSK    = MK[640..1151]
296          * EMSK   = MK[1152..1663]
297          */
298
299         os_memcpy(key, ik, EAP_AKA_IK_LEN);
300         os_memcpy(key + EAP_AKA_IK_LEN, ck, EAP_AKA_CK_LEN);
301
302         prf_prime(key, "EAP-AKA'", identity, identity_len, NULL, 0,
303                   keys, sizeof(keys));
304
305         pos = keys;
306         os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
307         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_encr",
308                         k_encr, EAP_SIM_K_ENCR_LEN);
309         pos += EAP_SIM_K_ENCR_LEN;
310
311         os_memcpy(k_aut, pos, EAP_AKA_PRIME_K_AUT_LEN);
312         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_aut",
313                         k_aut, EAP_AKA_PRIME_K_AUT_LEN);
314         pos += EAP_AKA_PRIME_K_AUT_LEN;
315
316         os_memcpy(k_re, pos, EAP_AKA_PRIME_K_RE_LEN);
317         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_re",
318                         k_re, EAP_AKA_PRIME_K_RE_LEN);
319         pos += EAP_AKA_PRIME_K_RE_LEN;
320
321         os_memcpy(msk, pos, EAP_MSK_LEN);
322         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
323         pos += EAP_MSK_LEN;
324
325         os_memcpy(emsk, pos, EAP_EMSK_LEN);
326         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
327 }
328
329
330 int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
331                                      const u8 *identity, size_t identity_len,
332                                      const u8 *nonce_s, u8 *msk, u8 *emsk)
333 {
334         u8 seed3[2 + EAP_SIM_NONCE_S_LEN];
335         u8 keys[EAP_MSK_LEN + EAP_EMSK_LEN];
336         u8 *pos;
337
338         /*
339          * MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S)
340          * MSK  = MK[0..511]
341          * EMSK = MK[512..1023]
342          */
343
344         WPA_PUT_BE16(seed3, counter);
345         os_memcpy(seed3 + 2, nonce_s, EAP_SIM_NONCE_S_LEN);
346
347         prf_prime(k_re, "EAP-AKA' re-auth", identity, identity_len,
348                   seed3, sizeof(seed3),
349                   keys, sizeof(keys));
350
351         pos = keys;
352         os_memcpy(msk, pos, EAP_MSK_LEN);
353         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
354         pos += EAP_MSK_LEN;
355
356         os_memcpy(emsk, pos, EAP_EMSK_LEN);
357         wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
358
359         os_memset(keys, 0, sizeof(keys));
360
361         return 0;
362 }
363
364
365 int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
366                               const u8 *mac, const u8 *extra, size_t extra_len)
367 {
368         unsigned char hmac[SHA256_MAC_LEN];
369         const u8 *addr[2];
370         size_t len[2];
371         u8 *tmp;
372
373         if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
374             mac < wpabuf_head_u8(req) ||
375             mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
376                 return -1;
377
378         tmp = os_malloc(wpabuf_len(req));
379         if (tmp == NULL)
380                 return -1;
381
382         addr[0] = tmp;
383         len[0] = wpabuf_len(req);
384         addr[1] = extra;
385         len[1] = extra_len;
386
387         /* HMAC-SHA-256-128 */
388         os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
389         os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
390         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg",
391                     tmp, wpabuf_len(req));
392         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data",
393                     extra, extra_len);
394         wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut",
395                         k_aut, EAP_AKA_PRIME_K_AUT_LEN);
396         hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
397         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC",
398                     hmac, EAP_SIM_MAC_LEN);
399         os_free(tmp);
400
401         return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
402 }
403
404
405 void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
406                             u8 *mac, const u8 *extra, size_t extra_len)
407 {
408         unsigned char hmac[SHA256_MAC_LEN];
409         const u8 *addr[2];
410         size_t len[2];
411
412         addr[0] = msg;
413         len[0] = msg_len;
414         addr[1] = extra;
415         len[1] = extra_len;
416
417         /* HMAC-SHA-256-128 */
418         os_memset(mac, 0, EAP_SIM_MAC_LEN);
419         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len);
420         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data",
421                     extra, extra_len);
422         wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut",
423                         k_aut, EAP_AKA_PRIME_K_AUT_LEN);
424         hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
425         os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
426         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC",
427                     mac, EAP_SIM_MAC_LEN);
428 }
429 #endif /* EAP_AKA_PRIME */
430
431
432 int eap_sim_parse_attr(const u8 *start, const u8 *end,
433                        struct eap_sim_attrs *attr, int aka, int encr)
434 {
435         const u8 *pos = start, *apos;
436         size_t alen, plen, i, list_len;
437
438         os_memset(attr, 0, sizeof(*attr));
439         attr->id_req = NO_ID_REQ;
440         attr->notification = -1;
441         attr->counter = -1;
442         attr->selected_version = -1;
443         attr->client_error_code = -1;
444
445         while (pos < end) {
446                 if (pos + 2 > end) {
447                         wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
448                         return -1;
449                 }
450                 wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
451                            pos[0], pos[1] * 4);
452                 if (pos + pos[1] * 4 > end) {
453                         wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
454                                    "(pos=%p len=%d end=%p)",
455                                    pos, pos[1] * 4, end);
456                         return -1;
457                 }
458                 if (pos[1] == 0) {
459                         wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow");
460                         return -1;
461                 }
462                 apos = pos + 2;
463                 alen = pos[1] * 4 - 2;
464                 wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
465                             apos, alen);
466
467                 switch (pos[0]) {
468                 case EAP_SIM_AT_RAND:
469                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
470                         apos += 2;
471                         alen -= 2;
472                         if ((!aka && (alen % GSM_RAND_LEN)) ||
473                             (aka && alen != EAP_AKA_RAND_LEN)) {
474                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
475                                            " (len %lu)",
476                                            (unsigned long) alen);
477                                 return -1;
478                         }
479                         attr->rand = apos;
480                         attr->num_chal = alen / GSM_RAND_LEN;
481                         break;
482                 case EAP_SIM_AT_AUTN:
483                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
484                         if (!aka) {
485                                 wpa_printf(MSG_DEBUG, "EAP-SIM: "
486                                            "Unexpected AT_AUTN");
487                                 return -1;
488                         }
489                         apos += 2;
490                         alen -= 2;
491                         if (alen != EAP_AKA_AUTN_LEN) {
492                                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
493                                            " (len %lu)",
494                                            (unsigned long) alen);
495                                 return -1;
496                         }
497                         attr->autn = apos;
498                         break;
499                 case EAP_SIM_AT_PADDING:
500                         if (!encr) {
501                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
502                                            "AT_PADDING");
503                                 return -1;
504                         }
505                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
506                         for (i = 2; i < alen; i++) {
507                                 if (apos[i] != 0) {
508                                         wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
509                                                    "AT_PADDING used a non-zero"
510                                                    " padding byte");
511                                         wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
512                                                     "(encr) padding bytes",
513                                                     apos + 2, alen - 2);
514                                         return -1;
515                                 }
516                         }
517                         break;
518                 case EAP_SIM_AT_NONCE_MT:
519                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
520                         if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
521                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
522                                            "AT_NONCE_MT length");
523                                 return -1;
524                         }
525                         attr->nonce_mt = apos + 2;
526                         break;
527                 case EAP_SIM_AT_PERMANENT_ID_REQ:
528                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
529                         attr->id_req = PERMANENT_ID;
530                         break;
531                 case EAP_SIM_AT_MAC:
532                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
533                         if (alen != 2 + EAP_SIM_MAC_LEN) {
534                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
535                                            "length");
536                                 return -1;
537                         }
538                         attr->mac = apos + 2;
539                         break;
540                 case EAP_SIM_AT_NOTIFICATION:
541                         if (alen != 2) {
542                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
543                                            "AT_NOTIFICATION length %lu",
544                                            (unsigned long) alen);
545                                 return -1;
546                         }
547                         attr->notification = apos[0] * 256 + apos[1];
548                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
549                                    attr->notification);
550                         break;
551                 case EAP_SIM_AT_ANY_ID_REQ:
552                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
553                         attr->id_req = ANY_ID;
554                         break;
555                 case EAP_SIM_AT_IDENTITY:
556                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
557                         plen = WPA_GET_BE16(apos);
558                         apos += 2;
559                         alen -= 2;
560                         if (plen > alen) {
561                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
562                                            "AT_IDENTITY (Actual Length %lu, "
563                                            "remaining length %lu)",
564                                            (unsigned long) plen,
565                                            (unsigned long) alen);
566                                 return -1;
567                         }
568
569                         attr->identity = apos;
570                         attr->identity_len = plen;
571                         break;
572                 case EAP_SIM_AT_VERSION_LIST:
573                         if (aka) {
574                                 wpa_printf(MSG_DEBUG, "EAP-AKA: "
575                                            "Unexpected AT_VERSION_LIST");
576                                 return -1;
577                         }
578                         list_len = apos[0] * 256 + apos[1];
579                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
580                         if (list_len < 2 || list_len > alen - 2) {
581                                 wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
582                                            "AT_VERSION_LIST (list_len=%lu "
583                                            "attr_len=%lu)",
584                                            (unsigned long) list_len,
585                                            (unsigned long) alen);
586                                 return -1;
587                         }
588                         attr->version_list = apos + 2;
589                         attr->version_list_len = list_len;
590                         break;
591                 case EAP_SIM_AT_SELECTED_VERSION:
592                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
593                         if (alen != 2) {
594                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
595                                            "AT_SELECTED_VERSION length %lu",
596                                            (unsigned long) alen);
597                                 return -1;
598                         }
599                         attr->selected_version = apos[0] * 256 + apos[1];
600                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
601                                    "%d", attr->selected_version);
602                         break;
603                 case EAP_SIM_AT_FULLAUTH_ID_REQ:
604                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
605                         attr->id_req = FULLAUTH_ID;
606                         break;
607                 case EAP_SIM_AT_COUNTER:
608                         if (!encr) {
609                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
610                                            "AT_COUNTER");
611                                 return -1;
612                         }
613                         if (alen != 2) {
614                                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
615                                            "AT_COUNTER (alen=%lu)",
616                                            (unsigned long) alen);
617                                 return -1;
618                         }
619                         attr->counter = apos[0] * 256 + apos[1];
620                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
621                                    attr->counter);
622                         break;
623                 case EAP_SIM_AT_COUNTER_TOO_SMALL:
624                         if (!encr) {
625                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
626                                            "AT_COUNTER_TOO_SMALL");
627                                 return -1;
628                         }
629                         if (alen != 2) {
630                                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
631                                            "AT_COUNTER_TOO_SMALL (alen=%lu)",
632                                            (unsigned long) alen);
633                                 return -1;
634                         }
635                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
636                                    "AT_COUNTER_TOO_SMALL");
637                         attr->counter_too_small = 1;
638                         break;
639                 case EAP_SIM_AT_NONCE_S:
640                         if (!encr) {
641                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
642                                            "AT_NONCE_S");
643                                 return -1;
644                         }
645                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
646                                    "AT_NONCE_S");
647                         if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
648                                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
649                                            "AT_NONCE_S (alen=%lu)",
650                                            (unsigned long) alen);
651                                 return -1;
652                         }
653                         attr->nonce_s = apos + 2;
654                         break;
655                 case EAP_SIM_AT_CLIENT_ERROR_CODE:
656                         if (alen != 2) {
657                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
658                                            "AT_CLIENT_ERROR_CODE length %lu",
659                                            (unsigned long) alen);
660                                 return -1;
661                         }
662                         attr->client_error_code = apos[0] * 256 + apos[1];
663                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
664                                    "%d", attr->client_error_code);
665                         break;
666                 case EAP_SIM_AT_IV:
667                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
668                         if (alen != 2 + EAP_SIM_MAC_LEN) {
669                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
670                                            "length %lu", (unsigned long) alen);
671                                 return -1;
672                         }
673                         attr->iv = apos + 2;
674                         break;
675                 case EAP_SIM_AT_ENCR_DATA:
676                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
677                         attr->encr_data = apos + 2;
678                         attr->encr_data_len = alen - 2;
679                         if (attr->encr_data_len % 16) {
680                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
681                                            "AT_ENCR_DATA length %lu",
682                                            (unsigned long)
683                                            attr->encr_data_len);
684                                 return -1;
685                         }
686                         break;
687                 case EAP_SIM_AT_NEXT_PSEUDONYM:
688                         if (!encr) {
689                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
690                                            "AT_NEXT_PSEUDONYM");
691                                 return -1;
692                         }
693                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
694                                    "AT_NEXT_PSEUDONYM");
695                         plen = apos[0] * 256 + apos[1];
696                         if (plen > alen - 2) {
697                                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
698                                            " AT_NEXT_PSEUDONYM (actual"
699                                            " len %lu, attr len %lu)",
700                                            (unsigned long) plen,
701                                            (unsigned long) alen);
702                                 return -1;
703                         }
704                         attr->next_pseudonym = pos + 4;
705                         attr->next_pseudonym_len = plen;
706                         break;
707                 case EAP_SIM_AT_NEXT_REAUTH_ID:
708                         if (!encr) {
709                                 wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
710                                            "AT_NEXT_REAUTH_ID");
711                                 return -1;
712                         }
713                         wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
714                                    "AT_NEXT_REAUTH_ID");
715                         plen = apos[0] * 256 + apos[1];
716                         if (plen > alen - 2) {
717                                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
718                                            " AT_NEXT_REAUTH_ID (actual"
719                                            " len %lu, attr len %lu)",
720                                            (unsigned long) plen,
721                                            (unsigned long) alen);
722                                 return -1;
723                         }
724                         attr->next_reauth_id = pos + 4;
725                         attr->next_reauth_id_len = plen;
726                         break;
727                 case EAP_SIM_AT_RES:
728                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
729                         attr->res_len_bits = WPA_GET_BE16(apos);
730                         apos += 2;
731                         alen -= 2;
732                         if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
733                             alen > EAP_AKA_MAX_RES_LEN) {
734                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
735                                            "(len %lu)",
736                                            (unsigned long) alen);
737                                 return -1;
738                         }
739                         attr->res = apos;
740                         attr->res_len = alen;
741                         break;
742                 case EAP_SIM_AT_AUTS:
743                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
744                         if (!aka) {
745                                 wpa_printf(MSG_DEBUG, "EAP-SIM: "
746                                            "Unexpected AT_AUTS");
747                                 return -1;
748                         }
749                         if (alen != EAP_AKA_AUTS_LEN) {
750                                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
751                                            " (len %lu)",
752                                            (unsigned long) alen);
753                                 return -1;
754                         }
755                         attr->auts = apos;
756                         break;
757                 case EAP_SIM_AT_CHECKCODE:
758                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_CHECKCODE");
759                         if (!aka) {
760                                 wpa_printf(MSG_DEBUG, "EAP-SIM: "
761                                            "Unexpected AT_CHECKCODE");
762                                 return -1;
763                         }
764                         apos += 2;
765                         alen -= 2;
766                         if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN &&
767                             alen != EAP_AKA_PRIME_CHECKCODE_LEN) {
768                                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
769                                            "AT_CHECKCODE (len %lu)",
770                                            (unsigned long) alen);
771                                 return -1;
772                         }
773                         attr->checkcode = apos;
774                         attr->checkcode_len = alen;
775                         break;
776                 case EAP_SIM_AT_RESULT_IND:
777                         if (encr) {
778                                 wpa_printf(MSG_ERROR, "EAP-SIM: Encrypted "
779                                            "AT_RESULT_IND");
780                                 return -1;
781                         }
782                         if (alen != 2) {
783                                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
784                                            "AT_RESULT_IND (alen=%lu)",
785                                            (unsigned long) alen);
786                                 return -1;
787                         }
788                         wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND");
789                         attr->result_ind = 1;
790                         break;
791 #ifdef EAP_AKA_PRIME
792                 case EAP_SIM_AT_KDF_INPUT:
793                         if (aka != 2) {
794                                 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
795                                            "AT_KDF_INPUT");
796                                 return -1;
797                         }
798
799                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF_INPUT");
800                         plen = WPA_GET_BE16(apos);
801                         apos += 2;
802                         alen -= 2;
803                         if (plen > alen) {
804                                 wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
805                                            "AT_KDF_INPUT (Actual Length %lu, "
806                                            "remaining length %lu)",
807                                            (unsigned long) plen,
808                                            (unsigned long) alen);
809                                 return -1;
810                         }
811                         attr->kdf_input = apos;
812                         attr->kdf_input_len = plen;
813                         break;
814                 case EAP_SIM_AT_KDF:
815                         if (aka != 2) {
816                                 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
817                                            "AT_KDF");
818                                 return -1;
819                         }
820
821                         wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF");
822                         if (alen != 2) {
823                                 wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
824                                            "AT_KDF (len %lu)",
825                                            (unsigned long) alen);
826                                 return -1;
827                         }
828                         if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) {
829                                 wpa_printf(MSG_DEBUG, "EAP-AKA': Too many "
830                                            "AT_KDF attributes - ignore this");
831                                 continue;
832                         }
833                         attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos);
834                         attr->kdf_count++;
835                         break;
836 #endif /* EAP_AKA_PRIME */
837                 default:
838                         if (pos[0] < 128) {
839                                 wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
840                                            "non-skippable attribute %d",
841                                            pos[0]);
842                                 return -1;
843                         }
844
845                         wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
846                                    " attribute %d ignored", pos[0]);
847                         break;
848                 }
849
850                 pos += pos[1] * 4;
851         }
852
853         wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
854                    "(aka=%d encr=%d)", aka, encr);
855
856         return 0;
857 }
858
859
860 u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
861                         size_t encr_data_len, const u8 *iv,
862                         struct eap_sim_attrs *attr, int aka)
863 {
864         u8 *decrypted;
865
866         if (!iv) {
867                 wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
868                 return NULL;
869         }
870
871         decrypted = os_malloc(encr_data_len);
872         if (decrypted == NULL)
873                 return NULL;
874         os_memcpy(decrypted, encr_data, encr_data_len);
875
876         if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) {
877                 os_free(decrypted);
878                 return NULL;
879         }
880         wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
881                     decrypted, encr_data_len);
882
883         if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
884                                aka, 1)) {
885                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
886                            "decrypted AT_ENCR_DATA");
887                 os_free(decrypted);
888                 return NULL;
889         }
890
891         return decrypted;
892 }
893
894
895 #define EAP_SIM_INIT_LEN 128
896
897 struct eap_sim_msg {
898         struct wpabuf *buf;
899         size_t mac, iv, encr; /* index from buf */
900         int type;
901 };
902
903
904 struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
905 {
906         struct eap_sim_msg *msg;
907         struct eap_hdr *eap;
908         u8 *pos;
909
910         msg = os_zalloc(sizeof(*msg));
911         if (msg == NULL)
912                 return NULL;
913
914         msg->type = type;
915         msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN);
916         if (msg->buf == NULL) {
917                 os_free(msg);
918                 return NULL;
919         }
920         eap = wpabuf_put(msg->buf, sizeof(*eap));
921         eap->code = code;
922         eap->identifier = id;
923
924         pos = wpabuf_put(msg->buf, 4);
925         *pos++ = type;
926         *pos++ = subtype;
927         *pos++ = 0; /* Reserved */
928         *pos++ = 0; /* Reserved */
929
930         return msg;
931 }
932
933
934 struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
935                                    const u8 *extra, size_t extra_len)
936 {
937         struct eap_hdr *eap;
938         struct wpabuf *buf;
939
940         if (msg == NULL)
941                 return NULL;
942
943         eap = wpabuf_mhead(msg->buf);
944         eap->length = host_to_be16(wpabuf_len(msg->buf));
945
946 #ifdef EAP_AKA_PRIME
947         if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) {
948                 eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
949                                        wpabuf_len(msg->buf),
950                                        (u8 *) wpabuf_mhead(msg->buf) +
951                                        msg->mac, extra, extra_len);
952         } else
953 #endif /* EAP_AKA_PRIME */
954         if (k_aut && msg->mac) {
955                 eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf),
956                                 wpabuf_len(msg->buf),
957                                 (u8 *) wpabuf_mhead(msg->buf) + msg->mac,
958                                 extra, extra_len);
959         }
960
961         buf = msg->buf;
962         os_free(msg);
963         return buf;
964 }
965
966
967 void eap_sim_msg_free(struct eap_sim_msg *msg)
968 {
969         if (msg) {
970                 wpabuf_free(msg->buf);
971                 os_free(msg);
972         }
973 }
974
975
976 u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
977                           const u8 *data, size_t len)
978 {
979         int attr_len = 2 + len;
980         int pad_len;
981         u8 *start;
982
983         if (msg == NULL)
984                 return NULL;
985
986         pad_len = (4 - attr_len % 4) % 4;
987         attr_len += pad_len;
988         if (wpabuf_resize(&msg->buf, attr_len))
989                 return NULL;
990         start = wpabuf_put(msg->buf, 0);
991         wpabuf_put_u8(msg->buf, attr);
992         wpabuf_put_u8(msg->buf, attr_len / 4);
993         wpabuf_put_data(msg->buf, data, len);
994         if (pad_len)
995                 os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
996         return start;
997 }
998
999
1000 u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
1001                      const u8 *data, size_t len)
1002 {
1003         int attr_len = 4 + len;
1004         int pad_len;
1005         u8 *start;
1006
1007         if (msg == NULL)
1008                 return NULL;
1009
1010         pad_len = (4 - attr_len % 4) % 4;
1011         attr_len += pad_len;
1012         if (wpabuf_resize(&msg->buf, attr_len))
1013                 return NULL;
1014         start = wpabuf_put(msg->buf, 0);
1015         wpabuf_put_u8(msg->buf, attr);
1016         wpabuf_put_u8(msg->buf, attr_len / 4);
1017         wpabuf_put_be16(msg->buf, value);
1018         if (data)
1019                 wpabuf_put_data(msg->buf, data, len);
1020         else
1021                 wpabuf_put(msg->buf, len);
1022         if (pad_len)
1023                 os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
1024         return start;
1025 }
1026
1027
1028 u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
1029 {
1030         u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
1031         if (pos)
1032                 msg->mac = (pos - wpabuf_head_u8(msg->buf)) + 4;
1033         return pos;
1034 }
1035
1036
1037 int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
1038                                u8 attr_encr)
1039 {
1040         u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
1041         if (pos == NULL)
1042                 return -1;
1043         msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4;
1044         if (os_get_random(wpabuf_mhead_u8(msg->buf) + msg->iv,
1045                           EAP_SIM_IV_LEN)) {
1046                 msg->iv = 0;
1047                 return -1;
1048         }
1049
1050         pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
1051         if (pos == NULL) {
1052                 msg->iv = 0;
1053                 return -1;
1054         }
1055         msg->encr = pos - wpabuf_head_u8(msg->buf);
1056
1057         return 0;
1058 }
1059
1060
1061 int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
1062 {
1063         size_t encr_len;
1064
1065         if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
1066                 return -1;
1067
1068         encr_len = wpabuf_len(msg->buf) - msg->encr - 4;
1069         if (encr_len % 16) {
1070                 u8 *pos;
1071                 int pad_len = 16 - (encr_len % 16);
1072                 if (pad_len < 4) {
1073                         wpa_printf(MSG_WARNING, "EAP-SIM: "
1074                                    "eap_sim_msg_add_encr_end - invalid pad_len"
1075                                    " %d", pad_len);
1076                         return -1;
1077                 }
1078                 wpa_printf(MSG_DEBUG, "   *AT_PADDING");
1079                 pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
1080                 if (pos == NULL)
1081                         return -1;
1082                 os_memset(pos + 4, 0, pad_len - 4);
1083                 encr_len += pad_len;
1084         }
1085         wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
1086                    (unsigned long) encr_len);
1087         wpabuf_mhead_u8(msg->buf)[msg->encr + 1] = encr_len / 4 + 1;
1088         return aes_128_cbc_encrypt(k_encr, wpabuf_head_u8(msg->buf) + msg->iv,
1089                                    wpabuf_mhead_u8(msg->buf) + msg->encr + 4,
1090                                    encr_len);
1091 }
1092
1093
1094 void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
1095 {
1096 #ifndef CONFIG_NO_STDOUT_DEBUG
1097         const char *type = aka ? "AKA" : "SIM";
1098 #endif /* CONFIG_NO_STDOUT_DEBUG */
1099
1100         switch (notification) {
1101         case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
1102                 wpa_printf(MSG_WARNING, "EAP-%s: General failure "
1103                            "notification (after authentication)", type);
1104                 break;
1105         case EAP_SIM_TEMPORARILY_DENIED:
1106                 wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
1107                            "User has been temporarily denied access to the "
1108                            "requested service", type);
1109                 break;
1110         case EAP_SIM_NOT_SUBSCRIBED:
1111                 wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
1112                            "User has not subscribed to the requested service",
1113                            type);
1114                 break;
1115         case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
1116                 wpa_printf(MSG_WARNING, "EAP-%s: General failure "
1117                            "notification (before authentication)", type);
1118                 break;
1119         case EAP_SIM_SUCCESS:
1120                 wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
1121                            "notification", type);
1122                 break;
1123         default:
1124                 if (notification >= 32768) {
1125                         wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
1126                                    "non-failure notification %d",
1127                                    type, notification);
1128                 } else {
1129                         wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
1130                                    "failure notification %d",
1131                                    type, notification);
1132                 }
1133         }
1134 }