Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / wpa / src / eap_server / eap_aka.c
blob2d0696571b8e1ee8718d432190e4ada52bcad415
1 /*
2 * hostapd / EAP-AKA (RFC 4187)
3 * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #include "common.h"
18 #include "eap_server/eap_i.h"
19 #include "eap_common/eap_sim_common.h"
20 #include "eap_server/eap_sim_db.h"
21 #include "sha1.h"
22 #include "crypto.h"
25 struct eap_aka_data {
26 u8 mk[EAP_SIM_MK_LEN];
27 u8 nonce_s[EAP_SIM_NONCE_S_LEN];
28 u8 k_aut[EAP_SIM_K_AUT_LEN];
29 u8 k_encr[EAP_SIM_K_ENCR_LEN];
30 u8 msk[EAP_SIM_KEYING_DATA_LEN];
31 u8 emsk[EAP_EMSK_LEN];
32 u8 rand[EAP_AKA_RAND_LEN];
33 u8 autn[EAP_AKA_AUTN_LEN];
34 u8 ck[EAP_AKA_CK_LEN];
35 u8 ik[EAP_AKA_IK_LEN];
36 u8 res[EAP_AKA_RES_MAX_LEN];
37 size_t res_len;
38 enum {
39 IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
40 } state;
41 char *next_pseudonym;
42 char *next_reauth_id;
43 u16 counter;
44 struct eap_sim_reauth *reauth;
45 int auts_reported; /* whether the current AUTS has been reported to the
46 * eap_sim_db */
47 u16 notification;
48 int use_result_ind;
50 struct wpabuf *id_msgs;
51 int pending_id;
55 static void eap_aka_determine_identity(struct eap_sm *sm,
56 struct eap_aka_data *data,
57 int before_identity, int after_reauth);
60 static const char * eap_aka_state_txt(int state)
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?!";
81 static void eap_aka_state(struct eap_aka_data *data, int state)
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;
90 static void * eap_aka_init(struct eap_sm *sm)
92 struct eap_aka_data *data;
94 if (sm->eap_sim_db_priv == NULL) {
95 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
96 return NULL;
99 data = os_zalloc(sizeof(*data));
100 if (data == NULL)
101 return NULL;
102 data->state = IDENTITY;
103 eap_aka_determine_identity(sm, data, 1, 0);
104 data->pending_id = -1;
106 return data;
110 static void eap_aka_reset(struct eap_sm *sm, void *priv)
112 struct eap_aka_data *data = priv;
113 os_free(data->next_pseudonym);
114 os_free(data->next_reauth_id);
115 wpabuf_free(data->id_msgs);
116 os_free(data);
120 static int eap_aka_add_id_msg(struct eap_aka_data *data,
121 const struct wpabuf *msg)
123 if (msg == NULL)
124 return -1;
126 if (data->id_msgs == NULL) {
127 data->id_msgs = wpabuf_dup(msg);
128 return data->id_msgs == NULL ? -1 : 0;
131 if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
132 return -1;
133 wpabuf_put_buf(data->id_msgs, msg);
135 return 0;
139 static void eap_aka_add_checkcode(struct eap_aka_data *data,
140 struct eap_sim_msg *msg)
142 const u8 *addr;
143 size_t len;
144 u8 hash[SHA1_MAC_LEN];
146 wpa_printf(MSG_DEBUG, " AT_CHECKCODE");
148 if (data->id_msgs == NULL) {
150 * No EAP-AKA/Identity packets were exchanged - send empty
151 * checkcode.
153 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
154 return;
157 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
158 addr = wpabuf_head(data->id_msgs);
159 len = wpabuf_len(data->id_msgs);
160 wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
161 sha1_vector(1, &addr, &len, hash);
163 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
164 EAP_AKA_CHECKCODE_LEN);
168 static int eap_aka_verify_checkcode(struct eap_aka_data *data,
169 const u8 *checkcode, size_t checkcode_len)
171 const u8 *addr;
172 size_t len;
173 u8 hash[SHA1_MAC_LEN];
175 if (checkcode == NULL)
176 return -1;
178 if (data->id_msgs == NULL) {
179 if (checkcode_len != 0) {
180 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
181 "indicates that AKA/Identity messages were "
182 "used, but they were not");
183 return -1;
185 return 0;
188 if (checkcode_len != EAP_AKA_CHECKCODE_LEN) {
189 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
190 "that AKA/Identity message were not used, but they "
191 "were");
192 return -1;
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 sha1_vector(1, &addr, &len, hash);
200 if (os_memcmp(hash, checkcode, EAP_AKA_CHECKCODE_LEN) != 0) {
201 wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
202 return -1;
205 return 0;
209 static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
210 struct eap_aka_data *data, u8 id)
212 struct eap_sim_msg *msg;
213 struct wpabuf *buf;
215 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
216 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
217 EAP_AKA_SUBTYPE_IDENTITY);
218 if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
219 sm->identity_len)) {
220 wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
221 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
222 } else {
224 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
225 * ignored and the AKA/Identity is used to request the
226 * identity.
228 wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ");
229 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
231 buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
232 if (eap_aka_add_id_msg(data, buf) < 0) {
233 wpabuf_free(buf);
234 return NULL;
236 data->pending_id = id;
237 return buf;
241 static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
242 struct eap_sim_msg *msg, u16 counter,
243 const u8 *nonce_s)
245 os_free(data->next_pseudonym);
246 data->next_pseudonym =
247 eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
248 os_free(data->next_reauth_id);
249 if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
250 data->next_reauth_id =
251 eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
252 } else {
253 wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
254 "count exceeded - force full authentication");
255 data->next_reauth_id = NULL;
258 if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
259 counter == 0 && nonce_s == NULL)
260 return 0;
262 wpa_printf(MSG_DEBUG, " AT_IV");
263 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
264 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
266 if (counter > 0) {
267 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter);
268 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
271 if (nonce_s) {
272 wpa_printf(MSG_DEBUG, " *AT_NONCE_S");
273 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
274 EAP_SIM_NONCE_S_LEN);
277 if (data->next_pseudonym) {
278 wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)",
279 data->next_pseudonym);
280 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
281 os_strlen(data->next_pseudonym),
282 (u8 *) data->next_pseudonym,
283 os_strlen(data->next_pseudonym));
286 if (data->next_reauth_id) {
287 wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)",
288 data->next_reauth_id);
289 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
290 os_strlen(data->next_reauth_id),
291 (u8 *) data->next_reauth_id,
292 os_strlen(data->next_reauth_id));
295 if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
296 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
297 "AT_ENCR_DATA");
298 return -1;
301 return 0;
305 static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
306 struct eap_aka_data *data,
307 u8 id)
309 struct eap_sim_msg *msg;
311 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
312 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
313 EAP_AKA_SUBTYPE_CHALLENGE);
314 wpa_printf(MSG_DEBUG, " AT_RAND");
315 eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
316 eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
318 if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
319 eap_sim_msg_free(msg);
320 return NULL;
323 eap_aka_add_checkcode(data, msg);
325 if (sm->eap_sim_aka_result_ind) {
326 wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
327 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
330 wpa_printf(MSG_DEBUG, " AT_MAC");
331 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
332 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
336 static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
337 struct eap_aka_data *data, u8 id)
339 struct eap_sim_msg *msg;
341 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
343 if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN))
344 return NULL;
345 wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
346 data->nonce_s, EAP_SIM_NONCE_S_LEN);
348 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
349 data->emsk);
350 eap_sim_derive_keys_reauth(data->counter, sm->identity,
351 sm->identity_len, data->nonce_s, data->mk,
352 data->msk, data->emsk);
354 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
355 EAP_AKA_SUBTYPE_REAUTHENTICATION);
357 if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
358 eap_sim_msg_free(msg);
359 return NULL;
362 eap_aka_add_checkcode(data, msg);
364 if (sm->eap_sim_aka_result_ind) {
365 wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
366 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
369 wpa_printf(MSG_DEBUG, " AT_MAC");
370 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
371 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
375 static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
376 struct eap_aka_data *data,
377 u8 id)
379 struct eap_sim_msg *msg;
381 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
382 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
383 EAP_AKA_SUBTYPE_NOTIFICATION);
384 wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification);
385 eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
386 NULL, 0);
387 if (data->use_result_ind) {
388 if (data->reauth) {
389 wpa_printf(MSG_DEBUG, " AT_IV");
390 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
391 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
392 EAP_SIM_AT_ENCR_DATA);
393 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)",
394 data->counter);
395 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
396 NULL, 0);
398 if (eap_sim_msg_add_encr_end(msg, data->k_encr,
399 EAP_SIM_AT_PADDING)) {
400 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
401 "encrypt AT_ENCR_DATA");
402 eap_sim_msg_free(msg);
403 return NULL;
407 wpa_printf(MSG_DEBUG, " AT_MAC");
408 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
410 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
414 static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
416 struct eap_aka_data *data = priv;
418 data->auts_reported = 0;
419 switch (data->state) {
420 case IDENTITY:
421 return eap_aka_build_identity(sm, data, id);
422 case CHALLENGE:
423 return eap_aka_build_challenge(sm, data, id);
424 case REAUTH:
425 return eap_aka_build_reauth(sm, data, id);
426 case NOTIFICATION:
427 return eap_aka_build_notification(sm, data, id);
428 default:
429 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
430 "buildReq", data->state);
431 break;
433 return NULL;
437 static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
438 struct wpabuf *respData)
440 const u8 *pos;
441 size_t len;
443 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_AKA, respData, &len);
444 if (pos == NULL || len < 3) {
445 wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
446 return TRUE;
449 return FALSE;
453 static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
455 if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
456 subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
457 return FALSE;
459 switch (data->state) {
460 case IDENTITY:
461 if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
462 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
463 "subtype %d", subtype);
464 return TRUE;
466 break;
467 case CHALLENGE:
468 if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
469 subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
470 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
471 "subtype %d", subtype);
472 return TRUE;
474 break;
475 case REAUTH:
476 if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
477 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
478 "subtype %d", subtype);
479 return TRUE;
481 break;
482 case NOTIFICATION:
483 if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
484 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
485 "subtype %d", subtype);
486 return TRUE;
488 break;
489 default:
490 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
491 "processing a response", data->state);
492 return TRUE;
495 return FALSE;
499 static void eap_aka_determine_identity(struct eap_sm *sm,
500 struct eap_aka_data *data,
501 int before_identity, int after_reauth)
503 const u8 *identity;
504 size_t identity_len;
505 int res;
507 identity = NULL;
508 identity_len = 0;
510 if (after_reauth && data->reauth) {
511 identity = data->reauth->identity;
512 identity_len = data->reauth->identity_len;
513 } else if (sm->identity && sm->identity_len > 0 &&
514 sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
515 identity = sm->identity;
516 identity_len = sm->identity_len;
517 } else {
518 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
519 sm->identity,
520 sm->identity_len,
521 &identity_len);
522 if (identity == NULL) {
523 data->reauth = eap_sim_db_get_reauth_entry(
524 sm->eap_sim_db_priv, sm->identity,
525 sm->identity_len);
526 if (data->reauth) {
527 wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
528 "re-authentication");
529 identity = data->reauth->identity;
530 identity_len = data->reauth->identity_len;
531 data->counter = data->reauth->counter;
532 os_memcpy(data->mk, data->reauth->mk,
533 EAP_SIM_MK_LEN);
538 if (identity == NULL ||
539 eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
540 sm->identity_len) < 0) {
541 if (before_identity) {
542 wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
543 "not known - send AKA-Identity request");
544 eap_aka_state(data, IDENTITY);
545 return;
546 } else {
547 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
548 "permanent user name is known; try to use "
549 "it");
550 /* eap_sim_db_get_aka_auth() will report failure, if
551 * this identity is not known. */
555 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
556 identity, identity_len);
558 if (!after_reauth && data->reauth) {
559 eap_aka_state(data, REAUTH);
560 return;
563 res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
564 identity_len, data->rand, data->autn,
565 data->ik, data->ck, data->res,
566 &data->res_len, sm);
567 if (res == EAP_SIM_DB_PENDING) {
568 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
569 "not yet available - pending request");
570 sm->method_pending = METHOD_PENDING_WAIT;
571 return;
574 data->reauth = NULL;
575 data->counter = 0; /* reset re-auth counter since this is full auth */
577 if (res != 0) {
578 wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
579 "authentication data for the peer");
580 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
581 eap_aka_state(data, NOTIFICATION);
582 return;
584 if (sm->method_pending == METHOD_PENDING_WAIT) {
585 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
586 "available - abort pending wait");
587 sm->method_pending = METHOD_PENDING_NONE;
590 identity_len = sm->identity_len;
591 while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
592 wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
593 "character from identity");
594 identity_len--;
596 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
597 sm->identity, identity_len);
599 eap_aka_derive_mk(sm->identity, identity_len, data->ik, data->ck,
600 data->mk);
601 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
602 data->emsk);
604 eap_aka_state(data, CHALLENGE);
608 static void eap_aka_process_identity(struct eap_sm *sm,
609 struct eap_aka_data *data,
610 struct wpabuf *respData,
611 struct eap_sim_attrs *attr)
613 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
615 if (attr->mac || attr->iv || attr->encr_data) {
616 wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
617 "received in EAP-Response/AKA-Identity");
618 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
619 eap_aka_state(data, NOTIFICATION);
620 return;
623 if (attr->identity) {
624 os_free(sm->identity);
625 sm->identity = os_malloc(attr->identity_len);
626 if (sm->identity) {
627 os_memcpy(sm->identity, attr->identity,
628 attr->identity_len);
629 sm->identity_len = attr->identity_len;
633 eap_aka_determine_identity(sm, data, 0, 0);
634 if (eap_get_id(respData) == data->pending_id) {
635 data->pending_id = -1;
636 eap_aka_add_id_msg(data, respData);
641 static void eap_aka_process_challenge(struct eap_sm *sm,
642 struct eap_aka_data *data,
643 struct wpabuf *respData,
644 struct eap_sim_attrs *attr)
646 const u8 *identity;
647 size_t identity_len;
649 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
651 if (attr->checkcode &&
652 eap_aka_verify_checkcode(data, attr->checkcode,
653 attr->checkcode_len)) {
654 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
655 "message");
656 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
657 eap_aka_state(data, NOTIFICATION);
658 return;
660 if (attr->mac == NULL ||
661 eap_sim_verify_mac(data->k_aut, respData, attr->mac, NULL, 0)) {
662 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
663 "did not include valid AT_MAC");
664 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
665 eap_aka_state(data, NOTIFICATION);
666 return;
669 if (attr->res == NULL || attr->res_len != data->res_len ||
670 os_memcmp(attr->res, data->res, data->res_len) != 0) {
671 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
672 "include valid AT_RES");
673 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
674 eap_aka_state(data, NOTIFICATION);
675 return;
678 wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
679 "correct AT_MAC");
680 if (sm->eap_sim_aka_result_ind && attr->result_ind) {
681 data->use_result_ind = 1;
682 data->notification = EAP_SIM_SUCCESS;
683 eap_aka_state(data, NOTIFICATION);
684 } else
685 eap_aka_state(data, SUCCESS);
687 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
688 sm->identity_len, &identity_len);
689 if (identity == NULL) {
690 identity = sm->identity;
691 identity_len = sm->identity_len;
694 if (data->next_pseudonym) {
695 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
696 identity_len,
697 data->next_pseudonym);
698 data->next_pseudonym = NULL;
700 if (data->next_reauth_id) {
701 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
702 identity_len,
703 data->next_reauth_id, data->counter + 1,
704 data->mk);
705 data->next_reauth_id = NULL;
710 static void eap_aka_process_sync_failure(struct eap_sm *sm,
711 struct eap_aka_data *data,
712 struct wpabuf *respData,
713 struct eap_sim_attrs *attr)
715 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
717 if (attr->auts == NULL) {
718 wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
719 "message did not include valid AT_AUTS");
720 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
721 eap_aka_state(data, NOTIFICATION);
722 return;
725 /* Avoid re-reporting AUTS when processing pending EAP packet by
726 * maintaining a local flag stating whether this AUTS has already been
727 * reported. */
728 if (!data->auts_reported &&
729 eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
730 sm->identity_len, attr->auts,
731 data->rand)) {
732 wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
733 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
734 eap_aka_state(data, NOTIFICATION);
735 return;
737 data->auts_reported = 1;
739 /* Try again after resynchronization */
740 eap_aka_determine_identity(sm, data, 0, 0);
744 static void eap_aka_process_reauth(struct eap_sm *sm,
745 struct eap_aka_data *data,
746 struct wpabuf *respData,
747 struct eap_sim_attrs *attr)
749 struct eap_sim_attrs eattr;
750 u8 *decrypted = NULL;
751 const u8 *identity, *id2;
752 size_t identity_len, id2_len;
754 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
756 if (attr->mac == NULL ||
757 eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
758 EAP_SIM_NONCE_S_LEN)) {
759 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
760 "did not include valid AT_MAC");
761 goto fail;
764 if (attr->encr_data == NULL || attr->iv == NULL) {
765 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
766 "message did not include encrypted data");
767 goto fail;
770 decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
771 attr->encr_data_len, attr->iv, &eattr,
773 if (decrypted == NULL) {
774 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
775 "data from reauthentication message");
776 goto fail;
779 if (eattr.counter != data->counter) {
780 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
781 "used incorrect counter %u, expected %u",
782 eattr.counter, data->counter);
783 goto fail;
785 os_free(decrypted);
786 decrypted = NULL;
788 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
789 "the correct AT_MAC");
791 if (eattr.counter_too_small) {
792 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
793 "included AT_COUNTER_TOO_SMALL - starting full "
794 "authentication");
795 eap_aka_determine_identity(sm, data, 0, 1);
796 return;
799 if (sm->eap_sim_aka_result_ind && attr->result_ind) {
800 data->use_result_ind = 1;
801 data->notification = EAP_SIM_SUCCESS;
802 eap_aka_state(data, NOTIFICATION);
803 } else
804 eap_aka_state(data, SUCCESS);
806 if (data->reauth) {
807 identity = data->reauth->identity;
808 identity_len = data->reauth->identity_len;
809 } else {
810 identity = sm->identity;
811 identity_len = sm->identity_len;
814 id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
815 identity_len, &id2_len);
816 if (id2) {
817 identity = id2;
818 identity_len = id2_len;
821 if (data->next_pseudonym) {
822 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
823 identity_len, data->next_pseudonym);
824 data->next_pseudonym = NULL;
826 if (data->next_reauth_id) {
827 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
828 identity_len, data->next_reauth_id,
829 data->counter + 1, data->mk);
830 data->next_reauth_id = NULL;
831 } else {
832 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
833 data->reauth = NULL;
836 return;
838 fail:
839 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
840 eap_aka_state(data, NOTIFICATION);
841 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
842 data->reauth = NULL;
843 os_free(decrypted);
847 static void eap_aka_process_client_error(struct eap_sm *sm,
848 struct eap_aka_data *data,
849 struct wpabuf *respData,
850 struct eap_sim_attrs *attr)
852 wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
853 attr->client_error_code);
854 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
855 eap_aka_state(data, SUCCESS);
856 else
857 eap_aka_state(data, FAILURE);
861 static void eap_aka_process_authentication_reject(
862 struct eap_sm *sm, struct eap_aka_data *data,
863 struct wpabuf *respData, struct eap_sim_attrs *attr)
865 wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
866 eap_aka_state(data, FAILURE);
870 static void eap_aka_process_notification(struct eap_sm *sm,
871 struct eap_aka_data *data,
872 struct wpabuf *respData,
873 struct eap_sim_attrs *attr)
875 wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
876 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
877 eap_aka_state(data, SUCCESS);
878 else
879 eap_aka_state(data, FAILURE);
883 static void eap_aka_process(struct eap_sm *sm, void *priv,
884 struct wpabuf *respData)
886 struct eap_aka_data *data = priv;
887 const u8 *pos, *end;
888 u8 subtype;
889 size_t len;
890 struct eap_sim_attrs attr;
892 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_AKA, respData, &len);
893 if (pos == NULL || len < 3)
894 return;
896 end = pos + len;
897 subtype = *pos;
898 pos += 3;
900 if (eap_aka_subtype_ok(data, subtype)) {
901 wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
902 "EAP-AKA Subtype in EAP Response");
903 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
904 eap_aka_state(data, NOTIFICATION);
905 return;
908 if (eap_sim_parse_attr(pos, end, &attr, 1, 0)) {
909 wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
910 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
911 eap_aka_state(data, NOTIFICATION);
912 return;
915 if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
916 eap_aka_process_client_error(sm, data, respData, &attr);
917 return;
920 if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
921 eap_aka_process_authentication_reject(sm, data, respData,
922 &attr);
923 return;
926 switch (data->state) {
927 case IDENTITY:
928 eap_aka_process_identity(sm, data, respData, &attr);
929 break;
930 case CHALLENGE:
931 if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
932 eap_aka_process_sync_failure(sm, data, respData,
933 &attr);
934 } else {
935 eap_aka_process_challenge(sm, data, respData, &attr);
937 break;
938 case REAUTH:
939 eap_aka_process_reauth(sm, data, respData, &attr);
940 break;
941 case NOTIFICATION:
942 eap_aka_process_notification(sm, data, respData, &attr);
943 break;
944 default:
945 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
946 "process", data->state);
947 break;
952 static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
954 struct eap_aka_data *data = priv;
955 return data->state == SUCCESS || data->state == FAILURE;
959 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
961 struct eap_aka_data *data = priv;
962 u8 *key;
964 if (data->state != SUCCESS)
965 return NULL;
967 key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
968 if (key == NULL)
969 return NULL;
970 os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
971 *len = EAP_SIM_KEYING_DATA_LEN;
972 return key;
976 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
978 struct eap_aka_data *data = priv;
979 u8 *key;
981 if (data->state != SUCCESS)
982 return NULL;
984 key = os_malloc(EAP_EMSK_LEN);
985 if (key == NULL)
986 return NULL;
987 os_memcpy(key, data->emsk, EAP_EMSK_LEN);
988 *len = EAP_EMSK_LEN;
989 return key;
993 static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
995 struct eap_aka_data *data = priv;
996 return data->state == SUCCESS;
1000 int eap_server_aka_register(void)
1002 struct eap_method *eap;
1003 int ret;
1005 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1006 EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
1007 if (eap == NULL)
1008 return -1;
1010 eap->init = eap_aka_init;
1011 eap->reset = eap_aka_reset;
1012 eap->buildReq = eap_aka_buildReq;
1013 eap->check = eap_aka_check;
1014 eap->process = eap_aka_process;
1015 eap->isDone = eap_aka_isDone;
1016 eap->getKey = eap_aka_getKey;
1017 eap->isSuccess = eap_aka_isSuccess;
1018 eap->get_emsk = eap_aka_get_emsk;
1020 ret = eap_server_method_register(eap);
1021 if (ret)
1022 eap_server_method_free(eap);
1023 return ret;