2 * WPA Supplicant / EAP-AKA (draft-arkko-pppext-eap-aka-12.txt)
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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
12 * See README and COPYING for more details.
21 #include "wpa_supplicant.h"
22 #include "config_ssid.h"
24 #include "pcsc_funcs.h"
25 #include "eap_sim_common.h"
27 /* EAP-AKA Subtypes */
28 #define EAP_AKA_SUBTYPE_CHALLENGE 1
29 #define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2
30 #define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4
31 #define EAP_AKA_SUBTYPE_IDENTITY 5
32 #define EAP_AKA_SUBTYPE_NOTIFICATION 12
33 #define EAP_AKA_SUBTYPE_REAUTHENTICATION 13
34 #define EAP_AKA_SUBTYPE_CLIENT_ERROR 14
36 /* AT_CLIENT_ERROR_CODE error codes */
37 #define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0
39 #define AKA_AUTS_LEN 14
40 #define RES_MAX_LEN 16
43 #define EAP_AKA_MAX_FAST_REAUTHS 1000
46 u8 ik[IK_LEN], ck[CK_LEN], res[RES_MAX_LEN];
48 u8 nonce_s[EAP_SIM_NONCE_S_LEN];
49 u8 mk[EAP_SIM_MK_LEN];
50 u8 k_aut[EAP_SIM_K_AUT_LEN];
51 u8 k_encr[EAP_SIM_K_ENCR_LEN];
52 u8 msk[EAP_SIM_KEYING_DATA_LEN];
53 u8 rand[AKA_RAND_LEN], autn[AKA_AUTN_LEN];
54 u8 auts[AKA_AUTS_LEN];
56 int num_id_req, num_notification;
62 unsigned int counter, counter_too_small;
63 u8 *last_eap_identity;
64 size_t last_eap_identity_len;
65 enum { CONTINUE, SUCCESS, FAILURE } state;
69 static void * eap_aka_init(struct eap_sm *sm)
71 struct eap_aka_data *data;
72 data = malloc(sizeof(*data));
75 memset(data, 0, sizeof(*data));
77 data->state = CONTINUE;
83 static void eap_aka_deinit(struct eap_sm *sm, void *priv)
85 struct eap_aka_data *data = priv;
87 free(data->pseudonym);
88 free(data->reauth_id);
89 free(data->last_eap_identity);
95 static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
97 wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm");
99 return scard_umts_auth(sm->scard_ctx, data->rand,
100 data->autn, data->res, &data->res_len,
101 data->ik, data->ck, data->auts);
102 #else /* PCSC_FUNCS */
103 /* These hardcoded Kc and SRES values are used for testing.
104 * Could consider making them configurable. */
105 memset(data->res, '2', RES_MAX_LEN);
107 memset(data->ik, '3', IK_LEN);
108 memset(data->ck, '4', CK_LEN);
110 u8 autn[AKA_AUTN_LEN];
111 memset(autn, '1', AKA_AUTN_LEN);
112 if (memcmp(autn, data->autn, AKA_AUTN_LEN) != 0) {
113 wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
114 "with expected value");
119 #endif /* PCSC_FUNCS */
123 static void eap_aka_derive_mk(struct eap_aka_data *data,
124 const u8 *identity, size_t identity_len)
130 len[0] = identity_len;
136 /* MK = SHA1(Identity|IK|CK) */
137 sha1_vector(3, addr, len, data->mk);
138 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", data->ik, IK_LEN);
139 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", data->ck, CK_LEN);
140 wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", data->mk, EAP_SIM_MK_LEN);
144 #define CLEAR_PSEUDONYM 0x01
145 #define CLEAR_REAUTH_ID 0x02
146 #define CLEAR_EAP_ID 0x04
148 static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
150 wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s",
151 id & CLEAR_PSEUDONYM ? " pseudonym" : "",
152 id & CLEAR_REAUTH_ID ? " reauth_id" : "",
153 id & CLEAR_EAP_ID ? " eap_id" : "");
154 if (id & CLEAR_PSEUDONYM) {
155 free(data->pseudonym);
156 data->pseudonym = NULL;
157 data->pseudonym_len = 0;
159 if (id & CLEAR_REAUTH_ID) {
160 free(data->reauth_id);
161 data->reauth_id = NULL;
162 data->reauth_id_len = 0;
164 if (id & CLEAR_EAP_ID) {
165 free(data->last_eap_identity);
166 data->last_eap_identity = NULL;
167 data->last_eap_identity_len = 0;
172 static int eap_aka_learn_ids(struct eap_aka_data *data,
173 struct eap_sim_attrs *attr)
175 if (attr->next_pseudonym) {
176 free(data->pseudonym);
177 data->pseudonym = malloc(attr->next_pseudonym_len);
178 if (data->pseudonym == NULL) {
179 wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
183 memcpy(data->pseudonym, attr->next_pseudonym,
184 attr->next_pseudonym_len);
185 data->pseudonym_len = attr->next_pseudonym_len;
186 wpa_hexdump_ascii(MSG_DEBUG,
187 "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
189 data->pseudonym_len);
192 if (attr->next_reauth_id) {
193 free(data->reauth_id);
194 data->reauth_id = malloc(attr->next_reauth_id_len);
195 if (data->reauth_id == NULL) {
196 wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
200 memcpy(data->reauth_id, attr->next_reauth_id,
201 attr->next_reauth_id_len);
202 data->reauth_id_len = attr->next_reauth_id_len;
203 wpa_hexdump_ascii(MSG_DEBUG,
204 "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
206 data->reauth_id_len);
213 static u8 * eap_aka_client_error(struct eap_sm *sm, struct eap_aka_data *data,
215 size_t *respDataLen, int err)
217 struct eap_sim_msg *msg;
219 data->state = FAILURE;
220 data->num_id_req = 0;
221 data->num_notification = 0;
223 msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
224 EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CLIENT_ERROR);
225 eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
226 return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
230 static u8 * eap_aka_authentication_reject(struct eap_sm *sm,
231 struct eap_aka_data *data,
235 struct eap_sim_msg *msg;
237 data->state = FAILURE;
238 data->num_id_req = 0;
239 data->num_notification = 0;
241 wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
242 "(id=%d)", req->identifier);
243 msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
245 EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
246 return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
250 static u8 * eap_aka_synchronization_failure(struct eap_sm *sm,
251 struct eap_aka_data *data,
255 struct eap_sim_msg *msg;
257 data->state = FAILURE;
258 data->num_id_req = 0;
259 data->num_notification = 0;
261 wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
262 "(id=%d)", req->identifier);
263 msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
265 EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
266 wpa_printf(MSG_DEBUG, " AT_AUTS");
267 eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts, AKA_AUTS_LEN);
268 return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
272 static u8 * eap_aka_response_identity(struct eap_sm *sm,
273 struct eap_aka_data *data,
276 enum eap_sim_id_req id_req)
278 struct wpa_ssid *config = eap_get_config(sm);
280 size_t identity_len = 0;
281 struct eap_sim_msg *msg;
284 if (id_req == ANY_ID && data->reauth_id) {
285 identity = data->reauth_id;
286 identity_len = data->reauth_id_len;
288 } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
290 identity = data->pseudonym;
291 identity_len = data->pseudonym_len;
292 eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
293 } else if (id_req != NO_ID_REQ && config && config->identity) {
294 identity = config->identity;
295 identity_len = config->identity_len;
296 eap_aka_clear_identities(data,
297 CLEAR_PSEUDONYM | CLEAR_REAUTH_ID);
299 if (id_req != NO_ID_REQ)
300 eap_aka_clear_identities(data, CLEAR_EAP_ID);
302 wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)",
304 msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
305 EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY);
308 wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY",
309 identity, identity_len);
310 eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
311 identity, identity_len);
314 return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
318 static u8 * eap_aka_response_challenge(struct eap_sm *sm,
319 struct eap_aka_data *data,
323 struct eap_sim_msg *msg;
325 wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)",
327 msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
328 EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE);
329 wpa_printf(MSG_DEBUG, " AT_RES");
330 eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len,
331 data->res, data->res_len);
332 wpa_printf(MSG_DEBUG, " AT_MAC");
333 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
334 return eap_sim_msg_finish(msg, respDataLen, data->k_aut, (u8 *) "", 0);
338 static u8 * eap_aka_response_reauth(struct eap_sm *sm,
339 struct eap_aka_data *data,
341 size_t *respDataLen, int counter_too_small)
343 struct eap_sim_msg *msg;
344 unsigned int counter;
346 wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
348 msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
350 EAP_AKA_SUBTYPE_REAUTHENTICATION);
351 wpa_printf(MSG_DEBUG, " AT_IV");
352 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
353 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
355 if (counter_too_small) {
356 wpa_printf(MSG_DEBUG, " *AT_COUNTER_TOO_SMALL");
357 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
358 counter = data->counter_too_small;
360 counter = data->counter;
362 wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", counter);
363 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
365 if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
366 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
368 eap_sim_msg_free(msg);
371 wpa_printf(MSG_DEBUG, " AT_MAC");
372 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
373 return eap_sim_msg_finish(msg, respDataLen, data->k_aut, data->nonce_s,
374 EAP_SIM_NONCE_S_LEN);
378 static u8 * eap_aka_response_notification(struct eap_sm *sm,
379 struct eap_aka_data *data,
384 struct eap_sim_msg *msg;
385 u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
387 wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)",
389 msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
390 EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION);
391 wpa_printf(MSG_DEBUG, " AT_NOTIFICATION");
392 eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, notification, NULL, 0);
393 if (k_aut && data->reauth) {
394 wpa_printf(MSG_DEBUG, " AT_IV");
395 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
396 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
397 EAP_SIM_AT_ENCR_DATA);
398 wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", data->counter);
399 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
401 if (eap_sim_msg_add_encr_end(msg, data->k_encr,
402 EAP_SIM_AT_PADDING)) {
403 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
405 eap_sim_msg_free(msg);
410 wpa_printf(MSG_DEBUG, " AT_MAC");
411 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
413 return eap_sim_msg_finish(msg, respDataLen, k_aut, (u8 *) "", 0);
417 static u8 * eap_aka_process_identity(struct eap_sm *sm,
418 struct eap_aka_data *data,
419 struct eap_hdr *req, size_t reqDataLen,
421 struct eap_sim_attrs *attr)
425 wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity");
428 switch (attr->id_req) {
432 if (data->num_id_req > 0)
437 if (data->num_id_req > 1)
442 if (data->num_id_req > 2)
448 wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests "
449 "used within one authentication");
450 return eap_aka_client_error(sm, data, req, respDataLen,
451 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
454 return eap_aka_response_identity(sm, data, req, respDataLen,
459 static u8 * eap_aka_process_challenge(struct eap_sm *sm,
460 struct eap_aka_data *data,
461 struct eap_hdr *req, size_t reqDataLen,
463 struct eap_sim_attrs *attr)
465 struct wpa_ssid *config = eap_get_config(sm);
469 struct eap_sim_attrs eattr;
471 wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");
473 if (!attr->mac || !attr->rand || !attr->autn) {
474 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
475 "did not include%s%s%s",
476 !attr->mac ? " AT_MAC" : "",
477 !attr->rand ? " AT_RAND" : "",
478 !attr->autn ? " AT_AUTN" : "");
479 return eap_aka_client_error(sm, data, req, respDataLen,
480 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
482 memcpy(data->rand, attr->rand, AKA_RAND_LEN);
483 memcpy(data->autn, attr->autn, AKA_AUTN_LEN);
485 res = eap_aka_umts_auth(sm, data);
487 wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
489 return eap_aka_authentication_reject(sm, data, req,
491 } else if (res == -2) {
492 wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
493 "failed (AUTN seq# -> AUTS)");
494 return eap_aka_synchronization_failure(sm, data, req,
497 wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
498 return eap_aka_client_error(sm, data, req, respDataLen,
499 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
501 if (data->last_eap_identity) {
502 identity = data->last_eap_identity;
503 identity_len = data->last_eap_identity_len;
504 } else if (data->pseudonym) {
505 identity = data->pseudonym;
506 identity_len = data->pseudonym_len;
508 identity = config->identity;
509 identity_len = config->identity_len;
511 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
512 "derivation", identity, identity_len);
513 eap_aka_derive_mk(data, identity, identity_len);
514 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
515 if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
517 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
518 "used invalid AT_MAC");
519 return eap_aka_client_error(sm, data, req, respDataLen,
520 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
523 /* Old reauthentication and pseudonym identities must not be used
524 * anymore. In other words, if no new identities are received, full
525 * authentication will be used on next reauthentication. */
526 eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
529 if (attr->encr_data) {
530 if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
531 attr->encr_data_len, attr->iv, &eattr,
533 return eap_aka_client_error(
534 sm, data, req, respDataLen,
535 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
537 eap_aka_learn_ids(data, &eattr);
540 if (data->state != FAILURE)
541 data->state = SUCCESS;
543 data->num_id_req = 0;
544 data->num_notification = 0;
545 /* draft-arkko-pppext-eap-aka-12.txt specifies that counter
546 * is initialized to one after fullauth, but initializing it to
547 * zero makes it easier to implement reauth verification. */
549 return eap_aka_response_challenge(sm, data, req, respDataLen);
553 static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
556 struct eap_sim_attrs *attr)
558 struct eap_sim_attrs eattr;
560 if (attr->encr_data == NULL || attr->iv == NULL) {
561 wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
562 "reauth did not include encrypted data");
566 if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
567 attr->encr_data_len, attr->iv, &eattr, 0)) {
568 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
569 "data from notification message");
573 if (eattr.counter != data->counter) {
574 wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
575 "message does not match with counter in reauth "
584 static int eap_aka_process_notification_auth(struct eap_aka_data *data,
587 struct eap_sim_attrs *attr)
589 if (attr->mac == NULL) {
590 wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth "
591 "Notification message");
595 if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
597 wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
598 "used invalid AT_MAC");
603 eap_aka_process_notification_reauth(data, req, reqDataLen, attr)) {
604 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification "
605 "message after reauth");
613 static u8 * eap_aka_process_notification(struct eap_sm *sm,
614 struct eap_aka_data *data,
618 struct eap_sim_attrs *attr)
620 wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification");
621 if (data->num_notification > 0) {
622 wpa_printf(MSG_INFO, "EAP-AKA: too many notification "
623 "rounds (only one allowed)");
624 return eap_aka_client_error(sm, data, req, respDataLen,
625 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
627 data->num_notification++;
628 if (attr->notification == -1) {
629 wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in "
630 "Notification message");
631 return eap_aka_client_error(sm, data, req, respDataLen,
632 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
635 if ((attr->notification & 0x4000) == 0 &&
636 eap_aka_process_notification_auth(data, req, reqDataLen, attr)) {
637 return eap_aka_client_error(sm, data, req, respDataLen,
638 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
641 eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
642 if (attr->notification >= 0 && attr->notification < 32768) {
643 data->state = FAILURE;
645 return eap_aka_response_notification(sm, data, req, respDataLen,
650 static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
651 struct eap_aka_data *data,
655 struct eap_sim_attrs *attr)
657 struct eap_sim_attrs eattr;
659 wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
661 if (data->reauth_id == NULL) {
662 wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying "
663 "reauthentication, but no reauth_id available");
664 return eap_aka_client_error(sm, data, req, respDataLen,
665 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
669 if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen,
670 attr->mac, (u8 *) "", 0)) {
671 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
672 "did not have valid AT_MAC");
673 return eap_aka_client_error(sm, data, req, respDataLen,
674 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
677 if (attr->encr_data == NULL || attr->iv == NULL) {
678 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
679 "message did not include encrypted data");
680 return eap_aka_client_error(sm, data, req, respDataLen,
681 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
684 if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
685 attr->encr_data_len, attr->iv, &eattr, 0)) {
686 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
687 "data from reauthentication message");
688 return eap_aka_client_error(sm, data, req, respDataLen,
689 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
692 if (eattr.nonce_s == NULL || eattr.counter < 0) {
693 wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
694 !eattr.nonce_s ? " AT_NONCE_S" : "",
695 eattr.counter < 0 ? " AT_COUNTER" : "");
696 return eap_aka_client_error(sm, data, req, respDataLen,
697 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
700 if (eattr.counter <= data->counter) {
701 wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
702 "(%d <= %d)", eattr.counter, data->counter);
703 data->counter_too_small = eattr.counter;
704 /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
705 * reauth_id must not be used to start a new reauthentication.
706 * However, since it was used in the last EAP-Response-Identity
707 * packet, it has to saved for the following fullauth to be
708 * used in MK derivation. */
709 free(data->last_eap_identity);
710 data->last_eap_identity = data->reauth_id;
711 data->last_eap_identity_len = data->reauth_id_len;
712 data->reauth_id = NULL;
713 data->reauth_id_len = 0;
714 return eap_aka_response_reauth(sm, data, req, respDataLen, 1);
716 data->counter = eattr.counter;
718 memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
719 wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
720 data->nonce_s, EAP_SIM_NONCE_S_LEN);
722 eap_sim_derive_keys_reauth(data->counter,
723 data->reauth_id, data->reauth_id_len,
724 data->nonce_s, data->mk, data->msk);
725 eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
726 eap_aka_learn_ids(data, &eattr);
728 if (data->state != FAILURE)
729 data->state = SUCCESS;
731 data->num_id_req = 0;
732 data->num_notification = 0;
733 if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
734 wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
735 "fast reauths performed - force fullauth");
736 eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
738 return eap_aka_response_reauth(sm, data, req, respDataLen, 0);
742 static u8 * eap_aka_process(struct eap_sm *sm, void *priv,
743 struct eap_method_ret *ret,
744 u8 *reqData, size_t reqDataLen,
747 struct eap_aka_data *data = priv;
748 struct wpa_ssid *config = eap_get_config(sm);
750 u8 *pos, subtype, *res;
751 struct eap_sim_attrs attr;
754 wpa_hexdump(MSG_DEBUG, "EAP-AKA: EAP data", reqData, reqDataLen);
755 if (config == NULL || config->identity == NULL) {
756 wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
757 eap_sm_request_identity(sm, config);
762 req = (struct eap_hdr *) reqData;
763 pos = (u8 *) (req + 1);
764 if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_AKA ||
765 (len = be_to_host16(req->length)) > reqDataLen) {
766 wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
772 ret->methodState = METHOD_CONT;
773 ret->decision = DECISION_FAIL;
774 ret->allowNotifications = TRUE;
778 wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
779 pos += 2; /* Reserved */
781 if (eap_sim_parse_attr(pos, reqData + len, &attr, 1, 0)) {
782 res = eap_aka_client_error(sm, data, req, respDataLen,
783 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
788 case EAP_AKA_SUBTYPE_IDENTITY:
789 res = eap_aka_process_identity(sm, data, req, len,
792 case EAP_AKA_SUBTYPE_CHALLENGE:
793 res = eap_aka_process_challenge(sm, data, req, len,
796 case EAP_AKA_SUBTYPE_NOTIFICATION:
797 res = eap_aka_process_notification(sm, data, req, len,
800 case EAP_AKA_SUBTYPE_REAUTHENTICATION:
801 res = eap_aka_process_reauthentication(sm, data, req, len,
804 case EAP_AKA_SUBTYPE_CLIENT_ERROR:
805 wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
806 res = eap_aka_client_error(sm, data, req, respDataLen,
807 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
810 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
811 res = eap_aka_client_error(sm, data, req, respDataLen,
812 EAP_AKA_UNABLE_TO_PROCESS_PACKET);
817 if (data->state == FAILURE) {
818 ret->decision = DECISION_FAIL;
819 ret->methodState = METHOD_DONE;
820 } else if (data->state == SUCCESS) {
821 ret->decision = DECISION_UNCOND_SUCC;
822 ret->methodState = METHOD_DONE;
825 if (ret->methodState == METHOD_DONE) {
826 ret->allowNotifications = FALSE;
833 static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
835 struct eap_aka_data *data = priv;
836 return data->pseudonym || data->reauth_id;
840 static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
842 struct eap_aka_data *data = priv;
843 eap_aka_clear_identities(data, CLEAR_EAP_ID);
847 static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv)
849 struct eap_aka_data *data = priv;
850 data->num_id_req = 0;
851 data->num_notification = 0;
852 data->state = CONTINUE;
857 static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv,
860 struct eap_aka_data *data = priv;
862 if (data->reauth_id) {
863 *len = data->reauth_id_len;
864 return data->reauth_id;
867 if (data->pseudonym) {
868 *len = data->pseudonym_len;
869 return data->pseudonym;
876 static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
878 struct eap_aka_data *data = priv;
879 return data->state == SUCCESS;
883 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
885 struct eap_aka_data *data = priv;
888 if (data->state != SUCCESS)
891 key = malloc(EAP_SIM_KEYING_DATA_LEN);
895 *len = EAP_SIM_KEYING_DATA_LEN;
896 memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
902 const struct eap_method eap_method_aka =
904 .method = EAP_TYPE_AKA,
906 .init = eap_aka_init,
907 .deinit = eap_aka_deinit,
908 .process = eap_aka_process,
909 .isKeyAvailable = eap_aka_isKeyAvailable,
910 .getKey = eap_aka_getKey,
911 .has_reauth_data = eap_aka_has_reauth_data,
912 .deinit_for_reauth = eap_aka_deinit_for_reauth,
913 .init_for_reauth = eap_aka_init_for_reauth,
914 .get_identity = eap_aka_get_identity,