2 * hostapd / EAP-AKA (RFC 4187)
3 * Copyright (c) 2005-2007, 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
12 * See README and COPYING for more details.
21 #include "eap_sim_common.h"
22 #include "eap_sim_db.h"
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
];
39 IDENTITY
, CHALLENGE
, REAUTH
, NOTIFICATION
, SUCCESS
, FAILURE
44 struct eap_sim_reauth
*reauth
;
45 int auts_reported
; /* whether the current AUTS has been reported to the
51 static void eap_aka_determine_identity(struct eap_sm
*sm
,
52 struct eap_aka_data
*data
,
53 int before_identity
, int after_reauth
);
56 static const char * eap_aka_state_txt(int state
)
70 return "NOTIFICATION";
77 static void eap_aka_state(struct eap_aka_data
*data
, int state
)
79 wpa_printf(MSG_DEBUG
, "EAP-AKA: %s -> %s",
80 eap_aka_state_txt(data
->state
),
81 eap_aka_state_txt(state
));
86 static void * eap_aka_init(struct eap_sm
*sm
)
88 struct eap_aka_data
*data
;
90 if (sm
->eap_sim_db_priv
== NULL
) {
91 wpa_printf(MSG_WARNING
, "EAP-AKA: eap_sim_db not configured");
95 data
= wpa_zalloc(sizeof(*data
));
98 data
->state
= IDENTITY
;
99 eap_aka_determine_identity(sm
, data
, 1, 0);
105 static void eap_aka_reset(struct eap_sm
*sm
, void *priv
)
107 struct eap_aka_data
*data
= priv
;
108 free(data
->next_pseudonym
);
109 free(data
->next_reauth_id
);
114 static u8
* eap_aka_build_identity(struct eap_sm
*sm
,
115 struct eap_aka_data
*data
,
116 int id
, size_t *reqDataLen
)
118 struct eap_sim_msg
*msg
;
120 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Identity");
121 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_AKA
,
122 EAP_AKA_SUBTYPE_IDENTITY
);
123 if (eap_sim_db_identity_known(sm
->eap_sim_db_priv
, sm
->identity
,
125 wpa_printf(MSG_DEBUG
, " AT_PERMANENT_ID_REQ");
126 eap_sim_msg_add(msg
, EAP_SIM_AT_PERMANENT_ID_REQ
, 0, NULL
, 0);
128 return eap_sim_msg_finish(msg
, reqDataLen
, NULL
, NULL
, 0);
132 static int eap_aka_build_encr(struct eap_sm
*sm
, struct eap_aka_data
*data
,
133 struct eap_sim_msg
*msg
, u16 counter
,
136 free(data
->next_pseudonym
);
137 data
->next_pseudonym
=
138 eap_sim_db_get_next_pseudonym(sm
->eap_sim_db_priv
, 1);
139 free(data
->next_reauth_id
);
140 if (data
->counter
<= EAP_AKA_MAX_FAST_REAUTHS
) {
141 data
->next_reauth_id
=
142 eap_sim_db_get_next_reauth_id(sm
->eap_sim_db_priv
, 1);
144 wpa_printf(MSG_DEBUG
, "EAP-AKA: Max fast re-authentication "
145 "count exceeded - force full authentication");
146 data
->next_reauth_id
= NULL
;
149 if (data
->next_pseudonym
== NULL
&& data
->next_reauth_id
== NULL
&&
150 counter
== 0 && nonce_s
== NULL
)
153 wpa_printf(MSG_DEBUG
, " AT_IV");
154 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
155 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
, EAP_SIM_AT_ENCR_DATA
);
158 wpa_printf(MSG_DEBUG
, " *AT_COUNTER (%u)", counter
);
159 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
163 wpa_printf(MSG_DEBUG
, " *AT_NONCE_S");
164 eap_sim_msg_add(msg
, EAP_SIM_AT_NONCE_S
, 0, nonce_s
,
165 EAP_SIM_NONCE_S_LEN
);
168 if (data
->next_pseudonym
) {
169 wpa_printf(MSG_DEBUG
, " *AT_NEXT_PSEUDONYM (%s)",
170 data
->next_pseudonym
);
171 eap_sim_msg_add(msg
, EAP_SIM_AT_NEXT_PSEUDONYM
,
172 strlen(data
->next_pseudonym
),
173 (u8
*) data
->next_pseudonym
,
174 strlen(data
->next_pseudonym
));
177 if (data
->next_reauth_id
) {
178 wpa_printf(MSG_DEBUG
, " *AT_NEXT_REAUTH_ID (%s)",
179 data
->next_reauth_id
);
180 eap_sim_msg_add(msg
, EAP_SIM_AT_NEXT_REAUTH_ID
,
181 strlen(data
->next_reauth_id
),
182 (u8
*) data
->next_reauth_id
,
183 strlen(data
->next_reauth_id
));
186 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
, EAP_SIM_AT_PADDING
)) {
187 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
196 static u8
* eap_aka_build_challenge(struct eap_sm
*sm
,
197 struct eap_aka_data
*data
,
198 int id
, size_t *reqDataLen
)
200 struct eap_sim_msg
*msg
;
202 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Challenge");
203 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_AKA
,
204 EAP_AKA_SUBTYPE_CHALLENGE
);
205 wpa_printf(MSG_DEBUG
, " AT_RAND");
206 eap_sim_msg_add(msg
, EAP_SIM_AT_RAND
, 0, data
->rand
, EAP_AKA_RAND_LEN
);
207 eap_sim_msg_add(msg
, EAP_SIM_AT_AUTN
, 0, data
->autn
, EAP_AKA_AUTN_LEN
);
209 if (eap_aka_build_encr(sm
, data
, msg
, 0, NULL
)) {
210 eap_sim_msg_free(msg
);
214 wpa_printf(MSG_DEBUG
, " AT_MAC");
215 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
216 return eap_sim_msg_finish(msg
, reqDataLen
, data
->k_aut
, NULL
, 0);
220 static u8
* eap_aka_build_reauth(struct eap_sm
*sm
,
221 struct eap_aka_data
*data
,
222 int id
, size_t *reqDataLen
)
224 struct eap_sim_msg
*msg
;
226 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Re-authentication");
228 if (hostapd_get_rand(data
->nonce_s
, EAP_SIM_NONCE_S_LEN
))
230 wpa_hexdump_key(MSG_MSGDUMP
, "EAP-AKA: NONCE_S",
231 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
);
233 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
,
235 eap_sim_derive_keys_reauth(data
->counter
, sm
->identity
,
236 sm
->identity_len
, data
->nonce_s
, data
->mk
,
237 data
->msk
, data
->emsk
);
239 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_AKA
,
240 EAP_AKA_SUBTYPE_REAUTHENTICATION
);
242 if (eap_aka_build_encr(sm
, data
, msg
, data
->counter
, data
->nonce_s
)) {
243 eap_sim_msg_free(msg
);
247 wpa_printf(MSG_DEBUG
, " AT_MAC");
248 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
249 return eap_sim_msg_finish(msg
, reqDataLen
, data
->k_aut
, NULL
, 0);
253 static u8
* eap_aka_build_notification(struct eap_sm
*sm
,
254 struct eap_aka_data
*data
,
255 int id
, size_t *reqDataLen
)
257 struct eap_sim_msg
*msg
;
259 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Notification");
260 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, EAP_TYPE_AKA
,
261 EAP_AKA_SUBTYPE_NOTIFICATION
);
262 wpa_printf(MSG_DEBUG
, " AT_NOTIFICATION");
263 eap_sim_msg_add(msg
, EAP_SIM_AT_NOTIFICATION
, data
->notification
,
265 return eap_sim_msg_finish(msg
, reqDataLen
, NULL
, NULL
, 0);
269 static u8
* eap_aka_buildReq(struct eap_sm
*sm
, void *priv
, int id
,
272 struct eap_aka_data
*data
= priv
;
274 data
->auts_reported
= 0;
275 switch (data
->state
) {
277 return eap_aka_build_identity(sm
, data
, id
, reqDataLen
);
279 return eap_aka_build_challenge(sm
, data
, id
, reqDataLen
);
281 return eap_aka_build_reauth(sm
, data
, id
, reqDataLen
);
283 return eap_aka_build_notification(sm
, data
, id
, reqDataLen
);
285 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown state %d in "
286 "buildReq", data
->state
);
293 static Boolean
eap_aka_check(struct eap_sm
*sm
, void *priv
,
294 u8
*respData
, size_t respDataLen
)
296 struct eap_hdr
*resp
;
299 resp
= (struct eap_hdr
*) respData
;
300 pos
= (u8
*) (resp
+ 1);
301 if (respDataLen
< sizeof(*resp
) + 4 || *pos
!= EAP_TYPE_AKA
||
302 (ntohs(resp
->length
)) > respDataLen
) {
303 wpa_printf(MSG_INFO
, "EAP-AKA: Invalid frame");
311 static Boolean
eap_aka_subtype_ok(struct eap_aka_data
*data
, u8 subtype
)
313 if (subtype
== EAP_AKA_SUBTYPE_CLIENT_ERROR
||
314 subtype
== EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
)
317 switch (data
->state
) {
319 if (subtype
!= EAP_AKA_SUBTYPE_IDENTITY
) {
320 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
321 "subtype %d", subtype
);
326 if (subtype
!= EAP_AKA_SUBTYPE_CHALLENGE
&&
327 subtype
!= EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
) {
328 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
329 "subtype %d", subtype
);
334 if (subtype
!= EAP_AKA_SUBTYPE_REAUTHENTICATION
) {
335 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
336 "subtype %d", subtype
);
341 if (subtype
!= EAP_AKA_SUBTYPE_NOTIFICATION
) {
342 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
343 "subtype %d", subtype
);
348 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected state (%d) for "
349 "processing a response", data
->state
);
357 static void eap_aka_determine_identity(struct eap_sm
*sm
,
358 struct eap_aka_data
*data
,
359 int before_identity
, int after_reauth
)
368 if (after_reauth
&& data
->reauth
) {
369 identity
= data
->reauth
->identity
;
370 identity_len
= data
->reauth
->identity_len
;
371 } else if (sm
->identity
&& sm
->identity_len
> 0 &&
372 sm
->identity
[0] == EAP_AKA_PERMANENT_PREFIX
) {
373 identity
= sm
->identity
;
374 identity_len
= sm
->identity_len
;
376 identity
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
,
380 if (identity
== NULL
) {
381 data
->reauth
= eap_sim_db_get_reauth_entry(
382 sm
->eap_sim_db_priv
, sm
->identity
,
385 wpa_printf(MSG_DEBUG
, "EAP-AKA: Using fast "
386 "re-authentication");
387 identity
= data
->reauth
->identity
;
388 identity_len
= data
->reauth
->identity_len
;
389 data
->counter
= data
->reauth
->counter
;
390 memcpy(data
->mk
, data
->reauth
->mk
,
396 if (identity
== NULL
||
397 eap_sim_db_identity_known(sm
->eap_sim_db_priv
, sm
->identity
,
398 sm
->identity_len
) < 0) {
399 if (before_identity
) {
400 wpa_printf(MSG_DEBUG
, "EAP-AKA: Permanent user name "
401 "not known - send AKA-Identity request");
402 eap_aka_state(data
, IDENTITY
);
405 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown whether the "
406 "permanent user name is known; try to use "
408 /* eap_sim_db_get_aka_auth() will report failure, if
409 * this identity is not known. */
413 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA: Identity",
414 identity
, identity_len
);
416 if (!after_reauth
&& data
->reauth
) {
417 eap_aka_state(data
, REAUTH
);
421 res
= eap_sim_db_get_aka_auth(sm
->eap_sim_db_priv
, identity
,
422 identity_len
, data
->rand
, data
->autn
,
423 data
->ik
, data
->ck
, data
->res
,
425 if (res
== EAP_SIM_DB_PENDING
) {
426 wpa_printf(MSG_DEBUG
, "EAP-AKA: AKA authentication data "
427 "not yet available - pending request");
428 sm
->method_pending
= METHOD_PENDING_WAIT
;
433 data
->counter
= 0; /* reset re-auth counter since this is full auth */
436 wpa_printf(MSG_INFO
, "EAP-AKA: Failed to get AKA "
437 "authentication data for the peer");
438 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
439 eap_aka_state(data
, NOTIFICATION
);
442 if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
443 wpa_printf(MSG_DEBUG
, "EAP-AKA: AKA authentication data "
444 "available - abort pending wait");
445 sm
->method_pending
= METHOD_PENDING_NONE
;
448 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA: Identity for MK derivation",
449 sm
->identity
, sm
->identity_len
);
451 eap_aka_derive_mk(sm
->identity
, sm
->identity_len
, data
->ik
, data
->ck
,
453 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
,
456 eap_aka_state(data
, CHALLENGE
);
460 static void eap_aka_process_identity(struct eap_sm
*sm
,
461 struct eap_aka_data
*data
,
462 u8
*respData
, size_t respDataLen
,
463 struct eap_sim_attrs
*attr
)
465 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Identity");
467 if (attr
->mac
|| attr
->iv
|| attr
->encr_data
) {
468 wpa_printf(MSG_WARNING
, "EAP-AKA: Unexpected attribute "
469 "received in EAP-Response/AKA-Identity");
470 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
471 eap_aka_state(data
, NOTIFICATION
);
475 if (attr
->identity
) {
477 sm
->identity
= malloc(attr
->identity_len
);
479 memcpy(sm
->identity
, attr
->identity
,
481 sm
->identity_len
= attr
->identity_len
;
485 eap_aka_determine_identity(sm
, data
, 0, 0);
489 static void eap_aka_process_challenge(struct eap_sm
*sm
,
490 struct eap_aka_data
*data
,
491 u8
*respData
, size_t respDataLen
,
492 struct eap_sim_attrs
*attr
)
497 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Challenge");
499 if (attr
->mac
== NULL
||
500 eap_sim_verify_mac(data
->k_aut
, respData
, respDataLen
, attr
->mac
,
502 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
503 "did not include valid AT_MAC");
504 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
505 eap_aka_state(data
, NOTIFICATION
);
509 if (attr
->res
== NULL
|| attr
->res_len
!= data
->res_len
||
510 memcmp(attr
->res
, data
->res
, data
->res_len
) != 0) {
511 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message did not "
512 "include valid AT_RES");
513 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
514 eap_aka_state(data
, NOTIFICATION
);
518 wpa_printf(MSG_DEBUG
, "EAP-AKA: Challenge response includes the "
520 eap_aka_state(data
, SUCCESS
);
522 identity
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
, sm
->identity
,
523 sm
->identity_len
, &identity_len
);
524 if (identity
== NULL
) {
525 identity
= sm
->identity
;
526 identity_len
= sm
->identity_len
;
529 if (data
->next_pseudonym
) {
530 eap_sim_db_add_pseudonym(sm
->eap_sim_db_priv
, identity
,
532 data
->next_pseudonym
);
533 data
->next_pseudonym
= NULL
;
535 if (data
->next_reauth_id
) {
536 eap_sim_db_add_reauth(sm
->eap_sim_db_priv
, identity
,
538 data
->next_reauth_id
, data
->counter
+ 1,
540 data
->next_reauth_id
= NULL
;
545 static void eap_aka_process_sync_failure(struct eap_sm
*sm
,
546 struct eap_aka_data
*data
,
547 u8
*respData
, size_t respDataLen
,
548 struct eap_sim_attrs
*attr
)
550 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Synchronization-Failure");
552 if (attr
->auts
== NULL
) {
553 wpa_printf(MSG_WARNING
, "EAP-AKA: Synchronization-Failure "
554 "message did not include valid AT_AUTS");
555 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
556 eap_aka_state(data
, NOTIFICATION
);
560 /* Avoid re-reporting AUTS when processing pending EAP packet by
561 * maintaining a local flag stating whether this AUTS has already been
563 if (!data
->auts_reported
&&
564 eap_sim_db_resynchronize(sm
->eap_sim_db_priv
, sm
->identity
,
565 sm
->identity_len
, attr
->auts
,
567 wpa_printf(MSG_WARNING
, "EAP-AKA: Resynchronization failed");
568 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
569 eap_aka_state(data
, NOTIFICATION
);
572 data
->auts_reported
= 1;
574 /* Try again after resynchronization */
575 eap_aka_determine_identity(sm
, data
, 0, 0);
579 static void eap_aka_process_reauth(struct eap_sm
*sm
,
580 struct eap_aka_data
*data
,
581 u8
*respData
, size_t respDataLen
,
582 struct eap_sim_attrs
*attr
)
584 struct eap_sim_attrs eattr
;
585 u8
*decrypted
= NULL
;
586 const u8
*identity
, *id2
;
587 size_t identity_len
, id2_len
;
589 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Reauthentication");
591 if (attr
->mac
== NULL
||
592 eap_sim_verify_mac(data
->k_aut
, respData
, respDataLen
, attr
->mac
,
593 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
)) {
594 wpa_printf(MSG_WARNING
, "EAP-AKA: Re-authentication message "
595 "did not include valid AT_MAC");
599 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
600 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
601 "message did not include encrypted data");
605 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
606 attr
->encr_data_len
, attr
->iv
, &eattr
,
608 if (decrypted
== NULL
) {
609 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
610 "data from reauthentication message");
614 if (eattr
.counter
!= data
->counter
) {
615 wpa_printf(MSG_WARNING
, "EAP-AKA: Re-authentication message "
616 "used incorrect counter %u, expected %u",
617 eattr
.counter
, data
->counter
);
623 wpa_printf(MSG_DEBUG
, "EAP-AKA: Re-authentication response includes "
624 "the correct AT_MAC");
626 if (eattr
.counter_too_small
) {
627 wpa_printf(MSG_DEBUG
, "EAP-AKA: Re-authentication response "
628 "included AT_COUNTER_TOO_SMALL - starting full "
630 eap_aka_determine_identity(sm
, data
, 0, 1);
634 eap_aka_state(data
, SUCCESS
);
637 identity
= data
->reauth
->identity
;
638 identity_len
= data
->reauth
->identity_len
;
640 identity
= sm
->identity
;
641 identity_len
= sm
->identity_len
;
644 id2
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
, identity
,
645 identity_len
, &id2_len
);
648 identity_len
= id2_len
;
651 if (data
->next_pseudonym
) {
652 eap_sim_db_add_pseudonym(sm
->eap_sim_db_priv
, identity
,
653 identity_len
, data
->next_pseudonym
);
654 data
->next_pseudonym
= NULL
;
656 if (data
->next_reauth_id
) {
657 eap_sim_db_add_reauth(sm
->eap_sim_db_priv
, identity
,
658 identity_len
, data
->next_reauth_id
,
659 data
->counter
+ 1, data
->mk
);
660 data
->next_reauth_id
= NULL
;
662 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
669 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
670 eap_aka_state(data
, NOTIFICATION
);
671 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
677 static void eap_aka_process_client_error(struct eap_sm
*sm
,
678 struct eap_aka_data
*data
,
679 u8
*respData
, size_t respDataLen
,
680 struct eap_sim_attrs
*attr
)
682 wpa_printf(MSG_DEBUG
, "EAP-AKA: Client reported error %d",
683 attr
->client_error_code
);
684 eap_aka_state(data
, FAILURE
);
688 static void eap_aka_process_authentication_reject(
689 struct eap_sm
*sm
, struct eap_aka_data
*data
,
690 u8
*respData
, size_t respDataLen
, struct eap_sim_attrs
*attr
)
692 wpa_printf(MSG_DEBUG
, "EAP-AKA: Client rejected authentication");
693 eap_aka_state(data
, FAILURE
);
697 static void eap_aka_process_notification(struct eap_sm
*sm
,
698 struct eap_aka_data
*data
,
699 u8
*respData
, size_t respDataLen
,
700 struct eap_sim_attrs
*attr
)
702 wpa_printf(MSG_DEBUG
, "EAP-AKA: Client replied to notification");
703 eap_aka_state(data
, FAILURE
);
707 static void eap_aka_process(struct eap_sm
*sm
, void *priv
,
708 u8
*respData
, size_t respDataLen
)
710 struct eap_aka_data
*data
= priv
;
711 struct eap_hdr
*resp
;
714 struct eap_sim_attrs attr
;
716 resp
= (struct eap_hdr
*) respData
;
717 pos
= (u8
*) (resp
+ 1);
720 if (eap_aka_subtype_ok(data
, subtype
)) {
721 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unrecognized or unexpected "
722 "EAP-AKA Subtype in EAP Response");
723 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
724 eap_aka_state(data
, NOTIFICATION
);
728 len
= be_to_host16(resp
->length
);
731 if (eap_sim_parse_attr(pos
, respData
+ len
, &attr
, 1, 0)) {
732 wpa_printf(MSG_DEBUG
, "EAP-AKA: Failed to parse attributes");
733 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
734 eap_aka_state(data
, NOTIFICATION
);
738 if (subtype
== EAP_AKA_SUBTYPE_CLIENT_ERROR
) {
739 eap_aka_process_client_error(sm
, data
, respData
, len
, &attr
);
743 if (subtype
== EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
) {
744 eap_aka_process_authentication_reject(sm
, data
, respData
, len
,
749 switch (data
->state
) {
751 eap_aka_process_identity(sm
, data
, respData
, len
, &attr
);
754 if (subtype
== EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
) {
755 eap_aka_process_sync_failure(sm
, data
, respData
, len
,
758 eap_aka_process_challenge(sm
, data
, respData
, len
,
763 eap_aka_process_reauth(sm
, data
, respData
, len
, &attr
);
766 eap_aka_process_notification(sm
, data
, respData
, len
, &attr
);
769 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown state %d in "
770 "process", data
->state
);
776 static Boolean
eap_aka_isDone(struct eap_sm
*sm
, void *priv
)
778 struct eap_aka_data
*data
= priv
;
779 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
783 static u8
* eap_aka_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
785 struct eap_aka_data
*data
= priv
;
788 if (data
->state
!= SUCCESS
)
791 key
= malloc(EAP_SIM_KEYING_DATA_LEN
);
794 memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
795 *len
= EAP_SIM_KEYING_DATA_LEN
;
800 static u8
* eap_aka_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
802 struct eap_aka_data
*data
= priv
;
805 if (data
->state
!= SUCCESS
)
808 key
= malloc(EAP_EMSK_LEN
);
811 memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
817 static Boolean
eap_aka_isSuccess(struct eap_sm
*sm
, void *priv
)
819 struct eap_aka_data
*data
= priv
;
820 return data
->state
== SUCCESS
;
824 int eap_server_aka_register(void)
826 struct eap_method
*eap
;
829 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
830 EAP_VENDOR_IETF
, EAP_TYPE_AKA
, "AKA");
834 eap
->init
= eap_aka_init
;
835 eap
->reset
= eap_aka_reset
;
836 eap
->buildReq
= eap_aka_buildReq
;
837 eap
->check
= eap_aka_check
;
838 eap
->process
= eap_aka_process
;
839 eap
->isDone
= eap_aka_isDone
;
840 eap
->getKey
= eap_aka_getKey
;
841 eap
->isSuccess
= eap_aka_isSuccess
;
842 eap
->get_emsk
= eap_aka_get_emsk
;
844 ret
= eap_server_method_register(eap
);
846 eap_server_method_free(eap
);