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
12 * See README and COPYING for more details.
18 #include "eap_server/eap_i.h"
19 #include "eap_common/eap_sim_common.h"
20 #include "eap_server/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
50 struct wpabuf
*id_msgs
;
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
)
74 return "NOTIFICATION";
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
));
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");
99 data
= os_zalloc(sizeof(*data
));
102 data
->state
= IDENTITY
;
103 eap_aka_determine_identity(sm
, data
, 1, 0);
104 data
->pending_id
= -1;
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
);
120 static int eap_aka_add_id_msg(struct eap_aka_data
*data
,
121 const struct wpabuf
*msg
)
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)
133 wpabuf_put_buf(data
->id_msgs
, msg
);
139 static void eap_aka_add_checkcode(struct eap_aka_data
*data
,
140 struct eap_sim_msg
*msg
)
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
153 eap_sim_msg_add(msg
, EAP_SIM_AT_CHECKCODE
, 0, NULL
, 0);
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
)
173 u8 hash
[SHA1_MAC_LEN
];
175 if (checkcode
== NULL
)
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");
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 "
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");
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
;
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
,
220 wpa_printf(MSG_DEBUG
, " AT_PERMANENT_ID_REQ");
221 eap_sim_msg_add(msg
, EAP_SIM_AT_PERMANENT_ID_REQ
, 0, NULL
, 0);
224 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
225 * ignored and the AKA/Identity is used to request the
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) {
236 data
->pending_id
= id
;
241 static int eap_aka_build_encr(struct eap_sm
*sm
, struct eap_aka_data
*data
,
242 struct eap_sim_msg
*msg
, u16 counter
,
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);
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
)
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
);
267 wpa_printf(MSG_DEBUG
, " *AT_COUNTER (%u)", counter
);
268 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
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 "
305 static struct wpabuf
* eap_aka_build_challenge(struct eap_sm
*sm
,
306 struct eap_aka_data
*data
,
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
);
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
))
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
,
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
);
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
,
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
,
387 if (data
->use_result_ind
) {
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)",
395 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, data
->counter
,
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
);
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
) {
421 return eap_aka_build_identity(sm
, data
, id
);
423 return eap_aka_build_challenge(sm
, data
, id
);
425 return eap_aka_build_reauth(sm
, data
, id
);
427 return eap_aka_build_notification(sm
, data
, id
);
429 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown state %d in "
430 "buildReq", data
->state
);
437 static Boolean
eap_aka_check(struct eap_sm
*sm
, void *priv
,
438 struct wpabuf
*respData
)
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");
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
)
459 switch (data
->state
) {
461 if (subtype
!= EAP_AKA_SUBTYPE_IDENTITY
) {
462 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
463 "subtype %d", subtype
);
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
);
476 if (subtype
!= EAP_AKA_SUBTYPE_REAUTHENTICATION
) {
477 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
478 "subtype %d", subtype
);
483 if (subtype
!= EAP_AKA_SUBTYPE_NOTIFICATION
) {
484 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
485 "subtype %d", subtype
);
490 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected state (%d) for "
491 "processing a response", data
->state
);
499 static void eap_aka_determine_identity(struct eap_sm
*sm
,
500 struct eap_aka_data
*data
,
501 int before_identity
, int after_reauth
)
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
;
518 identity
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
,
522 if (identity
== NULL
) {
523 data
->reauth
= eap_sim_db_get_reauth_entry(
524 sm
->eap_sim_db_priv
, sm
->identity
,
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
,
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
);
547 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown whether the "
548 "permanent user name is known; try to use "
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
);
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
,
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
;
575 data
->counter
= 0; /* reset re-auth counter since this is full auth */
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
);
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");
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
,
601 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
,
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
);
623 if (attr
->identity
) {
624 os_free(sm
->identity
);
625 sm
->identity
= os_malloc(attr
->identity_len
);
627 os_memcpy(sm
->identity
, attr
->identity
,
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
)
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 "
656 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
657 eap_aka_state(data
, NOTIFICATION
);
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
);
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
);
678 wpa_printf(MSG_DEBUG
, "EAP-AKA: Challenge response includes the "
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
);
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
,
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
,
703 data
->next_reauth_id
, data
->counter
+ 1,
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
);
725 /* Avoid re-reporting AUTS when processing pending EAP packet by
726 * maintaining a local flag stating whether this AUTS has already been
728 if (!data
->auts_reported
&&
729 eap_sim_db_resynchronize(sm
->eap_sim_db_priv
, sm
->identity
,
730 sm
->identity_len
, attr
->auts
,
732 wpa_printf(MSG_WARNING
, "EAP-AKA: Resynchronization failed");
733 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
734 eap_aka_state(data
, NOTIFICATION
);
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");
764 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
765 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
766 "message did not include encrypted data");
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");
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
);
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 "
795 eap_aka_determine_identity(sm
, data
, 0, 1);
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
);
804 eap_aka_state(data
, SUCCESS
);
807 identity
= data
->reauth
->identity
;
808 identity_len
= data
->reauth
->identity_len
;
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
);
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
;
832 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
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
);
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
);
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
);
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
;
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)
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
);
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
);
915 if (subtype
== EAP_AKA_SUBTYPE_CLIENT_ERROR
) {
916 eap_aka_process_client_error(sm
, data
, respData
, &attr
);
920 if (subtype
== EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
) {
921 eap_aka_process_authentication_reject(sm
, data
, respData
,
926 switch (data
->state
) {
928 eap_aka_process_identity(sm
, data
, respData
, &attr
);
931 if (subtype
== EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
) {
932 eap_aka_process_sync_failure(sm
, data
, respData
,
935 eap_aka_process_challenge(sm
, data
, respData
, &attr
);
939 eap_aka_process_reauth(sm
, data
, respData
, &attr
);
942 eap_aka_process_notification(sm
, data
, respData
, &attr
);
945 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown state %d in "
946 "process", data
->state
);
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
;
964 if (data
->state
!= SUCCESS
)
967 key
= os_malloc(EAP_SIM_KEYING_DATA_LEN
);
970 os_memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
971 *len
= EAP_SIM_KEYING_DATA_LEN
;
976 static u8
* eap_aka_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
978 struct eap_aka_data
*data
= priv
;
981 if (data
->state
!= SUCCESS
)
984 key
= os_malloc(EAP_EMSK_LEN
);
987 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
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
;
1005 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
1006 EAP_VENDOR_IETF
, EAP_TYPE_AKA
, "AKA");
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
);
1022 eap_server_method_free(eap
);