1 /*
2 * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
3 * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "crypto/sha256.h"
13 #include "crypto/crypto.h"
14 #include "crypto/random.h"
15 #include "eap_common/eap_sim_common.h"
16 #include "eap_server/eap_i.h"
17 #include "eap_server/eap_sim_db.h"
18
19
20 struct eap_aka_data {
21 u8 mk[EAP_SIM_MK_LEN];
22 u8 nonce_s[EAP_SIM_NONCE_S_LEN];
23 u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
24 u8 k_encr[EAP_SIM_K_ENCR_LEN];
25 u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
26 u8 msk[EAP_SIM_KEYING_DATA_LEN];
27 u8 emsk[EAP_EMSK_LEN];
28 u8 rand[EAP_AKA_RAND_LEN];
29 u8 autn[EAP_AKA_AUTN_LEN];
30 u8 ck[EAP_AKA_CK_LEN];
31 u8 ik[EAP_AKA_IK_LEN];
32 u8 res[EAP_AKA_RES_MAX_LEN];
33 size_t res_len;
34 enum {
35 IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
36 } state;
37 char *next_pseudonym;
38 char *next_reauth_id;
39 u16 counter;
40 struct eap_sim_reauth *reauth;
41 int auts_reported; /* whether the current AUTS has been reported to the
42 * eap_sim_db */
43 u16 notification;
44 int use_result_ind;
45
46 struct wpabuf *id_msgs;
47 int pending_id;
48 u8 eap_method;
49 u8 *network_name;
50 size_t network_name_len;
51 u16 kdf;
52 };
53
54
55 static void eap_aka_determine_identity(struct eap_sm *sm,
56 struct eap_aka_data *data,
57 int before_identity, int after_reauth);
58
59
eap_aka_state_txt(int state)60 static const char * eap_aka_state_txt(int state)
61 {
62 switch (state) {
63 case IDENTITY:
64 return "IDENTITY";
65 case CHALLENGE:
66 return "CHALLENGE";
67 case REAUTH:
68 return "REAUTH";
69 case SUCCESS:
70 return "SUCCESS";
71 case FAILURE:
72 return "FAILURE";
73 case NOTIFICATION:
74 return "NOTIFICATION";
75 default:
76 return "Unknown?!";
77 }
78 }
79
80
eap_aka_state(struct eap_aka_data * data,int state)81 static void eap_aka_state(struct eap_aka_data *data, int state)
82 {
83 wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
84 eap_aka_state_txt(data->state),
85 eap_aka_state_txt(state));
86 data->state = state;
87 }
88
89
eap_aka_init(struct eap_sm * sm)90 static void * eap_aka_init(struct eap_sm *sm)
91 {
92 struct eap_aka_data *data;
93
94 if (sm->eap_sim_db_priv == NULL) {
95 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
96 return NULL;
97 }
98
99 data = os_zalloc(sizeof(*data));
100 if (data == NULL)
101 return NULL;
102
103 data->eap_method = EAP_TYPE_AKA;
104
105 data->state = IDENTITY;
106 eap_aka_determine_identity(sm, data, 1, 0);
107 data->pending_id = -1;
108
109 return data;
110 }
111
112
113 #ifdef EAP_SERVER_AKA_PRIME
eap_aka_prime_init(struct eap_sm * sm)114 static void * eap_aka_prime_init(struct eap_sm *sm)
115 {
116 struct eap_aka_data *data;
117 /* TODO: make ANID configurable; see 3GPP TS 24.302 */
118 char *network_name = "WLAN";
119
120 if (sm->eap_sim_db_priv == NULL) {
121 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
122 return NULL;
123 }
124
125 data = os_zalloc(sizeof(*data));
126 if (data == NULL)
127 return NULL;
128
129 data->eap_method = EAP_TYPE_AKA_PRIME;
130 data->network_name = (u8 *) os_strdup(network_name);
131 if (data->network_name == NULL) {
132 os_free(data);
133 return NULL;
134 }
135
136 data->network_name_len = os_strlen(network_name);
137
138 data->state = IDENTITY;
139 eap_aka_determine_identity(sm, data, 1, 0);
140 data->pending_id = -1;
141
142 return data;
143 }
144 #endif /* EAP_SERVER_AKA_PRIME */
145
146
eap_aka_reset(struct eap_sm * sm,void * priv)147 static void eap_aka_reset(struct eap_sm *sm, void *priv)
148 {
149 struct eap_aka_data *data = priv;
150 os_free(data->next_pseudonym);
151 os_free(data->next_reauth_id);
152 wpabuf_free(data->id_msgs);
153 os_free(data->network_name);
154 os_free(data);
155 }
156
157
eap_aka_add_id_msg(struct eap_aka_data * data,const struct wpabuf * msg)158 static int eap_aka_add_id_msg(struct eap_aka_data *data,
159 const struct wpabuf *msg)
160 {
161 if (msg == NULL)
162 return -1;
163
164 if (data->id_msgs == NULL) {
165 data->id_msgs = wpabuf_dup(msg);
166 return data->id_msgs == NULL ? -1 : 0;
167 }
168
169 if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
170 return -1;
171 wpabuf_put_buf(data->id_msgs, msg);
172
173 return 0;
174 }
175
176
eap_aka_add_checkcode(struct eap_aka_data * data,struct eap_sim_msg * msg)177 static void eap_aka_add_checkcode(struct eap_aka_data *data,
178 struct eap_sim_msg *msg)
179 {
180 const u8 *addr;
181 size_t len;
182 u8 hash[SHA256_MAC_LEN];
183
184 wpa_printf(MSG_DEBUG, " AT_CHECKCODE");
185
186 if (data->id_msgs == NULL) {
187 /*
188 * No EAP-AKA/Identity packets were exchanged - send empty
189 * checkcode.
190 */
191 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
192 return;
193 }
194
195 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
196 addr = wpabuf_head(data->id_msgs);
197 len = wpabuf_len(data->id_msgs);
198 wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
199 if (data->eap_method == EAP_TYPE_AKA_PRIME)
200 sha256_vector(1, &addr, &len, hash);
201 else
202 sha1_vector(1, &addr, &len, hash);
203
204 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
205 data->eap_method == EAP_TYPE_AKA_PRIME ?
206 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
207 }
208
209
eap_aka_verify_checkcode(struct eap_aka_data * data,const u8 * checkcode,size_t checkcode_len)210 static int eap_aka_verify_checkcode(struct eap_aka_data *data,
211 const u8 *checkcode, size_t checkcode_len)
212 {
213 const u8 *addr;
214 size_t len;
215 u8 hash[SHA256_MAC_LEN];
216 size_t hash_len;
217
218 if (checkcode == NULL)
219 return -1;
220
221 if (data->id_msgs == NULL) {
222 if (checkcode_len != 0) {
223 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
224 "indicates that AKA/Identity messages were "
225 "used, but they were not");
226 return -1;
227 }
228 return 0;
229 }
230
231 hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
232 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
233
234 if (checkcode_len != hash_len) {
235 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
236 "that AKA/Identity message were not used, but they "
237 "were");
238 return -1;
239 }
240
241 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
242 addr = wpabuf_head(data->id_msgs);
243 len = wpabuf_len(data->id_msgs);
244 if (data->eap_method == EAP_TYPE_AKA_PRIME)
245 sha256_vector(1, &addr, &len, hash);
246 else
247 sha1_vector(1, &addr, &len, hash);
248
249 if (os_memcmp(hash, checkcode, hash_len) != 0) {
250 wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
251 return -1;
252 }
253
254 return 0;
255 }
256
257
eap_aka_build_identity(struct eap_sm * sm,struct eap_aka_data * data,u8 id)258 static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
259 struct eap_aka_data *data, u8 id)
260 {
261 struct eap_sim_msg *msg;
262 struct wpabuf *buf;
263
264 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
265 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
266 EAP_AKA_SUBTYPE_IDENTITY);
267 if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
268 sm->identity_len)) {
269 wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
270 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
271 } else {
272 /*
273 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
274 * ignored and the AKA/Identity is used to request the
275 * identity.
276 */
277 wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ");
278 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
279 }
280 buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
281 if (eap_aka_add_id_msg(data, buf) < 0) {
282 wpabuf_free(buf);
283 return NULL;
284 }
285 data->pending_id = id;
286 return buf;
287 }
288
289
eap_aka_build_encr(struct eap_sm * sm,struct eap_aka_data * data,struct eap_sim_msg * msg,u16 counter,const u8 * nonce_s)290 static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
291 struct eap_sim_msg *msg, u16 counter,
292 const u8 *nonce_s)
293 {
294 os_free(data->next_pseudonym);
295 data->next_pseudonym =
296 eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
297 os_free(data->next_reauth_id);
298 if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
299 data->next_reauth_id =
300 eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
301 } else {
302 wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
303 "count exceeded - force full authentication");
304 data->next_reauth_id = NULL;
305 }
306
307 if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
308 counter == 0 && nonce_s == NULL)
309 return 0;
310
311 wpa_printf(MSG_DEBUG, " AT_IV");
312 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
313 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
314
315 if (counter > 0) {
316 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter);
317 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
318 }
319
320 if (nonce_s) {
321 wpa_printf(MSG_DEBUG, " *AT_NONCE_S");
322 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
323 EAP_SIM_NONCE_S_LEN);
324 }
325
326 if (data->next_pseudonym) {
327 wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)",
328 data->next_pseudonym);
329 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
330 os_strlen(data->next_pseudonym),
331 (u8 *) data->next_pseudonym,
332 os_strlen(data->next_pseudonym));
333 }
334
335 if (data->next_reauth_id) {
336 wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)",
337 data->next_reauth_id);
338 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
339 os_strlen(data->next_reauth_id),
340 (u8 *) data->next_reauth_id,
341 os_strlen(data->next_reauth_id));
342 }
343
344 if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
345 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
346 "AT_ENCR_DATA");
347 return -1;
348 }
349
350 return 0;
351 }
352
353
eap_aka_build_challenge(struct eap_sm * sm,struct eap_aka_data * data,u8 id)354 static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
355 struct eap_aka_data *data,
356 u8 id)
357 {
358 struct eap_sim_msg *msg;
359
360 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
361 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
362 EAP_AKA_SUBTYPE_CHALLENGE);
363 wpa_printf(MSG_DEBUG, " AT_RAND");
364 eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
365 wpa_printf(MSG_DEBUG, " AT_AUTN");
366 eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
367 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
368 if (data->kdf) {
369 /* Add the selected KDF into the beginning */
370 wpa_printf(MSG_DEBUG, " AT_KDF");
371 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
372 NULL, 0);
373 }
374 wpa_printf(MSG_DEBUG, " AT_KDF");
375 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
376 NULL, 0);
377 wpa_printf(MSG_DEBUG, " AT_KDF_INPUT");
378 eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
379 data->network_name_len,
380 data->network_name, data->network_name_len);
381 }
382
383 if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
384 eap_sim_msg_free(msg);
385 return NULL;
386 }
387
388 eap_aka_add_checkcode(data, msg);
389
390 if (sm->eap_sim_aka_result_ind) {
391 wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
392 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
393 }
394
395 #ifdef EAP_SERVER_AKA_PRIME
396 if (data->eap_method == EAP_TYPE_AKA) {
397 u16 flags = 0;
398 int i;
399 int aka_prime_preferred = 0;
400
401 i = 0;
402 while (sm->user && i < EAP_MAX_METHODS &&
403 (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
404 sm->user->methods[i].method != EAP_TYPE_NONE)) {
405 if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
406 if (sm->user->methods[i].method ==
407 EAP_TYPE_AKA)
408 break;
409 if (sm->user->methods[i].method ==
410 EAP_TYPE_AKA_PRIME) {
411 aka_prime_preferred = 1;
412 break;
413 }
414 }
415 i++;
416 }
417
418 if (aka_prime_preferred)
419 flags |= EAP_AKA_BIDDING_FLAG_D;
420 eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
421 }
422 #endif /* EAP_SERVER_AKA_PRIME */
423
424 wpa_printf(MSG_DEBUG, " AT_MAC");
425 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
426 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
427 }
428
429
eap_aka_build_reauth(struct eap_sm * sm,struct eap_aka_data * data,u8 id)430 static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
431 struct eap_aka_data *data, u8 id)
432 {
433 struct eap_sim_msg *msg;
434
435 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
436
437 if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
438 return NULL;
439 wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
440 data->nonce_s, EAP_SIM_NONCE_S_LEN);
441
442 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
443 eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
444 sm->identity,
445 sm->identity_len,
446 data->nonce_s,
447 data->msk, data->emsk);
448 } else {
449 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
450 data->msk, data->emsk);
451 eap_sim_derive_keys_reauth(data->counter, sm->identity,
452 sm->identity_len, data->nonce_s,
453 data->mk, data->msk, data->emsk);
454 }
455
456 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
457 EAP_AKA_SUBTYPE_REAUTHENTICATION);
458
459 if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
460 eap_sim_msg_free(msg);
461 return NULL;
462 }
463
464 eap_aka_add_checkcode(data, msg);
465
466 if (sm->eap_sim_aka_result_ind) {
467 wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
468 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
469 }
470
471 wpa_printf(MSG_DEBUG, " AT_MAC");
472 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
473 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
474 }
475
476
eap_aka_build_notification(struct eap_sm * sm,struct eap_aka_data * data,u8 id)477 static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
478 struct eap_aka_data *data,
479 u8 id)
480 {
481 struct eap_sim_msg *msg;
482
483 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
484 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
485 EAP_AKA_SUBTYPE_NOTIFICATION);
486 wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification);
487 eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
488 NULL, 0);
489 if (data->use_result_ind) {
490 if (data->reauth) {
491 wpa_printf(MSG_DEBUG, " AT_IV");
492 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
493 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
494 EAP_SIM_AT_ENCR_DATA);
495 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)",
496 data->counter);
497 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
498 NULL, 0);
499
500 if (eap_sim_msg_add_encr_end(msg, data->k_encr,
501 EAP_SIM_AT_PADDING)) {
502 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
503 "encrypt AT_ENCR_DATA");
504 eap_sim_msg_free(msg);
505 return NULL;
506 }
507 }
508
509 wpa_printf(MSG_DEBUG, " AT_MAC");
510 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
511 }
512 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
513 }
514
515
eap_aka_buildReq(struct eap_sm * sm,void * priv,u8 id)516 static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
517 {
518 struct eap_aka_data *data = priv;
519
520 data->auts_reported = 0;
521 switch (data->state) {
522 case IDENTITY:
523 return eap_aka_build_identity(sm, data, id);
524 case CHALLENGE:
525 return eap_aka_build_challenge(sm, data, id);
526 case REAUTH:
527 return eap_aka_build_reauth(sm, data, id);
528 case NOTIFICATION:
529 return eap_aka_build_notification(sm, data, id);
530 default:
531 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
532 "buildReq", data->state);
533 break;
534 }
535 return NULL;
536 }
537
538
eap_aka_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)539 static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
540 struct wpabuf *respData)
541 {
542 struct eap_aka_data *data = priv;
543 const u8 *pos;
544 size_t len;
545
546 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
547 &len);
548 if (pos == NULL || len < 3) {
549 wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
550 return TRUE;
551 }
552
553 return FALSE;
554 }
555
556
eap_aka_subtype_ok(struct eap_aka_data * data,u8 subtype)557 static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
558 {
559 if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
560 subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
561 return FALSE;
562
563 switch (data->state) {
564 case IDENTITY:
565 if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
566 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
567 "subtype %d", subtype);
568 return TRUE;
569 }
570 break;
571 case CHALLENGE:
572 if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
573 subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
574 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
575 "subtype %d", subtype);
576 return TRUE;
577 }
578 break;
579 case REAUTH:
580 if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
581 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
582 "subtype %d", subtype);
583 return TRUE;
584 }
585 break;
586 case NOTIFICATION:
587 if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
588 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
589 "subtype %d", subtype);
590 return TRUE;
591 }
592 break;
593 default:
594 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
595 "processing a response", data->state);
596 return TRUE;
597 }
598
599 return FALSE;
600 }
601
602
eap_aka_determine_identity(struct eap_sm * sm,struct eap_aka_data * data,int before_identity,int after_reauth)603 static void eap_aka_determine_identity(struct eap_sm *sm,
604 struct eap_aka_data *data,
605 int before_identity, int after_reauth)
606 {
607 const u8 *identity;
608 size_t identity_len;
609 int res;
610
611 identity = NULL;
612 identity_len = 0;
613
614 if (after_reauth && data->reauth) {
615 identity = data->reauth->identity;
616 identity_len = data->reauth->identity_len;
617 } else if (sm->identity && sm->identity_len > 0 &&
618 sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
619 identity = sm->identity;
620 identity_len = sm->identity_len;
621 } else {
622 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
623 sm->identity,
624 sm->identity_len,
625 &identity_len);
626 if (identity == NULL) {
627 data->reauth = eap_sim_db_get_reauth_entry(
628 sm->eap_sim_db_priv, sm->identity,
629 sm->identity_len);
630 if (data->reauth &&
631 data->reauth->aka_prime !=
632 (data->eap_method == EAP_TYPE_AKA_PRIME)) {
633 wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
634 "was for different AKA version");
635 data->reauth = NULL;
636 }
637 if (data->reauth) {
638 wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
639 "re-authentication");
640 identity = data->reauth->identity;
641 identity_len = data->reauth->identity_len;
642 data->counter = data->reauth->counter;
643 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
644 os_memcpy(data->k_encr,
645 data->reauth->k_encr,
646 EAP_SIM_K_ENCR_LEN);
647 os_memcpy(data->k_aut,
648 data->reauth->k_aut,
649 EAP_AKA_PRIME_K_AUT_LEN);
650 os_memcpy(data->k_re,
651 data->reauth->k_re,
652 EAP_AKA_PRIME_K_RE_LEN);
653 } else {
654 os_memcpy(data->mk, data->reauth->mk,
655 EAP_SIM_MK_LEN);
656 }
657 }
658 }
659 }
660
661 if (identity == NULL ||
662 eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
663 sm->identity_len) < 0) {
664 if (before_identity) {
665 wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
666 "not known - send AKA-Identity request");
667 eap_aka_state(data, IDENTITY);
668 return;
669 } else {
670 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
671 "permanent user name is known; try to use "
672 "it");
673 /* eap_sim_db_get_aka_auth() will report failure, if
674 * this identity is not known. */
675 }
676 }
677
678 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
679 identity, identity_len);
680
681 if (!after_reauth && data->reauth) {
682 eap_aka_state(data, REAUTH);
683 return;
684 }
685
686 res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
687 identity_len, data->rand, data->autn,
688 data->ik, data->ck, data->res,
689 &data->res_len, sm);
690 if (res == EAP_SIM_DB_PENDING) {
691 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
692 "not yet available - pending request");
693 sm->method_pending = METHOD_PENDING_WAIT;
694 return;
695 }
696
697 #ifdef EAP_SERVER_AKA_PRIME
698 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
699 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
700 * needed 6-octet SQN ^AK for CK',IK' derivation */
701 eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
702 data->autn,
703 data->network_name,
704 data->network_name_len);
705 }
706 #endif /* EAP_SERVER_AKA_PRIME */
707
708 data->reauth = NULL;
709 data->counter = 0; /* reset re-auth counter since this is full auth */
710
711 if (res != 0) {
712 wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
713 "authentication data for the peer");
714 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
715 eap_aka_state(data, NOTIFICATION);
716 return;
717 }
718 if (sm->method_pending == METHOD_PENDING_WAIT) {
719 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
720 "available - abort pending wait");
721 sm->method_pending = METHOD_PENDING_NONE;
722 }
723
724 identity_len = sm->identity_len;
725 while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
726 wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
727 "character from identity");
728 identity_len--;
729 }
730 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
731 sm->identity, identity_len);
732
733 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
734 eap_aka_prime_derive_keys(identity, identity_len, data->ik,
735 data->ck, data->k_encr, data->k_aut,
736 data->k_re, data->msk, data->emsk);
737 } else {
738 eap_aka_derive_mk(sm->identity, identity_len, data->ik,
739 data->ck, data->mk);
740 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
741 data->msk, data->emsk);
742 }
743
744 eap_aka_state(data, CHALLENGE);
745 }
746
747
eap_aka_process_identity(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)748 static void eap_aka_process_identity(struct eap_sm *sm,
749 struct eap_aka_data *data,
750 struct wpabuf *respData,
751 struct eap_sim_attrs *attr)
752 {
753 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
754
755 if (attr->mac || attr->iv || attr->encr_data) {
756 wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
757 "received in EAP-Response/AKA-Identity");
758 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
759 eap_aka_state(data, NOTIFICATION);
760 return;
761 }
762
763 if (attr->identity) {
764 os_free(sm->identity);
765 sm->identity = os_malloc(attr->identity_len);
766 if (sm->identity) {
767 os_memcpy(sm->identity, attr->identity,
768 attr->identity_len);
769 sm->identity_len = attr->identity_len;
770 }
771 }
772
773 eap_aka_determine_identity(sm, data, 0, 0);
774 if (eap_get_id(respData) == data->pending_id) {
775 data->pending_id = -1;
776 eap_aka_add_id_msg(data, respData);
777 }
778 }
779
780
eap_aka_verify_mac(struct eap_aka_data * data,const struct wpabuf * req,const u8 * mac,const u8 * extra,size_t extra_len)781 static int eap_aka_verify_mac(struct eap_aka_data *data,
782 const struct wpabuf *req,
783 const u8 *mac, const u8 *extra,
784 size_t extra_len)
785 {
786 if (data->eap_method == EAP_TYPE_AKA_PRIME)
787 return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
788 extra_len);
789 return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
790 }
791
792
eap_aka_process_challenge(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)793 static void eap_aka_process_challenge(struct eap_sm *sm,
794 struct eap_aka_data *data,
795 struct wpabuf *respData,
796 struct eap_sim_attrs *attr)
797 {
798 const u8 *identity;
799 size_t identity_len;
800
801 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
802
803 #ifdef EAP_SERVER_AKA_PRIME
804 #if 0
805 /* KDF negotiation; to be enabled only after more than one KDF is
806 * supported */
807 if (data->eap_method == EAP_TYPE_AKA_PRIME &&
808 attr->kdf_count == 1 && attr->mac == NULL) {
809 if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
810 wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
811 "unknown KDF");
812 data->notification =
813 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
814 eap_aka_state(data, NOTIFICATION);
815 return;
816 }
817
818 data->kdf = attr->kdf[0];
819
820 /* Allow negotiation to continue with the selected KDF by
821 * sending another Challenge message */
822 wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
823 return;
824 }
825 #endif
826 #endif /* EAP_SERVER_AKA_PRIME */
827
828 if (attr->checkcode &&
829 eap_aka_verify_checkcode(data, attr->checkcode,
830 attr->checkcode_len)) {
831 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
832 "message");
833 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
834 eap_aka_state(data, NOTIFICATION);
835 return;
836 }
837 if (attr->mac == NULL ||
838 eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
839 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
840 "did not include valid AT_MAC");
841 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
842 eap_aka_state(data, NOTIFICATION);
843 return;
844 }
845
846 /*
847 * AT_RES is padded, so verify that there is enough room for RES and
848 * that the RES length in bits matches with the expected RES.
849 */
850 if (attr->res == NULL || attr->res_len < data->res_len ||
851 attr->res_len_bits != data->res_len * 8 ||
852 os_memcmp(attr->res, data->res, data->res_len) != 0) {
853 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
854 "include valid AT_RES (attr len=%lu, res len=%lu "
855 "bits, expected %lu bits)",
856 (unsigned long) attr->res_len,
857 (unsigned long) attr->res_len_bits,
858 (unsigned long) data->res_len * 8);
859 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
860 eap_aka_state(data, NOTIFICATION);
861 return;
862 }
863
864 wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
865 "correct AT_MAC");
866 if (sm->eap_sim_aka_result_ind && attr->result_ind) {
867 data->use_result_ind = 1;
868 data->notification = EAP_SIM_SUCCESS;
869 eap_aka_state(data, NOTIFICATION);
870 } else
871 eap_aka_state(data, SUCCESS);
872
873 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
874 sm->identity_len, &identity_len);
875 if (identity == NULL) {
876 identity = sm->identity;
877 identity_len = sm->identity_len;
878 }
879
880 if (data->next_pseudonym) {
881 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
882 identity_len,
883 data->next_pseudonym);
884 data->next_pseudonym = NULL;
885 }
886 if (data->next_reauth_id) {
887 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
888 #ifdef EAP_SERVER_AKA_PRIME
889 eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
890 identity,
891 identity_len,
892 data->next_reauth_id,
893 data->counter + 1,
894 data->k_encr, data->k_aut,
895 data->k_re);
896 #endif /* EAP_SERVER_AKA_PRIME */
897 } else {
898 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
899 identity_len,
900 data->next_reauth_id,
901 data->counter + 1,
902 data->mk);
903 }
904 data->next_reauth_id = NULL;
905 }
906 }
907
908
eap_aka_process_sync_failure(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)909 static void eap_aka_process_sync_failure(struct eap_sm *sm,
910 struct eap_aka_data *data,
911 struct wpabuf *respData,
912 struct eap_sim_attrs *attr)
913 {
914 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
915
916 if (attr->auts == NULL) {
917 wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
918 "message did not include valid AT_AUTS");
919 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
920 eap_aka_state(data, NOTIFICATION);
921 return;
922 }
923
924 /* Avoid re-reporting AUTS when processing pending EAP packet by
925 * maintaining a local flag stating whether this AUTS has already been
926 * reported. */
927 if (!data->auts_reported &&
928 eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
929 sm->identity_len, attr->auts,
930 data->rand)) {
931 wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
932 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
933 eap_aka_state(data, NOTIFICATION);
934 return;
935 }
936 data->auts_reported = 1;
937
938 /* Try again after resynchronization */
939 eap_aka_determine_identity(sm, data, 0, 0);
940 }
941
942
eap_aka_process_reauth(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)943 static void eap_aka_process_reauth(struct eap_sm *sm,
944 struct eap_aka_data *data,
945 struct wpabuf *respData,
946 struct eap_sim_attrs *attr)
947 {
948 struct eap_sim_attrs eattr;
949 u8 *decrypted = NULL;
950 const u8 *identity, *id2;
951 size_t identity_len, id2_len;
952
953 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
954
955 if (attr->mac == NULL ||
956 eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
957 EAP_SIM_NONCE_S_LEN)) {
958 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
959 "did not include valid AT_MAC");
960 goto fail;
961 }
962
963 if (attr->encr_data == NULL || attr->iv == NULL) {
964 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
965 "message did not include encrypted data");
966 goto fail;
967 }
968
969 decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
970 attr->encr_data_len, attr->iv, &eattr,
971 0);
972 if (decrypted == NULL) {
973 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
974 "data from reauthentication message");
975 goto fail;
976 }
977
978 if (eattr.counter != data->counter) {
979 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
980 "used incorrect counter %u, expected %u",
981 eattr.counter, data->counter);
982 goto fail;
983 }
984 os_free(decrypted);
985 decrypted = NULL;
986
987 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
988 "the correct AT_MAC");
989
990 if (eattr.counter_too_small) {
991 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
992 "included AT_COUNTER_TOO_SMALL - starting full "
993 "authentication");
994 eap_aka_determine_identity(sm, data, 0, 1);
995 return;
996 }
997
998 if (sm->eap_sim_aka_result_ind && attr->result_ind) {
999 data->use_result_ind = 1;
1000 data->notification = EAP_SIM_SUCCESS;
1001 eap_aka_state(data, NOTIFICATION);
1002 } else
1003 eap_aka_state(data, SUCCESS);
1004
1005 if (data->reauth) {
1006 identity = data->reauth->identity;
1007 identity_len = data->reauth->identity_len;
1008 } else {
1009 identity = sm->identity;
1010 identity_len = sm->identity_len;
1011 }
1012
1013 id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
1014 identity_len, &id2_len);
1015 if (id2) {
1016 identity = id2;
1017 identity_len = id2_len;
1018 }
1019
1020 if (data->next_pseudonym) {
1021 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
1022 identity_len, data->next_pseudonym);
1023 data->next_pseudonym = NULL;
1024 }
1025 if (data->next_reauth_id) {
1026 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
1027 #ifdef EAP_SERVER_AKA_PRIME
1028 eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
1029 identity,
1030 identity_len,
1031 data->next_reauth_id,
1032 data->counter + 1,
1033 data->k_encr, data->k_aut,
1034 data->k_re);
1035 #endif /* EAP_SERVER_AKA_PRIME */
1036 } else {
1037 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
1038 identity_len,
1039 data->next_reauth_id,
1040 data->counter + 1,
1041 data->mk);
1042 }
1043 data->next_reauth_id = NULL;
1044 } else {
1045 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
1046 data->reauth = NULL;
1047 }
1048
1049 return;
1050
1051 fail:
1052 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1053 eap_aka_state(data, NOTIFICATION);
1054 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
1055 data->reauth = NULL;
1056 os_free(decrypted);
1057 }
1058
1059
eap_aka_process_client_error(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)1060 static void eap_aka_process_client_error(struct eap_sm *sm,
1061 struct eap_aka_data *data,
1062 struct wpabuf *respData,
1063 struct eap_sim_attrs *attr)
1064 {
1065 wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
1066 attr->client_error_code);
1067 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
1068 eap_aka_state(data, SUCCESS);
1069 else
1070 eap_aka_state(data, FAILURE);
1071 }
1072
1073
eap_aka_process_authentication_reject(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)1074 static void eap_aka_process_authentication_reject(
1075 struct eap_sm *sm, struct eap_aka_data *data,
1076 struct wpabuf *respData, struct eap_sim_attrs *attr)
1077 {
1078 wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
1079 eap_aka_state(data, FAILURE);
1080 }
1081
1082
eap_aka_process_notification(struct eap_sm * sm,struct eap_aka_data * data,struct wpabuf * respData,struct eap_sim_attrs * attr)1083 static void eap_aka_process_notification(struct eap_sm *sm,
1084 struct eap_aka_data *data,
1085 struct wpabuf *respData,
1086 struct eap_sim_attrs *attr)
1087 {
1088 wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
1089 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
1090 eap_aka_state(data, SUCCESS);
1091 else
1092 eap_aka_state(data, FAILURE);
1093 }
1094
1095
eap_aka_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)1096 static void eap_aka_process(struct eap_sm *sm, void *priv,
1097 struct wpabuf *respData)
1098 {
1099 struct eap_aka_data *data = priv;
1100 const u8 *pos, *end;
1101 u8 subtype;
1102 size_t len;
1103 struct eap_sim_attrs attr;
1104
1105 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
1106 &len);
1107 if (pos == NULL || len < 3)
1108 return;
1109
1110 end = pos + len;
1111 subtype = *pos;
1112 pos += 3;
1113
1114 if (eap_aka_subtype_ok(data, subtype)) {
1115 wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
1116 "EAP-AKA Subtype in EAP Response");
1117 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1118 eap_aka_state(data, NOTIFICATION);
1119 return;
1120 }
1121
1122 if (eap_sim_parse_attr(pos, end, &attr,
1123 data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
1124 0)) {
1125 wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
1126 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1127 eap_aka_state(data, NOTIFICATION);
1128 return;
1129 }
1130
1131 if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
1132 eap_aka_process_client_error(sm, data, respData, &attr);
1133 return;
1134 }
1135
1136 if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
1137 eap_aka_process_authentication_reject(sm, data, respData,
1138 &attr);
1139 return;
1140 }
1141
1142 switch (data->state) {
1143 case IDENTITY:
1144 eap_aka_process_identity(sm, data, respData, &attr);
1145 break;
1146 case CHALLENGE:
1147 if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
1148 eap_aka_process_sync_failure(sm, data, respData,
1149 &attr);
1150 } else {
1151 eap_aka_process_challenge(sm, data, respData, &attr);
1152 }
1153 break;
1154 case REAUTH:
1155 eap_aka_process_reauth(sm, data, respData, &attr);
1156 break;
1157 case NOTIFICATION:
1158 eap_aka_process_notification(sm, data, respData, &attr);
1159 break;
1160 default:
1161 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
1162 "process", data->state);
1163 break;
1164 }
1165 }
1166
1167
eap_aka_isDone(struct eap_sm * sm,void * priv)1168 static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
1169 {
1170 struct eap_aka_data *data = priv;
1171 return data->state == SUCCESS || data->state == FAILURE;
1172 }
1173
1174
eap_aka_getKey(struct eap_sm * sm,void * priv,size_t * len)1175 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
1176 {
1177 struct eap_aka_data *data = priv;
1178 u8 *key;
1179
1180 if (data->state != SUCCESS)
1181 return NULL;
1182
1183 key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
1184 if (key == NULL)
1185 return NULL;
1186 os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
1187 *len = EAP_SIM_KEYING_DATA_LEN;
1188 return key;
1189 }
1190
1191
eap_aka_get_emsk(struct eap_sm * sm,void * priv,size_t * len)1192 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1193 {
1194 struct eap_aka_data *data = priv;
1195 u8 *key;
1196
1197 if (data->state != SUCCESS)
1198 return NULL;
1199
1200 key = os_malloc(EAP_EMSK_LEN);
1201 if (key == NULL)
1202 return NULL;
1203 os_memcpy(key, data->emsk, EAP_EMSK_LEN);
1204 *len = EAP_EMSK_LEN;
1205 return key;
1206 }
1207
1208
eap_aka_isSuccess(struct eap_sm * sm,void * priv)1209 static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
1210 {
1211 struct eap_aka_data *data = priv;
1212 return data->state == SUCCESS;
1213 }
1214
1215
eap_server_aka_register(void)1216 int eap_server_aka_register(void)
1217 {
1218 struct eap_method *eap;
1219 int ret;
1220
1221 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1222 EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
1223 if (eap == NULL)
1224 return -1;
1225
1226 eap->init = eap_aka_init;
1227 eap->reset = eap_aka_reset;
1228 eap->buildReq = eap_aka_buildReq;
1229 eap->check = eap_aka_check;
1230 eap->process = eap_aka_process;
1231 eap->isDone = eap_aka_isDone;
1232 eap->getKey = eap_aka_getKey;
1233 eap->isSuccess = eap_aka_isSuccess;
1234 eap->get_emsk = eap_aka_get_emsk;
1235
1236 ret = eap_server_method_register(eap);
1237 if (ret)
1238 eap_server_method_free(eap);
1239 return ret;
1240 }
1241
1242
1243 #ifdef EAP_SERVER_AKA_PRIME
eap_server_aka_prime_register(void)1244 int eap_server_aka_prime_register(void)
1245 {
1246 struct eap_method *eap;
1247 int ret;
1248
1249 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1250 EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
1251 "AKA'");
1252 if (eap == NULL)
1253 return -1;
1254
1255 eap->init = eap_aka_prime_init;
1256 eap->reset = eap_aka_reset;
1257 eap->buildReq = eap_aka_buildReq;
1258 eap->check = eap_aka_check;
1259 eap->process = eap_aka_process;
1260 eap->isDone = eap_aka_isDone;
1261 eap->getKey = eap_aka_getKey;
1262 eap->isSuccess = eap_aka_isSuccess;
1263 eap->get_emsk = eap_aka_get_emsk;
1264
1265 ret = eap_server_method_register(eap);
1266 if (ret)
1267 eap_server_method_free(eap);
1268
1269 return ret;
1270 }
1271 #endif /* EAP_SERVER_AKA_PRIME */
1272