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