]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/hostapd/eap_sim.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / contrib / hostapd / eap_sim.c
1 /*
2  * hostapd / EAP-SIM (RFC 4186)
3  * Copyright (c) 2005-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 "hostapd.h"
18 #include "common.h"
19 #include "crypto.h"
20 #include "eap_i.h"
21 #include "eap_sim_common.h"
22 #include "eap_sim_db.h"
23
24
25 struct eap_sim_data {
26         u8 mk[EAP_SIM_MK_LEN];
27         u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
28         u8 nonce_s[EAP_SIM_NONCE_S_LEN];
29         u8 k_aut[EAP_SIM_K_AUT_LEN];
30         u8 k_encr[EAP_SIM_K_ENCR_LEN];
31         u8 msk[EAP_SIM_KEYING_DATA_LEN];
32         u8 emsk[EAP_EMSK_LEN];
33         u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
34         u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
35         u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
36         int num_chal;
37         enum { START, CHALLENGE, REAUTH, SUCCESS, FAILURE } state;
38         char *next_pseudonym;
39         char *next_reauth_id;
40         u16 counter;
41         struct eap_sim_reauth *reauth;
42 };
43
44
45 static const char * eap_sim_state_txt(int state)
46 {
47         switch (state) {
48         case START:
49                 return "START";
50         case CHALLENGE:
51                 return "CHALLENGE";
52         case REAUTH:
53                 return "REAUTH";
54         case SUCCESS:
55                 return "SUCCESS";
56         case FAILURE:
57                 return "FAILURE";
58         default:
59                 return "Unknown?!";
60         }
61 }
62
63
64 static void eap_sim_state(struct eap_sim_data *data, int state)
65 {
66         wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
67                    eap_sim_state_txt(data->state),
68                    eap_sim_state_txt(state));
69         data->state = state;
70 }
71
72
73 static void * eap_sim_init(struct eap_sm *sm)
74 {
75         struct eap_sim_data *data;
76
77         if (sm->eap_sim_db_priv == NULL) {
78                 wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
79                 return NULL;
80         }
81
82         data = wpa_zalloc(sizeof(*data));
83         if (data == NULL)
84                 return NULL;
85         data->state = START;
86
87         return data;
88 }
89
90
91 static void eap_sim_reset(struct eap_sm *sm, void *priv)
92 {
93         struct eap_sim_data *data = priv;
94         free(data->next_pseudonym);
95         free(data->next_reauth_id);
96         free(data);
97 }
98
99
100 static u8 * eap_sim_build_start(struct eap_sm *sm, struct eap_sim_data *data,
101                                 int id, size_t *reqDataLen)
102 {
103         struct eap_sim_msg *msg;
104         u8 ver[2];
105
106         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
107         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
108                                EAP_SIM_SUBTYPE_START);
109         if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
110                                       sm->identity_len)) {
111                 wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
112                 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
113         } else {
114                 /*
115                  * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
116                  * ignored and the SIM/Start is used to request the identity.
117                  */
118                 wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
119                 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
120         }
121         wpa_printf(MSG_DEBUG, "   AT_VERSION_LIST");
122         ver[0] = 0;
123         ver[1] = EAP_SIM_VERSION;
124         eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
125                         ver, sizeof(ver));
126         return eap_sim_msg_finish(msg, reqDataLen, NULL, NULL, 0);
127 }
128
129
130 static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
131                               struct eap_sim_msg *msg, u16 counter,
132                               const u8 *nonce_s)
133 {
134         free(data->next_pseudonym);
135         data->next_pseudonym =
136                 eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0);
137         free(data->next_reauth_id);
138         if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
139                 data->next_reauth_id =
140                         eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0);
141         } else {
142                 wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
143                            "count exceeded - force full authentication");
144                 data->next_reauth_id = NULL;
145         }
146
147         if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
148             counter == 0 && nonce_s == NULL)
149                 return 0;
150
151         wpa_printf(MSG_DEBUG, "   AT_IV");
152         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
153         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
154
155         if (counter > 0) {
156                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
157                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
158         }
159
160         if (nonce_s) {
161                 wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
162                 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
163                                 EAP_SIM_NONCE_S_LEN);
164         }
165
166         if (data->next_pseudonym) {
167                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
168                            data->next_pseudonym);
169                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
170                                 strlen(data->next_pseudonym),
171                                 (u8 *) data->next_pseudonym,
172                                 strlen(data->next_pseudonym));
173         }
174
175         if (data->next_reauth_id) {
176                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
177                            data->next_reauth_id);
178                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
179                                 strlen(data->next_reauth_id),
180                                 (u8 *) data->next_reauth_id,
181                                 strlen(data->next_reauth_id));
182         }
183
184         if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
185                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
186                            "AT_ENCR_DATA");
187                 return -1;
188         }
189
190         return 0;
191 }
192
193
194 static u8 * eap_sim_build_challenge(struct eap_sm *sm,
195                                     struct eap_sim_data *data,
196                                     int id, size_t *reqDataLen)
197 {
198         struct eap_sim_msg *msg;
199
200         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
201         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
202                                EAP_SIM_SUBTYPE_CHALLENGE);
203         wpa_printf(MSG_DEBUG, "   AT_RAND");
204         eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
205                         data->num_chal * GSM_RAND_LEN);
206
207         if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
208                 eap_sim_msg_free(msg);
209                 return NULL;
210         }
211
212         wpa_printf(MSG_DEBUG, "   AT_MAC");
213         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
214         return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, data->nonce_mt,
215                                   EAP_SIM_NONCE_MT_LEN);
216 }
217
218
219 static u8 * eap_sim_build_reauth(struct eap_sm *sm,
220                                  struct eap_sim_data *data,
221                                  int id, size_t *reqDataLen)
222 {
223         struct eap_sim_msg *msg;
224
225         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
226
227         if (hostapd_get_rand(data->nonce_s, EAP_SIM_NONCE_S_LEN))
228                 return NULL;
229         wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
230                         data->nonce_s, EAP_SIM_NONCE_S_LEN);
231
232         eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
233                             data->emsk);
234         eap_sim_derive_keys_reauth(data->counter, sm->identity,
235                                    sm->identity_len, data->nonce_s, data->mk,
236                                    data->msk, data->emsk);
237
238         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
239                                EAP_SIM_SUBTYPE_REAUTHENTICATION);
240
241         if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
242                 eap_sim_msg_free(msg);
243                 return NULL;
244         }
245
246         wpa_printf(MSG_DEBUG, "   AT_MAC");
247         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
248         return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, NULL, 0);
249 }
250
251
252 static u8 * eap_sim_buildReq(struct eap_sm *sm, void *priv, int id,
253                              size_t *reqDataLen)
254 {
255         struct eap_sim_data *data = priv;
256
257         switch (data->state) {
258         case START:
259                 return eap_sim_build_start(sm, data, id, reqDataLen);
260         case CHALLENGE:
261                 return eap_sim_build_challenge(sm, data, id, reqDataLen);
262         case REAUTH:
263                 return eap_sim_build_reauth(sm, data, id, reqDataLen);
264         default:
265                 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
266                            "buildReq", data->state);
267                 break;
268         }
269         return NULL;
270 }
271
272
273 static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
274                              u8 *respData, size_t respDataLen)
275 {
276         struct eap_sim_data *data = priv;
277         struct eap_hdr *resp;
278         u8 *pos, subtype;
279
280         resp = (struct eap_hdr *) respData;
281         pos = (u8 *) (resp + 1);
282         if (respDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_SIM ||
283             (ntohs(resp->length)) > respDataLen) {
284                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
285                 return TRUE;
286         }
287         subtype = pos[1];
288
289         if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
290                 return FALSE;
291
292         switch (data->state) {
293         case START:
294                 if (subtype != EAP_SIM_SUBTYPE_START) {
295                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
296                                    "subtype %d", subtype);
297                         return TRUE;
298                 }
299                 break;
300         case CHALLENGE:
301                 if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
302                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
303                                    "subtype %d", subtype);
304                         return TRUE;
305                 }
306                 break;
307         case REAUTH:
308                 if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
309                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
310                                    "subtype %d", subtype);
311                         return TRUE;
312                 }
313                 break;
314         default:
315                 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
316                            "processing a response", data->state);
317                 return TRUE;
318         }
319
320         return FALSE;
321 }
322
323
324 static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
325 {
326         return version == EAP_SIM_VERSION;
327 }
328
329
330 static void eap_sim_process_start(struct eap_sm *sm,
331                                   struct eap_sim_data *data,
332                                   u8 *respData, size_t respDataLen,
333                                   struct eap_sim_attrs *attr)
334 {
335         const u8 *identity;
336         size_t identity_len;
337         u8 ver_list[2];
338
339         wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
340
341         if (attr->identity) {
342                 free(sm->identity);
343                 sm->identity = malloc(attr->identity_len);
344                 if (sm->identity) {
345                         memcpy(sm->identity, attr->identity,
346                                attr->identity_len);
347                         sm->identity_len = attr->identity_len;
348                 }
349         }
350
351         identity = NULL;
352         identity_len = 0;
353
354         if (sm->identity && sm->identity_len > 0 &&
355             sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) {
356                 identity = sm->identity;
357                 identity_len = sm->identity_len;
358         } else {
359                 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
360                                                     sm->identity,
361                                                     sm->identity_len,
362                                                     &identity_len);
363                 if (identity == NULL) {
364                         data->reauth = eap_sim_db_get_reauth_entry(
365                                 sm->eap_sim_db_priv, sm->identity,
366                                 sm->identity_len);
367                         if (data->reauth) {
368                                 wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast "
369                                            "re-authentication");
370                                 identity = data->reauth->identity;
371                                 identity_len = data->reauth->identity_len;
372                                 data->counter = data->reauth->counter;
373                                 memcpy(data->mk, data->reauth->mk,
374                                        EAP_SIM_MK_LEN);
375                         }
376                 }
377         }
378
379         if (identity == NULL) {
380                 wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
381                            " user name");
382                 eap_sim_state(data, FAILURE);
383                 return;
384         }
385
386         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
387                           identity, identity_len);
388
389         if (data->reauth) {
390                 eap_sim_state(data, REAUTH);
391                 return;
392         }
393
394         if (attr->nonce_mt == NULL || attr->selected_version < 0) {
395                 wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
396                            "required attributes");
397                 eap_sim_state(data, FAILURE);
398                 return;
399         }
400
401         if (!eap_sim_supported_ver(data, attr->selected_version)) {
402                 wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
403                            "version %d", attr->selected_version);
404                 eap_sim_state(data, FAILURE);
405                 return;
406         }
407
408         data->counter = 0; /* reset re-auth counter since this is full auth */
409         data->reauth = NULL;
410
411         data->num_chal = eap_sim_db_get_gsm_triplets(
412                 sm->eap_sim_db_priv, identity, identity_len,
413                 EAP_SIM_MAX_CHAL,
414                 (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
415         if (data->num_chal == EAP_SIM_DB_PENDING) {
416                 wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
417                            "not yet available - pending request");
418                 sm->method_pending = METHOD_PENDING_WAIT;
419                 return;
420         }
421         if (data->num_chal < 2) {
422                 wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
423                            "authentication triplets for the peer");
424                 eap_sim_state(data, FAILURE);
425                 return;
426         }
427
428         identity_len = sm->identity_len;
429         while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
430                 wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
431                            "character from identity");
432                 identity_len--;
433         }
434         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
435                           sm->identity, identity_len);
436
437         memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
438         WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
439         eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt,
440                           attr->selected_version, ver_list, sizeof(ver_list),
441                           data->num_chal, (const u8 *) data->kc, data->mk);
442         eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
443                             data->emsk);
444
445         eap_sim_state(data, CHALLENGE);
446 }
447
448
449 static void eap_sim_process_challenge(struct eap_sm *sm,
450                                       struct eap_sim_data *data,
451                                       u8 *respData, size_t respDataLen,
452                                       struct eap_sim_attrs *attr)
453 {
454         const u8 *identity;
455         size_t identity_len;
456
457         if (attr->mac == NULL ||
458             eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
459                                (u8 *) data->sres,
460                                data->num_chal * EAP_SIM_SRES_LEN)) {
461                 wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
462                            "did not include valid AT_MAC");
463                 eap_sim_state(data, FAILURE);
464                 return;
465         }
466
467         wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
468                    "correct AT_MAC");
469         eap_sim_state(data, SUCCESS);
470
471         identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
472                                             sm->identity_len, &identity_len);
473         if (identity == NULL) {
474                 identity = sm->identity;
475                 identity_len = sm->identity_len;
476         }
477
478         if (data->next_pseudonym) {
479                 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
480                                          identity_len,
481                                          data->next_pseudonym);
482                 data->next_pseudonym = NULL;
483         }
484         if (data->next_reauth_id) {
485                 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
486                                       identity_len,
487                                       data->next_reauth_id, data->counter + 1,
488                                       data->mk);
489                 data->next_reauth_id = NULL;
490         }
491 }
492
493
494 static void eap_sim_process_reauth(struct eap_sm *sm,
495                                    struct eap_sim_data *data,
496                                    u8 *respData, size_t respDataLen,
497                                    struct eap_sim_attrs *attr)
498 {
499         struct eap_sim_attrs eattr;
500         u8 *decrypted = NULL;
501         const u8 *identity, *id2;
502         size_t identity_len, id2_len;
503
504         if (attr->mac == NULL ||
505             eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
506                                data->nonce_s, EAP_SIM_NONCE_S_LEN)) {
507                 wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
508                            "did not include valid AT_MAC");
509                 goto fail;
510         }
511
512         if (attr->encr_data == NULL || attr->iv == NULL) {
513                 wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
514                            "message did not include encrypted data");
515                 goto fail;
516         }
517
518         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
519                                        attr->encr_data_len, attr->iv, &eattr,
520                                        0);
521         if (decrypted == NULL) {
522                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
523                            "data from reauthentication message");
524                 goto fail;
525         }
526
527         if (eattr.counter != data->counter) {
528                 wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
529                            "used incorrect counter %u, expected %u",
530                            eattr.counter, data->counter);
531                 goto fail;
532         }
533         free(decrypted);
534         decrypted = NULL;
535
536         wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
537                    "the correct AT_MAC");
538         eap_sim_state(data, SUCCESS);
539
540         if (data->reauth) {
541                 identity = data->reauth->identity;
542                 identity_len = data->reauth->identity_len;
543         } else {
544                 identity = sm->identity;
545                 identity_len = sm->identity_len;
546         }
547
548         id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
549                                        identity_len, &id2_len);
550         if (id2) {
551                 identity = id2;
552                 identity_len = id2_len;
553         }
554
555         if (data->next_pseudonym) {
556                 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
557                                          identity_len, data->next_pseudonym);
558                 data->next_pseudonym = NULL;
559         }
560         if (data->next_reauth_id) {
561                 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
562                                       identity_len, data->next_reauth_id,
563                                       data->counter + 1, data->mk);
564                 data->next_reauth_id = NULL;
565         } else {
566                 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
567                 data->reauth = NULL;
568         }
569
570         return;
571
572 fail:
573         eap_sim_state(data, FAILURE);
574         eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
575         data->reauth = NULL;
576         free(decrypted);
577 }
578
579
580 static void eap_sim_process_client_error(struct eap_sm *sm,
581                                          struct eap_sim_data *data,
582                                          u8 *respData, size_t respDataLen,
583                                          struct eap_sim_attrs *attr)
584 {
585         wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
586                    attr->client_error_code);
587         eap_sim_state(data, FAILURE);
588 }
589
590
591 static void eap_sim_process(struct eap_sm *sm, void *priv,
592                             u8 *respData, size_t respDataLen)
593 {
594         struct eap_sim_data *data = priv;
595         struct eap_hdr *resp;
596         u8 *pos, subtype;
597         size_t len;
598         struct eap_sim_attrs attr;
599
600         resp = (struct eap_hdr *) respData;
601         pos = (u8 *) (resp + 1);
602         subtype = pos[1];
603         len = ntohs(resp->length);
604         pos += 4;
605
606         if (eap_sim_parse_attr(pos, respData + len, &attr, 0, 0)) {
607                 wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
608                 eap_sim_state(data, FAILURE);
609                 return;
610         }
611
612         if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
613                 eap_sim_process_client_error(sm, data, respData, len, &attr);
614                 return;
615         }
616
617         switch (data->state) {
618         case START:
619                 eap_sim_process_start(sm, data, respData, len, &attr);
620                 break;
621         case CHALLENGE:
622                 eap_sim_process_challenge(sm, data, respData, len, &attr);
623                 break;
624         case REAUTH:
625                 eap_sim_process_reauth(sm, data, respData, len, &attr);
626                 break;
627         default:
628                 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
629                            "process", data->state);
630                 break;
631         }
632 }
633
634
635 static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
636 {
637         struct eap_sim_data *data = priv;
638         return data->state == SUCCESS || data->state == FAILURE;
639 }
640
641
642 static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
643 {
644         struct eap_sim_data *data = priv;
645         u8 *key;
646
647         if (data->state != SUCCESS)
648                 return NULL;
649
650         key = malloc(EAP_SIM_KEYING_DATA_LEN);
651         if (key == NULL)
652                 return NULL;
653         memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
654         *len = EAP_SIM_KEYING_DATA_LEN;
655         return key;
656 }
657
658
659 static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
660 {
661         struct eap_sim_data *data = priv;
662         u8 *key;
663
664         if (data->state != SUCCESS)
665                 return NULL;
666
667         key = malloc(EAP_EMSK_LEN);
668         if (key == NULL)
669                 return NULL;
670         memcpy(key, data->emsk, EAP_EMSK_LEN);
671         *len = EAP_EMSK_LEN;
672         return key;
673 }
674
675
676 static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
677 {
678         struct eap_sim_data *data = priv;
679         return data->state == SUCCESS;
680 }
681
682
683 int eap_server_sim_register(void)
684 {
685         struct eap_method *eap;
686         int ret;
687
688         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
689                                       EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
690         if (eap == NULL)
691                 return -1;
692
693         eap->init = eap_sim_init;
694         eap->reset = eap_sim_reset;
695         eap->buildReq = eap_sim_buildReq;
696         eap->check = eap_sim_check;
697         eap->process = eap_sim_process;
698         eap->isDone = eap_sim_isDone;
699         eap->getKey = eap_sim_getKey;
700         eap->isSuccess = eap_sim_isSuccess;
701         eap->get_emsk = eap_sim_get_emsk;
702
703         ret = eap_server_method_register(eap);
704         if (ret)
705                 eap_server_method_free(eap);
706         return ret;
707 }