2 * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
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"
27 u8 mk
[EAP_SIM_MK_LEN
];
28 u8 nonce_s
[EAP_SIM_NONCE_S_LEN
];
29 u8 k_aut
[EAP_AKA_PRIME_K_AUT_LEN
];
30 u8 k_encr
[EAP_SIM_K_ENCR_LEN
];
31 u8 k_re
[EAP_AKA_PRIME_K_RE_LEN
]; /* EAP-AKA' only */
32 u8 msk
[EAP_SIM_KEYING_DATA_LEN
];
33 u8 emsk
[EAP_EMSK_LEN
];
34 u8 rand
[EAP_AKA_RAND_LEN
];
35 u8 autn
[EAP_AKA_AUTN_LEN
];
36 u8 ck
[EAP_AKA_CK_LEN
];
37 u8 ik
[EAP_AKA_IK_LEN
];
38 u8 res
[EAP_AKA_RES_MAX_LEN
];
41 IDENTITY
, CHALLENGE
, REAUTH
, NOTIFICATION
, SUCCESS
, FAILURE
46 struct eap_sim_reauth
*reauth
;
47 int auts_reported
; /* whether the current AUTS has been reported to the
52 struct wpabuf
*id_msgs
;
56 size_t network_name_len
;
61 static void eap_aka_determine_identity(struct eap_sm
*sm
,
62 struct eap_aka_data
*data
,
63 int before_identity
, int after_reauth
);
66 static const char * eap_aka_state_txt(int state
)
80 return "NOTIFICATION";
87 static void eap_aka_state(struct eap_aka_data
*data
, int state
)
89 wpa_printf(MSG_DEBUG
, "EAP-AKA: %s -> %s",
90 eap_aka_state_txt(data
->state
),
91 eap_aka_state_txt(state
));
96 static void * eap_aka_init(struct eap_sm
*sm
)
98 struct eap_aka_data
*data
;
100 if (sm
->eap_sim_db_priv
== NULL
) {
101 wpa_printf(MSG_WARNING
, "EAP-AKA: eap_sim_db not configured");
105 data
= os_zalloc(sizeof(*data
));
109 data
->eap_method
= EAP_TYPE_AKA
;
111 data
->state
= IDENTITY
;
112 eap_aka_determine_identity(sm
, data
, 1, 0);
113 data
->pending_id
= -1;
120 static void * eap_aka_prime_init(struct eap_sm
*sm
)
122 struct eap_aka_data
*data
;
123 /* TODO: make ANID configurable; see 3GPP TS 24.302 */
124 char *network_name
= "WLAN";
126 if (sm
->eap_sim_db_priv
== NULL
) {
127 wpa_printf(MSG_WARNING
, "EAP-AKA: eap_sim_db not configured");
131 data
= os_zalloc(sizeof(*data
));
135 data
->eap_method
= EAP_TYPE_AKA_PRIME
;
136 data
->network_name
= os_malloc(os_strlen(network_name
));
137 if (data
->network_name
== NULL
) {
142 data
->network_name_len
= os_strlen(network_name
);
143 os_memcpy(data
->network_name
, network_name
, data
->network_name_len
);
145 data
->state
= IDENTITY
;
146 eap_aka_determine_identity(sm
, data
, 1, 0);
147 data
->pending_id
= -1;
151 #endif /* EAP_AKA_PRIME */
154 static void eap_aka_reset(struct eap_sm
*sm
, void *priv
)
156 struct eap_aka_data
*data
= priv
;
157 os_free(data
->next_pseudonym
);
158 os_free(data
->next_reauth_id
);
159 wpabuf_free(data
->id_msgs
);
160 os_free(data
->network_name
);
165 static int eap_aka_add_id_msg(struct eap_aka_data
*data
,
166 const struct wpabuf
*msg
)
171 if (data
->id_msgs
== NULL
) {
172 data
->id_msgs
= wpabuf_dup(msg
);
173 return data
->id_msgs
== NULL
? -1 : 0;
176 if (wpabuf_resize(&data
->id_msgs
, wpabuf_len(msg
)) < 0)
178 wpabuf_put_buf(data
->id_msgs
, msg
);
184 static void eap_aka_add_checkcode(struct eap_aka_data
*data
,
185 struct eap_sim_msg
*msg
)
189 u8 hash
[SHA256_MAC_LEN
];
191 wpa_printf(MSG_DEBUG
, " AT_CHECKCODE");
193 if (data
->id_msgs
== NULL
) {
195 * No EAP-AKA/Identity packets were exchanged - send empty
198 eap_sim_msg_add(msg
, EAP_SIM_AT_CHECKCODE
, 0, NULL
, 0);
202 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
203 addr
= wpabuf_head(data
->id_msgs
);
204 len
= wpabuf_len(data
->id_msgs
);
205 wpa_hexdump(MSG_MSGDUMP
, "EAP-AKA: AT_CHECKCODE data", addr
, len
);
206 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
)
207 sha256_vector(1, &addr
, &len
, hash
);
209 sha1_vector(1, &addr
, &len
, hash
);
211 eap_sim_msg_add(msg
, EAP_SIM_AT_CHECKCODE
, 0, hash
,
212 data
->eap_method
== EAP_TYPE_AKA_PRIME
?
213 EAP_AKA_PRIME_CHECKCODE_LEN
: EAP_AKA_CHECKCODE_LEN
);
217 static int eap_aka_verify_checkcode(struct eap_aka_data
*data
,
218 const u8
*checkcode
, size_t checkcode_len
)
222 u8 hash
[SHA256_MAC_LEN
];
225 if (checkcode
== NULL
)
228 if (data
->id_msgs
== NULL
) {
229 if (checkcode_len
!= 0) {
230 wpa_printf(MSG_DEBUG
, "EAP-AKA: Checkcode from peer "
231 "indicates that AKA/Identity messages were "
232 "used, but they were not");
238 hash_len
= data
->eap_method
== EAP_TYPE_AKA_PRIME
?
239 EAP_AKA_PRIME_CHECKCODE_LEN
: EAP_AKA_CHECKCODE_LEN
;
241 if (checkcode_len
!= hash_len
) {
242 wpa_printf(MSG_DEBUG
, "EAP-AKA: Checkcode from peer indicates "
243 "that AKA/Identity message were not used, but they "
248 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
249 addr
= wpabuf_head(data
->id_msgs
);
250 len
= wpabuf_len(data
->id_msgs
);
251 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
)
252 sha256_vector(1, &addr
, &len
, hash
);
254 sha1_vector(1, &addr
, &len
, hash
);
256 if (os_memcmp(hash
, checkcode
, hash_len
) != 0) {
257 wpa_printf(MSG_DEBUG
, "EAP-AKA: Mismatch in AT_CHECKCODE");
265 static struct wpabuf
* eap_aka_build_identity(struct eap_sm
*sm
,
266 struct eap_aka_data
*data
, u8 id
)
268 struct eap_sim_msg
*msg
;
271 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Identity");
272 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, data
->eap_method
,
273 EAP_AKA_SUBTYPE_IDENTITY
);
274 if (eap_sim_db_identity_known(sm
->eap_sim_db_priv
, sm
->identity
,
276 wpa_printf(MSG_DEBUG
, " AT_PERMANENT_ID_REQ");
277 eap_sim_msg_add(msg
, EAP_SIM_AT_PERMANENT_ID_REQ
, 0, NULL
, 0);
280 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
281 * ignored and the AKA/Identity is used to request the
284 wpa_printf(MSG_DEBUG
, " AT_ANY_ID_REQ");
285 eap_sim_msg_add(msg
, EAP_SIM_AT_ANY_ID_REQ
, 0, NULL
, 0);
287 buf
= eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
288 if (eap_aka_add_id_msg(data
, buf
) < 0) {
292 data
->pending_id
= id
;
297 static int eap_aka_build_encr(struct eap_sm
*sm
, struct eap_aka_data
*data
,
298 struct eap_sim_msg
*msg
, u16 counter
,
301 os_free(data
->next_pseudonym
);
302 data
->next_pseudonym
=
303 eap_sim_db_get_next_pseudonym(sm
->eap_sim_db_priv
, 1);
304 os_free(data
->next_reauth_id
);
305 if (data
->counter
<= EAP_AKA_MAX_FAST_REAUTHS
) {
306 data
->next_reauth_id
=
307 eap_sim_db_get_next_reauth_id(sm
->eap_sim_db_priv
, 1);
309 wpa_printf(MSG_DEBUG
, "EAP-AKA: Max fast re-authentication "
310 "count exceeded - force full authentication");
311 data
->next_reauth_id
= NULL
;
314 if (data
->next_pseudonym
== NULL
&& data
->next_reauth_id
== NULL
&&
315 counter
== 0 && nonce_s
== NULL
)
318 wpa_printf(MSG_DEBUG
, " AT_IV");
319 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
320 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
, EAP_SIM_AT_ENCR_DATA
);
323 wpa_printf(MSG_DEBUG
, " *AT_COUNTER (%u)", counter
);
324 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
328 wpa_printf(MSG_DEBUG
, " *AT_NONCE_S");
329 eap_sim_msg_add(msg
, EAP_SIM_AT_NONCE_S
, 0, nonce_s
,
330 EAP_SIM_NONCE_S_LEN
);
333 if (data
->next_pseudonym
) {
334 wpa_printf(MSG_DEBUG
, " *AT_NEXT_PSEUDONYM (%s)",
335 data
->next_pseudonym
);
336 eap_sim_msg_add(msg
, EAP_SIM_AT_NEXT_PSEUDONYM
,
337 os_strlen(data
->next_pseudonym
),
338 (u8
*) data
->next_pseudonym
,
339 os_strlen(data
->next_pseudonym
));
342 if (data
->next_reauth_id
) {
343 wpa_printf(MSG_DEBUG
, " *AT_NEXT_REAUTH_ID (%s)",
344 data
->next_reauth_id
);
345 eap_sim_msg_add(msg
, EAP_SIM_AT_NEXT_REAUTH_ID
,
346 os_strlen(data
->next_reauth_id
),
347 (u8
*) data
->next_reauth_id
,
348 os_strlen(data
->next_reauth_id
));
351 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
, EAP_SIM_AT_PADDING
)) {
352 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
361 static struct wpabuf
* eap_aka_build_challenge(struct eap_sm
*sm
,
362 struct eap_aka_data
*data
,
365 struct eap_sim_msg
*msg
;
367 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Challenge");
368 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, data
->eap_method
,
369 EAP_AKA_SUBTYPE_CHALLENGE
);
370 wpa_printf(MSG_DEBUG
, " AT_RAND");
371 eap_sim_msg_add(msg
, EAP_SIM_AT_RAND
, 0, data
->rand
, EAP_AKA_RAND_LEN
);
372 wpa_printf(MSG_DEBUG
, " AT_AUTN");
373 eap_sim_msg_add(msg
, EAP_SIM_AT_AUTN
, 0, data
->autn
, EAP_AKA_AUTN_LEN
);
374 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
376 /* Add the selected KDF into the beginning */
377 wpa_printf(MSG_DEBUG
, " AT_KDF");
378 eap_sim_msg_add(msg
, EAP_SIM_AT_KDF
, data
->kdf
,
381 wpa_printf(MSG_DEBUG
, " AT_KDF");
382 eap_sim_msg_add(msg
, EAP_SIM_AT_KDF
, EAP_AKA_PRIME_KDF
,
384 wpa_printf(MSG_DEBUG
, " AT_KDF_INPUT");
385 eap_sim_msg_add(msg
, EAP_SIM_AT_KDF_INPUT
,
386 data
->network_name_len
,
387 data
->network_name
, data
->network_name_len
);
390 if (eap_aka_build_encr(sm
, data
, msg
, 0, NULL
)) {
391 eap_sim_msg_free(msg
);
395 eap_aka_add_checkcode(data
, msg
);
397 if (sm
->eap_sim_aka_result_ind
) {
398 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
399 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
403 if (data
->eap_method
== EAP_TYPE_AKA
) {
406 int aka_prime_preferred
= 0;
409 while (sm
->user
&& i
< EAP_MAX_METHODS
&&
410 (sm
->user
->methods
[i
].vendor
!= EAP_VENDOR_IETF
||
411 sm
->user
->methods
[i
].method
!= EAP_TYPE_NONE
)) {
412 if (sm
->user
->methods
[i
].vendor
== EAP_VENDOR_IETF
) {
413 if (sm
->user
->methods
[i
].method
==
416 if (sm
->user
->methods
[i
].method
==
417 EAP_TYPE_AKA_PRIME
) {
418 aka_prime_preferred
= 1;
425 if (aka_prime_preferred
)
426 flags
|= EAP_AKA_BIDDING_FLAG_D
;
427 eap_sim_msg_add(msg
, EAP_SIM_AT_BIDDING
, flags
, NULL
, 0);
429 #endif /* EAP_AKA_PRIME */
431 wpa_printf(MSG_DEBUG
, " AT_MAC");
432 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
433 return eap_sim_msg_finish(msg
, data
->k_aut
, NULL
, 0);
437 static struct wpabuf
* eap_aka_build_reauth(struct eap_sm
*sm
,
438 struct eap_aka_data
*data
, u8 id
)
440 struct eap_sim_msg
*msg
;
442 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Re-authentication");
444 if (os_get_random(data
->nonce_s
, EAP_SIM_NONCE_S_LEN
))
446 wpa_hexdump_key(MSG_MSGDUMP
, "EAP-AKA: NONCE_S",
447 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
);
449 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
450 eap_aka_prime_derive_keys_reauth(data
->k_re
, data
->counter
,
454 data
->msk
, data
->emsk
);
456 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
,
457 data
->msk
, data
->emsk
);
458 eap_sim_derive_keys_reauth(data
->counter
, sm
->identity
,
459 sm
->identity_len
, data
->nonce_s
,
460 data
->mk
, data
->msk
, data
->emsk
);
463 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, data
->eap_method
,
464 EAP_AKA_SUBTYPE_REAUTHENTICATION
);
466 if (eap_aka_build_encr(sm
, data
, msg
, data
->counter
, data
->nonce_s
)) {
467 eap_sim_msg_free(msg
);
471 eap_aka_add_checkcode(data
, msg
);
473 if (sm
->eap_sim_aka_result_ind
) {
474 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
475 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
478 wpa_printf(MSG_DEBUG
, " AT_MAC");
479 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
480 return eap_sim_msg_finish(msg
, data
->k_aut
, NULL
, 0);
484 static struct wpabuf
* eap_aka_build_notification(struct eap_sm
*sm
,
485 struct eap_aka_data
*data
,
488 struct eap_sim_msg
*msg
;
490 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Notification");
491 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, data
->eap_method
,
492 EAP_AKA_SUBTYPE_NOTIFICATION
);
493 wpa_printf(MSG_DEBUG
, " AT_NOTIFICATION (%d)", data
->notification
);
494 eap_sim_msg_add(msg
, EAP_SIM_AT_NOTIFICATION
, data
->notification
,
496 if (data
->use_result_ind
) {
498 wpa_printf(MSG_DEBUG
, " AT_IV");
499 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
500 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
,
501 EAP_SIM_AT_ENCR_DATA
);
502 wpa_printf(MSG_DEBUG
, " *AT_COUNTER (%u)",
504 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, data
->counter
,
507 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
,
508 EAP_SIM_AT_PADDING
)) {
509 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to "
510 "encrypt AT_ENCR_DATA");
511 eap_sim_msg_free(msg
);
516 wpa_printf(MSG_DEBUG
, " AT_MAC");
517 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
519 return eap_sim_msg_finish(msg
, data
->k_aut
, NULL
, 0);
523 static struct wpabuf
* eap_aka_buildReq(struct eap_sm
*sm
, void *priv
, u8 id
)
525 struct eap_aka_data
*data
= priv
;
527 data
->auts_reported
= 0;
528 switch (data
->state
) {
530 return eap_aka_build_identity(sm
, data
, id
);
532 return eap_aka_build_challenge(sm
, data
, id
);
534 return eap_aka_build_reauth(sm
, data
, id
);
536 return eap_aka_build_notification(sm
, data
, id
);
538 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown state %d in "
539 "buildReq", data
->state
);
546 static Boolean
eap_aka_check(struct eap_sm
*sm
, void *priv
,
547 struct wpabuf
*respData
)
549 struct eap_aka_data
*data
= priv
;
553 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, data
->eap_method
, respData
,
555 if (pos
== NULL
|| len
< 3) {
556 wpa_printf(MSG_INFO
, "EAP-AKA: Invalid frame");
564 static Boolean
eap_aka_subtype_ok(struct eap_aka_data
*data
, u8 subtype
)
566 if (subtype
== EAP_AKA_SUBTYPE_CLIENT_ERROR
||
567 subtype
== EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
)
570 switch (data
->state
) {
572 if (subtype
!= EAP_AKA_SUBTYPE_IDENTITY
) {
573 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
574 "subtype %d", subtype
);
579 if (subtype
!= EAP_AKA_SUBTYPE_CHALLENGE
&&
580 subtype
!= EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
) {
581 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
582 "subtype %d", subtype
);
587 if (subtype
!= EAP_AKA_SUBTYPE_REAUTHENTICATION
) {
588 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
589 "subtype %d", subtype
);
594 if (subtype
!= EAP_AKA_SUBTYPE_NOTIFICATION
) {
595 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
596 "subtype %d", subtype
);
601 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected state (%d) for "
602 "processing a response", data
->state
);
610 static void eap_aka_determine_identity(struct eap_sm
*sm
,
611 struct eap_aka_data
*data
,
612 int before_identity
, int after_reauth
)
621 if (after_reauth
&& data
->reauth
) {
622 identity
= data
->reauth
->identity
;
623 identity_len
= data
->reauth
->identity_len
;
624 } else if (sm
->identity
&& sm
->identity_len
> 0 &&
625 sm
->identity
[0] == EAP_AKA_PERMANENT_PREFIX
) {
626 identity
= sm
->identity
;
627 identity_len
= sm
->identity_len
;
629 identity
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
,
633 if (identity
== NULL
) {
634 data
->reauth
= eap_sim_db_get_reauth_entry(
635 sm
->eap_sim_db_priv
, sm
->identity
,
638 data
->reauth
->aka_prime
!=
639 (data
->eap_method
== EAP_TYPE_AKA_PRIME
)) {
640 wpa_printf(MSG_DEBUG
, "EAP-AKA: Reauth data "
641 "was for different AKA version");
645 wpa_printf(MSG_DEBUG
, "EAP-AKA: Using fast "
646 "re-authentication");
647 identity
= data
->reauth
->identity
;
648 identity_len
= data
->reauth
->identity_len
;
649 data
->counter
= data
->reauth
->counter
;
650 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
651 os_memcpy(data
->k_encr
,
652 data
->reauth
->k_encr
,
654 os_memcpy(data
->k_aut
,
656 EAP_AKA_PRIME_K_AUT_LEN
);
657 os_memcpy(data
->k_re
,
659 EAP_AKA_PRIME_K_RE_LEN
);
661 os_memcpy(data
->mk
, data
->reauth
->mk
,
668 if (identity
== NULL
||
669 eap_sim_db_identity_known(sm
->eap_sim_db_priv
, sm
->identity
,
670 sm
->identity_len
) < 0) {
671 if (before_identity
) {
672 wpa_printf(MSG_DEBUG
, "EAP-AKA: Permanent user name "
673 "not known - send AKA-Identity request");
674 eap_aka_state(data
, IDENTITY
);
677 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown whether the "
678 "permanent user name is known; try to use "
680 /* eap_sim_db_get_aka_auth() will report failure, if
681 * this identity is not known. */
685 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA: Identity",
686 identity
, identity_len
);
688 if (!after_reauth
&& data
->reauth
) {
689 eap_aka_state(data
, REAUTH
);
693 res
= eap_sim_db_get_aka_auth(sm
->eap_sim_db_priv
, identity
,
694 identity_len
, data
->rand
, data
->autn
,
695 data
->ik
, data
->ck
, data
->res
,
697 if (res
== EAP_SIM_DB_PENDING
) {
698 wpa_printf(MSG_DEBUG
, "EAP-AKA: AKA authentication data "
699 "not yet available - pending request");
700 sm
->method_pending
= METHOD_PENDING_WAIT
;
705 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
706 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
707 * needed 6-octet SQN ^AK for CK',IK' derivation */
708 eap_aka_prime_derive_ck_ik_prime(data
->ck
, data
->ik
,
711 data
->network_name_len
);
713 #endif /* EAP_AKA_PRIME */
716 data
->counter
= 0; /* reset re-auth counter since this is full auth */
719 wpa_printf(MSG_INFO
, "EAP-AKA: Failed to get AKA "
720 "authentication data for the peer");
721 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
722 eap_aka_state(data
, NOTIFICATION
);
725 if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
726 wpa_printf(MSG_DEBUG
, "EAP-AKA: AKA authentication data "
727 "available - abort pending wait");
728 sm
->method_pending
= METHOD_PENDING_NONE
;
731 identity_len
= sm
->identity_len
;
732 while (identity_len
> 0 && sm
->identity
[identity_len
- 1] == '\0') {
733 wpa_printf(MSG_DEBUG
, "EAP-AKA: Workaround - drop last null "
734 "character from identity");
737 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA: Identity for MK derivation",
738 sm
->identity
, identity_len
);
740 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
741 eap_aka_prime_derive_keys(identity
, identity_len
, data
->ik
,
742 data
->ck
, data
->k_encr
, data
->k_aut
,
743 data
->k_re
, data
->msk
, data
->emsk
);
745 eap_aka_derive_mk(sm
->identity
, identity_len
, data
->ik
,
747 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
,
748 data
->msk
, data
->emsk
);
751 eap_aka_state(data
, CHALLENGE
);
755 static void eap_aka_process_identity(struct eap_sm
*sm
,
756 struct eap_aka_data
*data
,
757 struct wpabuf
*respData
,
758 struct eap_sim_attrs
*attr
)
760 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Identity");
762 if (attr
->mac
|| attr
->iv
|| attr
->encr_data
) {
763 wpa_printf(MSG_WARNING
, "EAP-AKA: Unexpected attribute "
764 "received in EAP-Response/AKA-Identity");
765 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
766 eap_aka_state(data
, NOTIFICATION
);
770 if (attr
->identity
) {
771 os_free(sm
->identity
);
772 sm
->identity
= os_malloc(attr
->identity_len
);
774 os_memcpy(sm
->identity
, attr
->identity
,
776 sm
->identity_len
= attr
->identity_len
;
780 eap_aka_determine_identity(sm
, data
, 0, 0);
781 if (eap_get_id(respData
) == data
->pending_id
) {
782 data
->pending_id
= -1;
783 eap_aka_add_id_msg(data
, respData
);
788 static int eap_aka_verify_mac(struct eap_aka_data
*data
,
789 const struct wpabuf
*req
,
790 const u8
*mac
, const u8
*extra
,
793 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
)
794 return eap_sim_verify_mac_sha256(data
->k_aut
, req
, mac
, extra
,
796 return eap_sim_verify_mac(data
->k_aut
, req
, mac
, extra
, extra_len
);
800 static void eap_aka_process_challenge(struct eap_sm
*sm
,
801 struct eap_aka_data
*data
,
802 struct wpabuf
*respData
,
803 struct eap_sim_attrs
*attr
)
808 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Challenge");
812 /* KDF negotiation; to be enabled only after more than one KDF is
814 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
&&
815 attr
->kdf_count
== 1 && attr
->mac
== NULL
) {
816 if (attr
->kdf
[0] != EAP_AKA_PRIME_KDF
) {
817 wpa_printf(MSG_WARNING
, "EAP-AKA': Peer selected "
820 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
821 eap_aka_state(data
, NOTIFICATION
);
825 data
->kdf
= attr
->kdf
[0];
827 /* Allow negotiation to continue with the selected KDF by
828 * sending another Challenge message */
829 wpa_printf(MSG_DEBUG
, "EAP-AKA': KDF %d selected", data
->kdf
);
833 #endif /* EAP_AKA_PRIME */
835 if (attr
->checkcode
&&
836 eap_aka_verify_checkcode(data
, attr
->checkcode
,
837 attr
->checkcode_len
)) {
838 wpa_printf(MSG_WARNING
, "EAP-AKA: Invalid AT_CHECKCODE in the "
840 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
841 eap_aka_state(data
, NOTIFICATION
);
844 if (attr
->mac
== NULL
||
845 eap_aka_verify_mac(data
, respData
, attr
->mac
, NULL
, 0)) {
846 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
847 "did not include valid AT_MAC");
848 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
849 eap_aka_state(data
, NOTIFICATION
);
854 * AT_RES is padded, so verify that there is enough room for RES and
855 * that the RES length in bits matches with the expected RES.
857 if (attr
->res
== NULL
|| attr
->res_len
< data
->res_len
||
858 attr
->res_len_bits
!= data
->res_len
* 8 ||
859 os_memcmp(attr
->res
, data
->res
, data
->res_len
) != 0) {
860 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message did not "
861 "include valid AT_RES (attr len=%lu, res len=%lu "
862 "bits, expected %lu bits)",
863 (unsigned long) attr
->res_len
,
864 (unsigned long) attr
->res_len_bits
,
865 (unsigned long) data
->res_len
* 8);
866 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
867 eap_aka_state(data
, NOTIFICATION
);
871 wpa_printf(MSG_DEBUG
, "EAP-AKA: Challenge response includes the "
873 if (sm
->eap_sim_aka_result_ind
&& attr
->result_ind
) {
874 data
->use_result_ind
= 1;
875 data
->notification
= EAP_SIM_SUCCESS
;
876 eap_aka_state(data
, NOTIFICATION
);
878 eap_aka_state(data
, SUCCESS
);
880 identity
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
, sm
->identity
,
881 sm
->identity_len
, &identity_len
);
882 if (identity
== NULL
) {
883 identity
= sm
->identity
;
884 identity_len
= sm
->identity_len
;
887 if (data
->next_pseudonym
) {
888 eap_sim_db_add_pseudonym(sm
->eap_sim_db_priv
, identity
,
890 data
->next_pseudonym
);
891 data
->next_pseudonym
= NULL
;
893 if (data
->next_reauth_id
) {
894 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
896 eap_sim_db_add_reauth_prime(sm
->eap_sim_db_priv
,
899 data
->next_reauth_id
,
901 data
->k_encr
, data
->k_aut
,
903 #endif /* EAP_AKA_PRIME */
905 eap_sim_db_add_reauth(sm
->eap_sim_db_priv
, identity
,
907 data
->next_reauth_id
,
911 data
->next_reauth_id
= NULL
;
916 static void eap_aka_process_sync_failure(struct eap_sm
*sm
,
917 struct eap_aka_data
*data
,
918 struct wpabuf
*respData
,
919 struct eap_sim_attrs
*attr
)
921 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Synchronization-Failure");
923 if (attr
->auts
== NULL
) {
924 wpa_printf(MSG_WARNING
, "EAP-AKA: Synchronization-Failure "
925 "message did not include valid AT_AUTS");
926 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
927 eap_aka_state(data
, NOTIFICATION
);
931 /* Avoid re-reporting AUTS when processing pending EAP packet by
932 * maintaining a local flag stating whether this AUTS has already been
934 if (!data
->auts_reported
&&
935 eap_sim_db_resynchronize(sm
->eap_sim_db_priv
, sm
->identity
,
936 sm
->identity_len
, attr
->auts
,
938 wpa_printf(MSG_WARNING
, "EAP-AKA: Resynchronization failed");
939 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
940 eap_aka_state(data
, NOTIFICATION
);
943 data
->auts_reported
= 1;
945 /* Try again after resynchronization */
946 eap_aka_determine_identity(sm
, data
, 0, 0);
950 static void eap_aka_process_reauth(struct eap_sm
*sm
,
951 struct eap_aka_data
*data
,
952 struct wpabuf
*respData
,
953 struct eap_sim_attrs
*attr
)
955 struct eap_sim_attrs eattr
;
956 u8
*decrypted
= NULL
;
957 const u8
*identity
, *id2
;
958 size_t identity_len
, id2_len
;
960 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Reauthentication");
962 if (attr
->mac
== NULL
||
963 eap_aka_verify_mac(data
, respData
, attr
->mac
, data
->nonce_s
,
964 EAP_SIM_NONCE_S_LEN
)) {
965 wpa_printf(MSG_WARNING
, "EAP-AKA: Re-authentication message "
966 "did not include valid AT_MAC");
970 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
971 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
972 "message did not include encrypted data");
976 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
977 attr
->encr_data_len
, attr
->iv
, &eattr
,
979 if (decrypted
== NULL
) {
980 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
981 "data from reauthentication message");
985 if (eattr
.counter
!= data
->counter
) {
986 wpa_printf(MSG_WARNING
, "EAP-AKA: Re-authentication message "
987 "used incorrect counter %u, expected %u",
988 eattr
.counter
, data
->counter
);
994 wpa_printf(MSG_DEBUG
, "EAP-AKA: Re-authentication response includes "
995 "the correct AT_MAC");
997 if (eattr
.counter_too_small
) {
998 wpa_printf(MSG_DEBUG
, "EAP-AKA: Re-authentication response "
999 "included AT_COUNTER_TOO_SMALL - starting full "
1001 eap_aka_determine_identity(sm
, data
, 0, 1);
1005 if (sm
->eap_sim_aka_result_ind
&& attr
->result_ind
) {
1006 data
->use_result_ind
= 1;
1007 data
->notification
= EAP_SIM_SUCCESS
;
1008 eap_aka_state(data
, NOTIFICATION
);
1010 eap_aka_state(data
, SUCCESS
);
1013 identity
= data
->reauth
->identity
;
1014 identity_len
= data
->reauth
->identity_len
;
1016 identity
= sm
->identity
;
1017 identity_len
= sm
->identity_len
;
1020 id2
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
, identity
,
1021 identity_len
, &id2_len
);
1024 identity_len
= id2_len
;
1027 if (data
->next_pseudonym
) {
1028 eap_sim_db_add_pseudonym(sm
->eap_sim_db_priv
, identity
,
1029 identity_len
, data
->next_pseudonym
);
1030 data
->next_pseudonym
= NULL
;
1032 if (data
->next_reauth_id
) {
1033 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
1034 #ifdef EAP_AKA_PRIME
1035 eap_sim_db_add_reauth_prime(sm
->eap_sim_db_priv
,
1038 data
->next_reauth_id
,
1040 data
->k_encr
, data
->k_aut
,
1042 #endif /* EAP_AKA_PRIME */
1044 eap_sim_db_add_reauth(sm
->eap_sim_db_priv
, identity
,
1046 data
->next_reauth_id
,
1050 data
->next_reauth_id
= NULL
;
1052 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
1053 data
->reauth
= NULL
;
1059 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
1060 eap_aka_state(data
, NOTIFICATION
);
1061 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
1062 data
->reauth
= NULL
;
1067 static void eap_aka_process_client_error(struct eap_sm
*sm
,
1068 struct eap_aka_data
*data
,
1069 struct wpabuf
*respData
,
1070 struct eap_sim_attrs
*attr
)
1072 wpa_printf(MSG_DEBUG
, "EAP-AKA: Client reported error %d",
1073 attr
->client_error_code
);
1074 if (data
->notification
== EAP_SIM_SUCCESS
&& data
->use_result_ind
)
1075 eap_aka_state(data
, SUCCESS
);
1077 eap_aka_state(data
, FAILURE
);
1081 static void eap_aka_process_authentication_reject(
1082 struct eap_sm
*sm
, struct eap_aka_data
*data
,
1083 struct wpabuf
*respData
, struct eap_sim_attrs
*attr
)
1085 wpa_printf(MSG_DEBUG
, "EAP-AKA: Client rejected authentication");
1086 eap_aka_state(data
, FAILURE
);
1090 static void eap_aka_process_notification(struct eap_sm
*sm
,
1091 struct eap_aka_data
*data
,
1092 struct wpabuf
*respData
,
1093 struct eap_sim_attrs
*attr
)
1095 wpa_printf(MSG_DEBUG
, "EAP-AKA: Client replied to notification");
1096 if (data
->notification
== EAP_SIM_SUCCESS
&& data
->use_result_ind
)
1097 eap_aka_state(data
, SUCCESS
);
1099 eap_aka_state(data
, FAILURE
);
1103 static void eap_aka_process(struct eap_sm
*sm
, void *priv
,
1104 struct wpabuf
*respData
)
1106 struct eap_aka_data
*data
= priv
;
1107 const u8
*pos
, *end
;
1110 struct eap_sim_attrs attr
;
1112 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, data
->eap_method
, respData
,
1114 if (pos
== NULL
|| len
< 3)
1121 if (eap_aka_subtype_ok(data
, subtype
)) {
1122 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unrecognized or unexpected "
1123 "EAP-AKA Subtype in EAP Response");
1124 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
1125 eap_aka_state(data
, NOTIFICATION
);
1129 if (eap_sim_parse_attr(pos
, end
, &attr
,
1130 data
->eap_method
== EAP_TYPE_AKA_PRIME
? 2 : 1,
1132 wpa_printf(MSG_DEBUG
, "EAP-AKA: Failed to parse attributes");
1133 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
1134 eap_aka_state(data
, NOTIFICATION
);
1138 if (subtype
== EAP_AKA_SUBTYPE_CLIENT_ERROR
) {
1139 eap_aka_process_client_error(sm
, data
, respData
, &attr
);
1143 if (subtype
== EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
) {
1144 eap_aka_process_authentication_reject(sm
, data
, respData
,
1149 switch (data
->state
) {
1151 eap_aka_process_identity(sm
, data
, respData
, &attr
);
1154 if (subtype
== EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
) {
1155 eap_aka_process_sync_failure(sm
, data
, respData
,
1158 eap_aka_process_challenge(sm
, data
, respData
, &attr
);
1162 eap_aka_process_reauth(sm
, data
, respData
, &attr
);
1165 eap_aka_process_notification(sm
, data
, respData
, &attr
);
1168 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown state %d in "
1169 "process", data
->state
);
1175 static Boolean
eap_aka_isDone(struct eap_sm
*sm
, void *priv
)
1177 struct eap_aka_data
*data
= priv
;
1178 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
1182 static u8
* eap_aka_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
1184 struct eap_aka_data
*data
= priv
;
1187 if (data
->state
!= SUCCESS
)
1190 key
= os_malloc(EAP_SIM_KEYING_DATA_LEN
);
1193 os_memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
1194 *len
= EAP_SIM_KEYING_DATA_LEN
;
1199 static u8
* eap_aka_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
1201 struct eap_aka_data
*data
= priv
;
1204 if (data
->state
!= SUCCESS
)
1207 key
= os_malloc(EAP_EMSK_LEN
);
1210 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
1211 *len
= EAP_EMSK_LEN
;
1216 static Boolean
eap_aka_isSuccess(struct eap_sm
*sm
, void *priv
)
1218 struct eap_aka_data
*data
= priv
;
1219 return data
->state
== SUCCESS
;
1223 int eap_server_aka_register(void)
1225 struct eap_method
*eap
;
1228 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
1229 EAP_VENDOR_IETF
, EAP_TYPE_AKA
, "AKA");
1233 eap
->init
= eap_aka_init
;
1234 eap
->reset
= eap_aka_reset
;
1235 eap
->buildReq
= eap_aka_buildReq
;
1236 eap
->check
= eap_aka_check
;
1237 eap
->process
= eap_aka_process
;
1238 eap
->isDone
= eap_aka_isDone
;
1239 eap
->getKey
= eap_aka_getKey
;
1240 eap
->isSuccess
= eap_aka_isSuccess
;
1241 eap
->get_emsk
= eap_aka_get_emsk
;
1243 ret
= eap_server_method_register(eap
);
1245 eap_server_method_free(eap
);
1250 #ifdef EAP_AKA_PRIME
1251 int eap_server_aka_prime_register(void)
1253 struct eap_method
*eap
;
1256 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
1257 EAP_VENDOR_IETF
, EAP_TYPE_AKA_PRIME
,
1262 eap
->init
= eap_aka_prime_init
;
1263 eap
->reset
= eap_aka_reset
;
1264 eap
->buildReq
= eap_aka_buildReq
;
1265 eap
->check
= eap_aka_check
;
1266 eap
->process
= eap_aka_process
;
1267 eap
->isDone
= eap_aka_isDone
;
1268 eap
->getKey
= eap_aka_getKey
;
1269 eap
->isSuccess
= eap_aka_isSuccess
;
1270 eap
->get_emsk
= eap_aka_get_emsk
;
1272 ret
= eap_server_method_register(eap
);
1274 eap_server_method_free(eap
);
1278 #endif /* EAP_AKA_PRIME */