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 "crypto/sha256.h"
19 #include "crypto/crypto.h"
20 #include "eap_common/eap_sim_common.h"
21 #include "eap_server/eap_i.h"
22 #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_AKA_PRIME_K_AUT_LEN
];
29 u8 k_encr
[EAP_SIM_K_ENCR_LEN
];
30 u8 k_re
[EAP_AKA_PRIME_K_RE_LEN
]; /* EAP-AKA' only */
31 u8 msk
[EAP_SIM_KEYING_DATA_LEN
];
32 u8 emsk
[EAP_EMSK_LEN
];
33 u8 rand
[EAP_AKA_RAND_LEN
];
34 u8 autn
[EAP_AKA_AUTN_LEN
];
35 u8 ck
[EAP_AKA_CK_LEN
];
36 u8 ik
[EAP_AKA_IK_LEN
];
37 u8 res
[EAP_AKA_RES_MAX_LEN
];
40 IDENTITY
, CHALLENGE
, REAUTH
, NOTIFICATION
, SUCCESS
, FAILURE
45 struct eap_sim_reauth
*reauth
;
46 int auts_reported
; /* whether the current AUTS has been reported to the
51 struct wpabuf
*id_msgs
;
55 size_t network_name_len
;
60 static void eap_aka_determine_identity(struct eap_sm
*sm
,
61 struct eap_aka_data
*data
,
62 int before_identity
, int after_reauth
);
65 static const char * eap_aka_state_txt(int state
)
79 return "NOTIFICATION";
86 static void eap_aka_state(struct eap_aka_data
*data
, int state
)
88 wpa_printf(MSG_DEBUG
, "EAP-AKA: %s -> %s",
89 eap_aka_state_txt(data
->state
),
90 eap_aka_state_txt(state
));
95 static void * eap_aka_init(struct eap_sm
*sm
)
97 struct eap_aka_data
*data
;
99 if (sm
->eap_sim_db_priv
== NULL
) {
100 wpa_printf(MSG_WARNING
, "EAP-AKA: eap_sim_db not configured");
104 data
= os_zalloc(sizeof(*data
));
108 data
->eap_method
= EAP_TYPE_AKA
;
110 data
->state
= IDENTITY
;
111 eap_aka_determine_identity(sm
, data
, 1, 0);
112 data
->pending_id
= -1;
118 #ifdef EAP_SERVER_AKA_PRIME
119 static void * eap_aka_prime_init(struct eap_sm
*sm
)
121 struct eap_aka_data
*data
;
122 /* TODO: make ANID configurable; see 3GPP TS 24.302 */
123 char *network_name
= "WLAN";
125 if (sm
->eap_sim_db_priv
== NULL
) {
126 wpa_printf(MSG_WARNING
, "EAP-AKA: eap_sim_db not configured");
130 data
= os_zalloc(sizeof(*data
));
134 data
->eap_method
= EAP_TYPE_AKA_PRIME
;
135 data
->network_name
= os_malloc(os_strlen(network_name
));
136 if (data
->network_name
== NULL
) {
141 data
->network_name_len
= os_strlen(network_name
);
142 os_memcpy(data
->network_name
, network_name
, data
->network_name_len
);
144 data
->state
= IDENTITY
;
145 eap_aka_determine_identity(sm
, data
, 1, 0);
146 data
->pending_id
= -1;
150 #endif /* EAP_SERVER_AKA_PRIME */
153 static void eap_aka_reset(struct eap_sm
*sm
, void *priv
)
155 struct eap_aka_data
*data
= priv
;
156 os_free(data
->next_pseudonym
);
157 os_free(data
->next_reauth_id
);
158 wpabuf_free(data
->id_msgs
);
159 os_free(data
->network_name
);
164 static int eap_aka_add_id_msg(struct eap_aka_data
*data
,
165 const struct wpabuf
*msg
)
170 if (data
->id_msgs
== NULL
) {
171 data
->id_msgs
= wpabuf_dup(msg
);
172 return data
->id_msgs
== NULL
? -1 : 0;
175 if (wpabuf_resize(&data
->id_msgs
, wpabuf_len(msg
)) < 0)
177 wpabuf_put_buf(data
->id_msgs
, msg
);
183 static void eap_aka_add_checkcode(struct eap_aka_data
*data
,
184 struct eap_sim_msg
*msg
)
188 u8 hash
[SHA256_MAC_LEN
];
190 wpa_printf(MSG_DEBUG
, " AT_CHECKCODE");
192 if (data
->id_msgs
== NULL
) {
194 * No EAP-AKA/Identity packets were exchanged - send empty
197 eap_sim_msg_add(msg
, EAP_SIM_AT_CHECKCODE
, 0, NULL
, 0);
201 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
202 addr
= wpabuf_head(data
->id_msgs
);
203 len
= wpabuf_len(data
->id_msgs
);
204 wpa_hexdump(MSG_MSGDUMP
, "EAP-AKA: AT_CHECKCODE data", addr
, len
);
205 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
)
206 sha256_vector(1, &addr
, &len
, hash
);
208 sha1_vector(1, &addr
, &len
, hash
);
210 eap_sim_msg_add(msg
, EAP_SIM_AT_CHECKCODE
, 0, hash
,
211 data
->eap_method
== EAP_TYPE_AKA_PRIME
?
212 EAP_AKA_PRIME_CHECKCODE_LEN
: EAP_AKA_CHECKCODE_LEN
);
216 static int eap_aka_verify_checkcode(struct eap_aka_data
*data
,
217 const u8
*checkcode
, size_t checkcode_len
)
221 u8 hash
[SHA256_MAC_LEN
];
224 if (checkcode
== NULL
)
227 if (data
->id_msgs
== NULL
) {
228 if (checkcode_len
!= 0) {
229 wpa_printf(MSG_DEBUG
, "EAP-AKA: Checkcode from peer "
230 "indicates that AKA/Identity messages were "
231 "used, but they were not");
237 hash_len
= data
->eap_method
== EAP_TYPE_AKA_PRIME
?
238 EAP_AKA_PRIME_CHECKCODE_LEN
: EAP_AKA_CHECKCODE_LEN
;
240 if (checkcode_len
!= hash_len
) {
241 wpa_printf(MSG_DEBUG
, "EAP-AKA: Checkcode from peer indicates "
242 "that AKA/Identity message were not used, but they "
247 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
248 addr
= wpabuf_head(data
->id_msgs
);
249 len
= wpabuf_len(data
->id_msgs
);
250 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
)
251 sha256_vector(1, &addr
, &len
, hash
);
253 sha1_vector(1, &addr
, &len
, hash
);
255 if (os_memcmp(hash
, checkcode
, hash_len
) != 0) {
256 wpa_printf(MSG_DEBUG
, "EAP-AKA: Mismatch in AT_CHECKCODE");
264 static struct wpabuf
* eap_aka_build_identity(struct eap_sm
*sm
,
265 struct eap_aka_data
*data
, u8 id
)
267 struct eap_sim_msg
*msg
;
270 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Identity");
271 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, data
->eap_method
,
272 EAP_AKA_SUBTYPE_IDENTITY
);
273 if (eap_sim_db_identity_known(sm
->eap_sim_db_priv
, sm
->identity
,
275 wpa_printf(MSG_DEBUG
, " AT_PERMANENT_ID_REQ");
276 eap_sim_msg_add(msg
, EAP_SIM_AT_PERMANENT_ID_REQ
, 0, NULL
, 0);
279 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
280 * ignored and the AKA/Identity is used to request the
283 wpa_printf(MSG_DEBUG
, " AT_ANY_ID_REQ");
284 eap_sim_msg_add(msg
, EAP_SIM_AT_ANY_ID_REQ
, 0, NULL
, 0);
286 buf
= eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
287 if (eap_aka_add_id_msg(data
, buf
) < 0) {
291 data
->pending_id
= id
;
296 static int eap_aka_build_encr(struct eap_sm
*sm
, struct eap_aka_data
*data
,
297 struct eap_sim_msg
*msg
, u16 counter
,
300 os_free(data
->next_pseudonym
);
301 data
->next_pseudonym
=
302 eap_sim_db_get_next_pseudonym(sm
->eap_sim_db_priv
, 1);
303 os_free(data
->next_reauth_id
);
304 if (data
->counter
<= EAP_AKA_MAX_FAST_REAUTHS
) {
305 data
->next_reauth_id
=
306 eap_sim_db_get_next_reauth_id(sm
->eap_sim_db_priv
, 1);
308 wpa_printf(MSG_DEBUG
, "EAP-AKA: Max fast re-authentication "
309 "count exceeded - force full authentication");
310 data
->next_reauth_id
= NULL
;
313 if (data
->next_pseudonym
== NULL
&& data
->next_reauth_id
== NULL
&&
314 counter
== 0 && nonce_s
== NULL
)
317 wpa_printf(MSG_DEBUG
, " AT_IV");
318 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
319 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
, EAP_SIM_AT_ENCR_DATA
);
322 wpa_printf(MSG_DEBUG
, " *AT_COUNTER (%u)", counter
);
323 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
327 wpa_printf(MSG_DEBUG
, " *AT_NONCE_S");
328 eap_sim_msg_add(msg
, EAP_SIM_AT_NONCE_S
, 0, nonce_s
,
329 EAP_SIM_NONCE_S_LEN
);
332 if (data
->next_pseudonym
) {
333 wpa_printf(MSG_DEBUG
, " *AT_NEXT_PSEUDONYM (%s)",
334 data
->next_pseudonym
);
335 eap_sim_msg_add(msg
, EAP_SIM_AT_NEXT_PSEUDONYM
,
336 os_strlen(data
->next_pseudonym
),
337 (u8
*) data
->next_pseudonym
,
338 os_strlen(data
->next_pseudonym
));
341 if (data
->next_reauth_id
) {
342 wpa_printf(MSG_DEBUG
, " *AT_NEXT_REAUTH_ID (%s)",
343 data
->next_reauth_id
);
344 eap_sim_msg_add(msg
, EAP_SIM_AT_NEXT_REAUTH_ID
,
345 os_strlen(data
->next_reauth_id
),
346 (u8
*) data
->next_reauth_id
,
347 os_strlen(data
->next_reauth_id
));
350 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
, EAP_SIM_AT_PADDING
)) {
351 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
360 static struct wpabuf
* eap_aka_build_challenge(struct eap_sm
*sm
,
361 struct eap_aka_data
*data
,
364 struct eap_sim_msg
*msg
;
366 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Challenge");
367 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, data
->eap_method
,
368 EAP_AKA_SUBTYPE_CHALLENGE
);
369 wpa_printf(MSG_DEBUG
, " AT_RAND");
370 eap_sim_msg_add(msg
, EAP_SIM_AT_RAND
, 0, data
->rand
, EAP_AKA_RAND_LEN
);
371 wpa_printf(MSG_DEBUG
, " AT_AUTN");
372 eap_sim_msg_add(msg
, EAP_SIM_AT_AUTN
, 0, data
->autn
, EAP_AKA_AUTN_LEN
);
373 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
375 /* Add the selected KDF into the beginning */
376 wpa_printf(MSG_DEBUG
, " AT_KDF");
377 eap_sim_msg_add(msg
, EAP_SIM_AT_KDF
, data
->kdf
,
380 wpa_printf(MSG_DEBUG
, " AT_KDF");
381 eap_sim_msg_add(msg
, EAP_SIM_AT_KDF
, EAP_AKA_PRIME_KDF
,
383 wpa_printf(MSG_DEBUG
, " AT_KDF_INPUT");
384 eap_sim_msg_add(msg
, EAP_SIM_AT_KDF_INPUT
,
385 data
->network_name_len
,
386 data
->network_name
, data
->network_name_len
);
389 if (eap_aka_build_encr(sm
, data
, msg
, 0, NULL
)) {
390 eap_sim_msg_free(msg
);
394 eap_aka_add_checkcode(data
, msg
);
396 if (sm
->eap_sim_aka_result_ind
) {
397 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
398 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
401 #ifdef EAP_SERVER_AKA_PRIME
402 if (data
->eap_method
== EAP_TYPE_AKA
) {
405 int aka_prime_preferred
= 0;
408 while (sm
->user
&& i
< EAP_MAX_METHODS
&&
409 (sm
->user
->methods
[i
].vendor
!= EAP_VENDOR_IETF
||
410 sm
->user
->methods
[i
].method
!= EAP_TYPE_NONE
)) {
411 if (sm
->user
->methods
[i
].vendor
== EAP_VENDOR_IETF
) {
412 if (sm
->user
->methods
[i
].method
==
415 if (sm
->user
->methods
[i
].method
==
416 EAP_TYPE_AKA_PRIME
) {
417 aka_prime_preferred
= 1;
424 if (aka_prime_preferred
)
425 flags
|= EAP_AKA_BIDDING_FLAG_D
;
426 eap_sim_msg_add(msg
, EAP_SIM_AT_BIDDING
, flags
, NULL
, 0);
428 #endif /* EAP_SERVER_AKA_PRIME */
430 wpa_printf(MSG_DEBUG
, " AT_MAC");
431 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
432 return eap_sim_msg_finish(msg
, data
->k_aut
, NULL
, 0);
436 static struct wpabuf
* eap_aka_build_reauth(struct eap_sm
*sm
,
437 struct eap_aka_data
*data
, u8 id
)
439 struct eap_sim_msg
*msg
;
441 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Re-authentication");
443 if (os_get_random(data
->nonce_s
, EAP_SIM_NONCE_S_LEN
))
445 wpa_hexdump_key(MSG_MSGDUMP
, "EAP-AKA: NONCE_S",
446 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
);
448 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
449 eap_aka_prime_derive_keys_reauth(data
->k_re
, data
->counter
,
453 data
->msk
, data
->emsk
);
455 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
,
456 data
->msk
, data
->emsk
);
457 eap_sim_derive_keys_reauth(data
->counter
, sm
->identity
,
458 sm
->identity_len
, data
->nonce_s
,
459 data
->mk
, data
->msk
, data
->emsk
);
462 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, data
->eap_method
,
463 EAP_AKA_SUBTYPE_REAUTHENTICATION
);
465 if (eap_aka_build_encr(sm
, data
, msg
, data
->counter
, data
->nonce_s
)) {
466 eap_sim_msg_free(msg
);
470 eap_aka_add_checkcode(data
, msg
);
472 if (sm
->eap_sim_aka_result_ind
) {
473 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
474 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
477 wpa_printf(MSG_DEBUG
, " AT_MAC");
478 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
479 return eap_sim_msg_finish(msg
, data
->k_aut
, NULL
, 0);
483 static struct wpabuf
* eap_aka_build_notification(struct eap_sm
*sm
,
484 struct eap_aka_data
*data
,
487 struct eap_sim_msg
*msg
;
489 wpa_printf(MSG_DEBUG
, "EAP-AKA: Generating Notification");
490 msg
= eap_sim_msg_init(EAP_CODE_REQUEST
, id
, data
->eap_method
,
491 EAP_AKA_SUBTYPE_NOTIFICATION
);
492 wpa_printf(MSG_DEBUG
, " AT_NOTIFICATION (%d)", data
->notification
);
493 eap_sim_msg_add(msg
, EAP_SIM_AT_NOTIFICATION
, data
->notification
,
495 if (data
->use_result_ind
) {
497 wpa_printf(MSG_DEBUG
, " AT_IV");
498 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
499 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
,
500 EAP_SIM_AT_ENCR_DATA
);
501 wpa_printf(MSG_DEBUG
, " *AT_COUNTER (%u)",
503 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, data
->counter
,
506 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
,
507 EAP_SIM_AT_PADDING
)) {
508 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to "
509 "encrypt AT_ENCR_DATA");
510 eap_sim_msg_free(msg
);
515 wpa_printf(MSG_DEBUG
, " AT_MAC");
516 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
518 return eap_sim_msg_finish(msg
, data
->k_aut
, NULL
, 0);
522 static struct wpabuf
* eap_aka_buildReq(struct eap_sm
*sm
, void *priv
, u8 id
)
524 struct eap_aka_data
*data
= priv
;
526 data
->auts_reported
= 0;
527 switch (data
->state
) {
529 return eap_aka_build_identity(sm
, data
, id
);
531 return eap_aka_build_challenge(sm
, data
, id
);
533 return eap_aka_build_reauth(sm
, data
, id
);
535 return eap_aka_build_notification(sm
, data
, id
);
537 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown state %d in "
538 "buildReq", data
->state
);
545 static Boolean
eap_aka_check(struct eap_sm
*sm
, void *priv
,
546 struct wpabuf
*respData
)
548 struct eap_aka_data
*data
= priv
;
552 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, data
->eap_method
, respData
,
554 if (pos
== NULL
|| len
< 3) {
555 wpa_printf(MSG_INFO
, "EAP-AKA: Invalid frame");
563 static Boolean
eap_aka_subtype_ok(struct eap_aka_data
*data
, u8 subtype
)
565 if (subtype
== EAP_AKA_SUBTYPE_CLIENT_ERROR
||
566 subtype
== EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
)
569 switch (data
->state
) {
571 if (subtype
!= EAP_AKA_SUBTYPE_IDENTITY
) {
572 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
573 "subtype %d", subtype
);
578 if (subtype
!= EAP_AKA_SUBTYPE_CHALLENGE
&&
579 subtype
!= EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
) {
580 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
581 "subtype %d", subtype
);
586 if (subtype
!= EAP_AKA_SUBTYPE_REAUTHENTICATION
) {
587 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
588 "subtype %d", subtype
);
593 if (subtype
!= EAP_AKA_SUBTYPE_NOTIFICATION
) {
594 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected response "
595 "subtype %d", subtype
);
600 wpa_printf(MSG_INFO
, "EAP-AKA: Unexpected state (%d) for "
601 "processing a response", data
->state
);
609 static void eap_aka_determine_identity(struct eap_sm
*sm
,
610 struct eap_aka_data
*data
,
611 int before_identity
, int after_reauth
)
620 if (after_reauth
&& data
->reauth
) {
621 identity
= data
->reauth
->identity
;
622 identity_len
= data
->reauth
->identity_len
;
623 } else if (sm
->identity
&& sm
->identity_len
> 0 &&
624 sm
->identity
[0] == EAP_AKA_PERMANENT_PREFIX
) {
625 identity
= sm
->identity
;
626 identity_len
= sm
->identity_len
;
628 identity
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
,
632 if (identity
== NULL
) {
633 data
->reauth
= eap_sim_db_get_reauth_entry(
634 sm
->eap_sim_db_priv
, sm
->identity
,
637 data
->reauth
->aka_prime
!=
638 (data
->eap_method
== EAP_TYPE_AKA_PRIME
)) {
639 wpa_printf(MSG_DEBUG
, "EAP-AKA: Reauth data "
640 "was for different AKA version");
644 wpa_printf(MSG_DEBUG
, "EAP-AKA: Using fast "
645 "re-authentication");
646 identity
= data
->reauth
->identity
;
647 identity_len
= data
->reauth
->identity_len
;
648 data
->counter
= data
->reauth
->counter
;
649 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
650 os_memcpy(data
->k_encr
,
651 data
->reauth
->k_encr
,
653 os_memcpy(data
->k_aut
,
655 EAP_AKA_PRIME_K_AUT_LEN
);
656 os_memcpy(data
->k_re
,
658 EAP_AKA_PRIME_K_RE_LEN
);
660 os_memcpy(data
->mk
, data
->reauth
->mk
,
667 if (identity
== NULL
||
668 eap_sim_db_identity_known(sm
->eap_sim_db_priv
, sm
->identity
,
669 sm
->identity_len
) < 0) {
670 if (before_identity
) {
671 wpa_printf(MSG_DEBUG
, "EAP-AKA: Permanent user name "
672 "not known - send AKA-Identity request");
673 eap_aka_state(data
, IDENTITY
);
676 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown whether the "
677 "permanent user name is known; try to use "
679 /* eap_sim_db_get_aka_auth() will report failure, if
680 * this identity is not known. */
684 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA: Identity",
685 identity
, identity_len
);
687 if (!after_reauth
&& data
->reauth
) {
688 eap_aka_state(data
, REAUTH
);
692 res
= eap_sim_db_get_aka_auth(sm
->eap_sim_db_priv
, identity
,
693 identity_len
, data
->rand
, data
->autn
,
694 data
->ik
, data
->ck
, data
->res
,
696 if (res
== EAP_SIM_DB_PENDING
) {
697 wpa_printf(MSG_DEBUG
, "EAP-AKA: AKA authentication data "
698 "not yet available - pending request");
699 sm
->method_pending
= METHOD_PENDING_WAIT
;
703 #ifdef EAP_SERVER_AKA_PRIME
704 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
705 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
706 * needed 6-octet SQN ^AK for CK',IK' derivation */
707 eap_aka_prime_derive_ck_ik_prime(data
->ck
, data
->ik
,
710 data
->network_name_len
);
712 #endif /* EAP_SERVER_AKA_PRIME */
715 data
->counter
= 0; /* reset re-auth counter since this is full auth */
718 wpa_printf(MSG_INFO
, "EAP-AKA: Failed to get AKA "
719 "authentication data for the peer");
720 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
721 eap_aka_state(data
, NOTIFICATION
);
724 if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
725 wpa_printf(MSG_DEBUG
, "EAP-AKA: AKA authentication data "
726 "available - abort pending wait");
727 sm
->method_pending
= METHOD_PENDING_NONE
;
730 identity_len
= sm
->identity_len
;
731 while (identity_len
> 0 && sm
->identity
[identity_len
- 1] == '\0') {
732 wpa_printf(MSG_DEBUG
, "EAP-AKA: Workaround - drop last null "
733 "character from identity");
736 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA: Identity for MK derivation",
737 sm
->identity
, identity_len
);
739 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
740 eap_aka_prime_derive_keys(identity
, identity_len
, data
->ik
,
741 data
->ck
, data
->k_encr
, data
->k_aut
,
742 data
->k_re
, data
->msk
, data
->emsk
);
744 eap_aka_derive_mk(sm
->identity
, identity_len
, data
->ik
,
746 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
,
747 data
->msk
, data
->emsk
);
750 eap_aka_state(data
, CHALLENGE
);
754 static void eap_aka_process_identity(struct eap_sm
*sm
,
755 struct eap_aka_data
*data
,
756 struct wpabuf
*respData
,
757 struct eap_sim_attrs
*attr
)
759 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Identity");
761 if (attr
->mac
|| attr
->iv
|| attr
->encr_data
) {
762 wpa_printf(MSG_WARNING
, "EAP-AKA: Unexpected attribute "
763 "received in EAP-Response/AKA-Identity");
764 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
765 eap_aka_state(data
, NOTIFICATION
);
769 if (attr
->identity
) {
770 os_free(sm
->identity
);
771 sm
->identity
= os_malloc(attr
->identity_len
);
773 os_memcpy(sm
->identity
, attr
->identity
,
775 sm
->identity_len
= attr
->identity_len
;
779 eap_aka_determine_identity(sm
, data
, 0, 0);
780 if (eap_get_id(respData
) == data
->pending_id
) {
781 data
->pending_id
= -1;
782 eap_aka_add_id_msg(data
, respData
);
787 static int eap_aka_verify_mac(struct eap_aka_data
*data
,
788 const struct wpabuf
*req
,
789 const u8
*mac
, const u8
*extra
,
792 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
)
793 return eap_sim_verify_mac_sha256(data
->k_aut
, req
, mac
, extra
,
795 return eap_sim_verify_mac(data
->k_aut
, req
, mac
, extra
, extra_len
);
799 static void eap_aka_process_challenge(struct eap_sm
*sm
,
800 struct eap_aka_data
*data
,
801 struct wpabuf
*respData
,
802 struct eap_sim_attrs
*attr
)
807 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Challenge");
809 #ifdef EAP_SERVER_AKA_PRIME
811 /* KDF negotiation; to be enabled only after more than one KDF is
813 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
&&
814 attr
->kdf_count
== 1 && attr
->mac
== NULL
) {
815 if (attr
->kdf
[0] != EAP_AKA_PRIME_KDF
) {
816 wpa_printf(MSG_WARNING
, "EAP-AKA': Peer selected "
819 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
820 eap_aka_state(data
, NOTIFICATION
);
824 data
->kdf
= attr
->kdf
[0];
826 /* Allow negotiation to continue with the selected KDF by
827 * sending another Challenge message */
828 wpa_printf(MSG_DEBUG
, "EAP-AKA': KDF %d selected", data
->kdf
);
832 #endif /* EAP_SERVER_AKA_PRIME */
834 if (attr
->checkcode
&&
835 eap_aka_verify_checkcode(data
, attr
->checkcode
,
836 attr
->checkcode_len
)) {
837 wpa_printf(MSG_WARNING
, "EAP-AKA: Invalid AT_CHECKCODE in the "
839 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
840 eap_aka_state(data
, NOTIFICATION
);
843 if (attr
->mac
== NULL
||
844 eap_aka_verify_mac(data
, respData
, attr
->mac
, NULL
, 0)) {
845 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
846 "did not include valid AT_MAC");
847 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
848 eap_aka_state(data
, NOTIFICATION
);
853 * AT_RES is padded, so verify that there is enough room for RES and
854 * that the RES length in bits matches with the expected RES.
856 if (attr
->res
== NULL
|| attr
->res_len
< data
->res_len
||
857 attr
->res_len_bits
!= data
->res_len
* 8 ||
858 os_memcmp(attr
->res
, data
->res
, data
->res_len
) != 0) {
859 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message did not "
860 "include valid AT_RES (attr len=%lu, res len=%lu "
861 "bits, expected %lu bits)",
862 (unsigned long) attr
->res_len
,
863 (unsigned long) attr
->res_len_bits
,
864 (unsigned long) data
->res_len
* 8);
865 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
866 eap_aka_state(data
, NOTIFICATION
);
870 wpa_printf(MSG_DEBUG
, "EAP-AKA: Challenge response includes the "
872 if (sm
->eap_sim_aka_result_ind
&& attr
->result_ind
) {
873 data
->use_result_ind
= 1;
874 data
->notification
= EAP_SIM_SUCCESS
;
875 eap_aka_state(data
, NOTIFICATION
);
877 eap_aka_state(data
, SUCCESS
);
879 identity
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
, sm
->identity
,
880 sm
->identity_len
, &identity_len
);
881 if (identity
== NULL
) {
882 identity
= sm
->identity
;
883 identity_len
= sm
->identity_len
;
886 if (data
->next_pseudonym
) {
887 eap_sim_db_add_pseudonym(sm
->eap_sim_db_priv
, identity
,
889 data
->next_pseudonym
);
890 data
->next_pseudonym
= NULL
;
892 if (data
->next_reauth_id
) {
893 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
894 #ifdef EAP_SERVER_AKA_PRIME
895 eap_sim_db_add_reauth_prime(sm
->eap_sim_db_priv
,
898 data
->next_reauth_id
,
900 data
->k_encr
, data
->k_aut
,
902 #endif /* EAP_SERVER_AKA_PRIME */
904 eap_sim_db_add_reauth(sm
->eap_sim_db_priv
, identity
,
906 data
->next_reauth_id
,
910 data
->next_reauth_id
= NULL
;
915 static void eap_aka_process_sync_failure(struct eap_sm
*sm
,
916 struct eap_aka_data
*data
,
917 struct wpabuf
*respData
,
918 struct eap_sim_attrs
*attr
)
920 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Synchronization-Failure");
922 if (attr
->auts
== NULL
) {
923 wpa_printf(MSG_WARNING
, "EAP-AKA: Synchronization-Failure "
924 "message did not include valid AT_AUTS");
925 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
926 eap_aka_state(data
, NOTIFICATION
);
930 /* Avoid re-reporting AUTS when processing pending EAP packet by
931 * maintaining a local flag stating whether this AUTS has already been
933 if (!data
->auts_reported
&&
934 eap_sim_db_resynchronize(sm
->eap_sim_db_priv
, sm
->identity
,
935 sm
->identity_len
, attr
->auts
,
937 wpa_printf(MSG_WARNING
, "EAP-AKA: Resynchronization failed");
938 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
939 eap_aka_state(data
, NOTIFICATION
);
942 data
->auts_reported
= 1;
944 /* Try again after resynchronization */
945 eap_aka_determine_identity(sm
, data
, 0, 0);
949 static void eap_aka_process_reauth(struct eap_sm
*sm
,
950 struct eap_aka_data
*data
,
951 struct wpabuf
*respData
,
952 struct eap_sim_attrs
*attr
)
954 struct eap_sim_attrs eattr
;
955 u8
*decrypted
= NULL
;
956 const u8
*identity
, *id2
;
957 size_t identity_len
, id2_len
;
959 wpa_printf(MSG_DEBUG
, "EAP-AKA: Processing Reauthentication");
961 if (attr
->mac
== NULL
||
962 eap_aka_verify_mac(data
, respData
, attr
->mac
, data
->nonce_s
,
963 EAP_SIM_NONCE_S_LEN
)) {
964 wpa_printf(MSG_WARNING
, "EAP-AKA: Re-authentication message "
965 "did not include valid AT_MAC");
969 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
970 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
971 "message did not include encrypted data");
975 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
976 attr
->encr_data_len
, attr
->iv
, &eattr
,
978 if (decrypted
== NULL
) {
979 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
980 "data from reauthentication message");
984 if (eattr
.counter
!= data
->counter
) {
985 wpa_printf(MSG_WARNING
, "EAP-AKA: Re-authentication message "
986 "used incorrect counter %u, expected %u",
987 eattr
.counter
, data
->counter
);
993 wpa_printf(MSG_DEBUG
, "EAP-AKA: Re-authentication response includes "
994 "the correct AT_MAC");
996 if (eattr
.counter_too_small
) {
997 wpa_printf(MSG_DEBUG
, "EAP-AKA: Re-authentication response "
998 "included AT_COUNTER_TOO_SMALL - starting full "
1000 eap_aka_determine_identity(sm
, data
, 0, 1);
1004 if (sm
->eap_sim_aka_result_ind
&& attr
->result_ind
) {
1005 data
->use_result_ind
= 1;
1006 data
->notification
= EAP_SIM_SUCCESS
;
1007 eap_aka_state(data
, NOTIFICATION
);
1009 eap_aka_state(data
, SUCCESS
);
1012 identity
= data
->reauth
->identity
;
1013 identity_len
= data
->reauth
->identity_len
;
1015 identity
= sm
->identity
;
1016 identity_len
= sm
->identity_len
;
1019 id2
= eap_sim_db_get_permanent(sm
->eap_sim_db_priv
, identity
,
1020 identity_len
, &id2_len
);
1023 identity_len
= id2_len
;
1026 if (data
->next_pseudonym
) {
1027 eap_sim_db_add_pseudonym(sm
->eap_sim_db_priv
, identity
,
1028 identity_len
, data
->next_pseudonym
);
1029 data
->next_pseudonym
= NULL
;
1031 if (data
->next_reauth_id
) {
1032 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
1033 #ifdef EAP_SERVER_AKA_PRIME
1034 eap_sim_db_add_reauth_prime(sm
->eap_sim_db_priv
,
1037 data
->next_reauth_id
,
1039 data
->k_encr
, data
->k_aut
,
1041 #endif /* EAP_SERVER_AKA_PRIME */
1043 eap_sim_db_add_reauth(sm
->eap_sim_db_priv
, identity
,
1045 data
->next_reauth_id
,
1049 data
->next_reauth_id
= NULL
;
1051 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
1052 data
->reauth
= NULL
;
1058 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
1059 eap_aka_state(data
, NOTIFICATION
);
1060 eap_sim_db_remove_reauth(sm
->eap_sim_db_priv
, data
->reauth
);
1061 data
->reauth
= NULL
;
1066 static void eap_aka_process_client_error(struct eap_sm
*sm
,
1067 struct eap_aka_data
*data
,
1068 struct wpabuf
*respData
,
1069 struct eap_sim_attrs
*attr
)
1071 wpa_printf(MSG_DEBUG
, "EAP-AKA: Client reported error %d",
1072 attr
->client_error_code
);
1073 if (data
->notification
== EAP_SIM_SUCCESS
&& data
->use_result_ind
)
1074 eap_aka_state(data
, SUCCESS
);
1076 eap_aka_state(data
, FAILURE
);
1080 static void eap_aka_process_authentication_reject(
1081 struct eap_sm
*sm
, struct eap_aka_data
*data
,
1082 struct wpabuf
*respData
, struct eap_sim_attrs
*attr
)
1084 wpa_printf(MSG_DEBUG
, "EAP-AKA: Client rejected authentication");
1085 eap_aka_state(data
, FAILURE
);
1089 static void eap_aka_process_notification(struct eap_sm
*sm
,
1090 struct eap_aka_data
*data
,
1091 struct wpabuf
*respData
,
1092 struct eap_sim_attrs
*attr
)
1094 wpa_printf(MSG_DEBUG
, "EAP-AKA: Client replied to notification");
1095 if (data
->notification
== EAP_SIM_SUCCESS
&& data
->use_result_ind
)
1096 eap_aka_state(data
, SUCCESS
);
1098 eap_aka_state(data
, FAILURE
);
1102 static void eap_aka_process(struct eap_sm
*sm
, void *priv
,
1103 struct wpabuf
*respData
)
1105 struct eap_aka_data
*data
= priv
;
1106 const u8
*pos
, *end
;
1109 struct eap_sim_attrs attr
;
1111 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, data
->eap_method
, respData
,
1113 if (pos
== NULL
|| len
< 3)
1120 if (eap_aka_subtype_ok(data
, subtype
)) {
1121 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unrecognized or unexpected "
1122 "EAP-AKA Subtype in EAP Response");
1123 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
1124 eap_aka_state(data
, NOTIFICATION
);
1128 if (eap_sim_parse_attr(pos
, end
, &attr
,
1129 data
->eap_method
== EAP_TYPE_AKA_PRIME
? 2 : 1,
1131 wpa_printf(MSG_DEBUG
, "EAP-AKA: Failed to parse attributes");
1132 data
->notification
= EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH
;
1133 eap_aka_state(data
, NOTIFICATION
);
1137 if (subtype
== EAP_AKA_SUBTYPE_CLIENT_ERROR
) {
1138 eap_aka_process_client_error(sm
, data
, respData
, &attr
);
1142 if (subtype
== EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
) {
1143 eap_aka_process_authentication_reject(sm
, data
, respData
,
1148 switch (data
->state
) {
1150 eap_aka_process_identity(sm
, data
, respData
, &attr
);
1153 if (subtype
== EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
) {
1154 eap_aka_process_sync_failure(sm
, data
, respData
,
1157 eap_aka_process_challenge(sm
, data
, respData
, &attr
);
1161 eap_aka_process_reauth(sm
, data
, respData
, &attr
);
1164 eap_aka_process_notification(sm
, data
, respData
, &attr
);
1167 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown state %d in "
1168 "process", data
->state
);
1174 static Boolean
eap_aka_isDone(struct eap_sm
*sm
, void *priv
)
1176 struct eap_aka_data
*data
= priv
;
1177 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
1181 static u8
* eap_aka_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
1183 struct eap_aka_data
*data
= priv
;
1186 if (data
->state
!= SUCCESS
)
1189 key
= os_malloc(EAP_SIM_KEYING_DATA_LEN
);
1192 os_memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
1193 *len
= EAP_SIM_KEYING_DATA_LEN
;
1198 static u8
* eap_aka_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
1200 struct eap_aka_data
*data
= priv
;
1203 if (data
->state
!= SUCCESS
)
1206 key
= os_malloc(EAP_EMSK_LEN
);
1209 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
1210 *len
= EAP_EMSK_LEN
;
1215 static Boolean
eap_aka_isSuccess(struct eap_sm
*sm
, void *priv
)
1217 struct eap_aka_data
*data
= priv
;
1218 return data
->state
== SUCCESS
;
1222 int eap_server_aka_register(void)
1224 struct eap_method
*eap
;
1227 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
1228 EAP_VENDOR_IETF
, EAP_TYPE_AKA
, "AKA");
1232 eap
->init
= eap_aka_init
;
1233 eap
->reset
= eap_aka_reset
;
1234 eap
->buildReq
= eap_aka_buildReq
;
1235 eap
->check
= eap_aka_check
;
1236 eap
->process
= eap_aka_process
;
1237 eap
->isDone
= eap_aka_isDone
;
1238 eap
->getKey
= eap_aka_getKey
;
1239 eap
->isSuccess
= eap_aka_isSuccess
;
1240 eap
->get_emsk
= eap_aka_get_emsk
;
1242 ret
= eap_server_method_register(eap
);
1244 eap_server_method_free(eap
);
1249 #ifdef EAP_SERVER_AKA_PRIME
1250 int eap_server_aka_prime_register(void)
1252 struct eap_method
*eap
;
1255 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
1256 EAP_VENDOR_IETF
, EAP_TYPE_AKA_PRIME
,
1261 eap
->init
= eap_aka_prime_init
;
1262 eap
->reset
= eap_aka_reset
;
1263 eap
->buildReq
= eap_aka_buildReq
;
1264 eap
->check
= eap_aka_check
;
1265 eap
->process
= eap_aka_process
;
1266 eap
->isDone
= eap_aka_isDone
;
1267 eap
->getKey
= eap_aka_getKey
;
1268 eap
->isSuccess
= eap_aka_isSuccess
;
1269 eap
->get_emsk
= eap_aka_get_emsk
;
1271 ret
= eap_server_method_register(eap
);
1273 eap_server_method_free(eap
);
1277 #endif /* EAP_SERVER_AKA_PRIME */