2 * EAP peer method: EAP-AKA (RFC 4187)
3 * Copyright (c) 2004-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.
18 #include "eap_peer/eap_i.h"
19 #include "pcsc_funcs.h"
20 #include "eap_common/eap_sim_common.h"
26 u8 ik
[EAP_AKA_IK_LEN
], ck
[EAP_AKA_CK_LEN
], res
[EAP_AKA_RES_MAX_LEN
];
28 u8 nonce_s
[EAP_SIM_NONCE_S_LEN
];
29 u8 mk
[EAP_SIM_MK_LEN
];
30 u8 k_aut
[EAP_SIM_K_AUT_LEN
];
31 u8 k_encr
[EAP_SIM_K_ENCR_LEN
];
32 u8 msk
[EAP_SIM_KEYING_DATA_LEN
];
33 u8 emsk
[EAP_EMSK_LEN
];
34 u8 rand
[EAP_AKA_RAND_LEN
], autn
[EAP_AKA_AUTN_LEN
];
35 u8 auts
[EAP_AKA_AUTS_LEN
];
37 int num_id_req
, num_notification
;
43 unsigned int counter
, counter_too_small
;
44 u8
*last_eap_identity
;
45 size_t last_eap_identity_len
;
47 CONTINUE
, RESULT_SUCCESS
, RESULT_FAILURE
, SUCCESS
, FAILURE
50 struct wpabuf
*id_msgs
;
52 int result_ind
, use_result_ind
;
56 #ifndef CONFIG_NO_STDOUT_DEBUG
57 static const char * eap_aka_state_txt(int state
)
63 return "RESULT_SUCCESS";
65 return "RESULT_FAILURE";
74 #endif /* CONFIG_NO_STDOUT_DEBUG */
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
;
89 const char *phase1
= eap_get_config_phase1(sm
);
91 data
= os_zalloc(sizeof(*data
));
95 eap_aka_state(data
, CONTINUE
);
98 data
->result_ind
= phase1
&& os_strstr(phase1
, "result_ind=1") != NULL
;
104 static void eap_aka_deinit(struct eap_sm
*sm
, void *priv
)
106 struct eap_aka_data
*data
= priv
;
108 os_free(data
->pseudonym
);
109 os_free(data
->reauth_id
);
110 os_free(data
->last_eap_identity
);
111 wpabuf_free(data
->id_msgs
);
117 static int eap_aka_umts_auth(struct eap_sm
*sm
, struct eap_aka_data
*data
)
119 wpa_printf(MSG_DEBUG
, "EAP-AKA: UMTS authentication algorithm");
121 return scard_umts_auth(sm
->scard_ctx
, data
->rand
,
122 data
->autn
, data
->res
, &data
->res_len
,
123 data
->ik
, data
->ck
, data
->auts
);
124 #else /* PCSC_FUNCS */
125 /* These hardcoded Kc and SRES values are used for testing.
126 * Could consider making them configurable. */
127 os_memset(data
->res
, '2', EAP_AKA_RES_MAX_LEN
);
128 data
->res_len
= EAP_AKA_RES_MAX_LEN
;
129 os_memset(data
->ik
, '3', EAP_AKA_IK_LEN
);
130 os_memset(data
->ck
, '4', EAP_AKA_CK_LEN
);
132 u8 autn
[EAP_AKA_AUTN_LEN
];
133 os_memset(autn
, '1', EAP_AKA_AUTN_LEN
);
134 if (os_memcmp(autn
, data
->autn
, EAP_AKA_AUTN_LEN
) != 0) {
135 wpa_printf(MSG_WARNING
, "EAP-AKA: AUTN did not match "
136 "with expected value");
142 static int test_resync
= 1;
144 /* Test Resynchronization */
151 #endif /* PCSC_FUNCS */
155 #define CLEAR_PSEUDONYM 0x01
156 #define CLEAR_REAUTH_ID 0x02
157 #define CLEAR_EAP_ID 0x04
159 static void eap_aka_clear_identities(struct eap_aka_data
*data
, int id
)
161 wpa_printf(MSG_DEBUG
, "EAP-AKA: forgetting old%s%s%s",
162 id
& CLEAR_PSEUDONYM
? " pseudonym" : "",
163 id
& CLEAR_REAUTH_ID
? " reauth_id" : "",
164 id
& CLEAR_EAP_ID
? " eap_id" : "");
165 if (id
& CLEAR_PSEUDONYM
) {
166 os_free(data
->pseudonym
);
167 data
->pseudonym
= NULL
;
168 data
->pseudonym_len
= 0;
170 if (id
& CLEAR_REAUTH_ID
) {
171 os_free(data
->reauth_id
);
172 data
->reauth_id
= NULL
;
173 data
->reauth_id_len
= 0;
175 if (id
& CLEAR_EAP_ID
) {
176 os_free(data
->last_eap_identity
);
177 data
->last_eap_identity
= NULL
;
178 data
->last_eap_identity_len
= 0;
183 static int eap_aka_learn_ids(struct eap_aka_data
*data
,
184 struct eap_sim_attrs
*attr
)
186 if (attr
->next_pseudonym
) {
187 os_free(data
->pseudonym
);
188 data
->pseudonym
= os_malloc(attr
->next_pseudonym_len
);
189 if (data
->pseudonym
== NULL
) {
190 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No memory for "
194 os_memcpy(data
->pseudonym
, attr
->next_pseudonym
,
195 attr
->next_pseudonym_len
);
196 data
->pseudonym_len
= attr
->next_pseudonym_len
;
197 wpa_hexdump_ascii(MSG_DEBUG
,
198 "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
200 data
->pseudonym_len
);
203 if (attr
->next_reauth_id
) {
204 os_free(data
->reauth_id
);
205 data
->reauth_id
= os_malloc(attr
->next_reauth_id_len
);
206 if (data
->reauth_id
== NULL
) {
207 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No memory for "
211 os_memcpy(data
->reauth_id
, attr
->next_reauth_id
,
212 attr
->next_reauth_id_len
);
213 data
->reauth_id_len
= attr
->next_reauth_id_len
;
214 wpa_hexdump_ascii(MSG_DEBUG
,
215 "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
217 data
->reauth_id_len
);
224 static int eap_aka_add_id_msg(struct eap_aka_data
*data
,
225 const struct wpabuf
*msg
)
230 if (data
->id_msgs
== NULL
) {
231 data
->id_msgs
= wpabuf_dup(msg
);
232 return data
->id_msgs
== NULL
? -1 : 0;
235 if (wpabuf_resize(&data
->id_msgs
, wpabuf_len(msg
)) < 0)
237 wpabuf_put_buf(data
->id_msgs
, msg
);
243 static void eap_aka_add_checkcode(struct eap_aka_data
*data
,
244 struct eap_sim_msg
*msg
)
248 u8 hash
[SHA1_MAC_LEN
];
250 wpa_printf(MSG_DEBUG
, " AT_CHECKCODE");
252 if (data
->id_msgs
== NULL
) {
254 * No EAP-AKA/Identity packets were exchanged - send empty
257 eap_sim_msg_add(msg
, EAP_SIM_AT_CHECKCODE
, 0, NULL
, 0);
261 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
262 addr
= wpabuf_head(data
->id_msgs
);
263 len
= wpabuf_len(data
->id_msgs
);
264 wpa_hexdump(MSG_MSGDUMP
, "EAP-AKA: AT_CHECKCODE data", addr
, len
);
265 sha1_vector(1, &addr
, &len
, hash
);
267 eap_sim_msg_add(msg
, EAP_SIM_AT_CHECKCODE
, 0, hash
,
268 EAP_AKA_CHECKCODE_LEN
);
272 static int eap_aka_verify_checkcode(struct eap_aka_data
*data
,
273 const u8
*checkcode
, size_t checkcode_len
)
277 u8 hash
[SHA1_MAC_LEN
];
279 if (checkcode
== NULL
)
282 if (data
->id_msgs
== NULL
) {
283 if (checkcode_len
!= 0) {
284 wpa_printf(MSG_DEBUG
, "EAP-AKA: Checkcode from server "
285 "indicates that AKA/Identity messages were "
286 "used, but they were not");
292 if (checkcode_len
!= EAP_AKA_CHECKCODE_LEN
) {
293 wpa_printf(MSG_DEBUG
, "EAP-AKA: Checkcode from server "
294 "indicates that AKA/Identity message were not "
295 "used, but they were");
299 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
300 addr
= wpabuf_head(data
->id_msgs
);
301 len
= wpabuf_len(data
->id_msgs
);
302 sha1_vector(1, &addr
, &len
, hash
);
304 if (os_memcmp(hash
, checkcode
, EAP_AKA_CHECKCODE_LEN
) != 0) {
305 wpa_printf(MSG_DEBUG
, "EAP-AKA: Mismatch in AT_CHECKCODE");
313 static struct wpabuf
* eap_aka_client_error(struct eap_aka_data
*data
, u8 id
,
316 struct eap_sim_msg
*msg
;
318 eap_aka_state(data
, FAILURE
);
319 data
->num_id_req
= 0;
320 data
->num_notification
= 0;
322 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, EAP_TYPE_AKA
,
323 EAP_AKA_SUBTYPE_CLIENT_ERROR
);
324 eap_sim_msg_add(msg
, EAP_SIM_AT_CLIENT_ERROR_CODE
, err
, NULL
, 0);
325 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
329 static struct wpabuf
* eap_aka_authentication_reject(struct eap_aka_data
*data
,
332 struct eap_sim_msg
*msg
;
334 eap_aka_state(data
, FAILURE
);
335 data
->num_id_req
= 0;
336 data
->num_notification
= 0;
338 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Authentication-Reject "
340 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, EAP_TYPE_AKA
,
341 EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
);
342 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
346 static struct wpabuf
* eap_aka_synchronization_failure(
347 struct eap_aka_data
*data
, u8 id
)
349 struct eap_sim_msg
*msg
;
351 data
->num_id_req
= 0;
352 data
->num_notification
= 0;
354 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Synchronization-Failure "
356 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, EAP_TYPE_AKA
,
357 EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
);
358 wpa_printf(MSG_DEBUG
, " AT_AUTS");
359 eap_sim_msg_add_full(msg
, EAP_SIM_AT_AUTS
, data
->auts
,
361 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
365 static struct wpabuf
* eap_aka_response_identity(struct eap_sm
*sm
,
366 struct eap_aka_data
*data
,
368 enum eap_sim_id_req id_req
)
370 const u8
*identity
= NULL
;
371 size_t identity_len
= 0;
372 struct eap_sim_msg
*msg
;
375 if (id_req
== ANY_ID
&& data
->reauth_id
) {
376 identity
= data
->reauth_id
;
377 identity_len
= data
->reauth_id_len
;
379 } else if ((id_req
== ANY_ID
|| id_req
== FULLAUTH_ID
) &&
381 identity
= data
->pseudonym
;
382 identity_len
= data
->pseudonym_len
;
383 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
);
384 } else if (id_req
!= NO_ID_REQ
) {
385 identity
= eap_get_config_identity(sm
, &identity_len
);
387 eap_aka_clear_identities(data
, CLEAR_PSEUDONYM
|
391 if (id_req
!= NO_ID_REQ
)
392 eap_aka_clear_identities(data
, CLEAR_EAP_ID
);
394 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Identity (id=%d)", id
);
395 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, EAP_TYPE_AKA
,
396 EAP_AKA_SUBTYPE_IDENTITY
);
399 wpa_hexdump_ascii(MSG_DEBUG
, " AT_IDENTITY",
400 identity
, identity_len
);
401 eap_sim_msg_add(msg
, EAP_SIM_AT_IDENTITY
, identity_len
,
402 identity
, identity_len
);
405 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
409 static struct wpabuf
* eap_aka_response_challenge(struct eap_aka_data
*data
,
412 struct eap_sim_msg
*msg
;
414 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Challenge (id=%d)", id
);
415 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, EAP_TYPE_AKA
,
416 EAP_AKA_SUBTYPE_CHALLENGE
);
417 wpa_printf(MSG_DEBUG
, " AT_RES");
418 eap_sim_msg_add(msg
, EAP_SIM_AT_RES
, data
->res_len
,
419 data
->res
, data
->res_len
);
420 eap_aka_add_checkcode(data
, msg
);
421 if (data
->use_result_ind
) {
422 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
423 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
425 wpa_printf(MSG_DEBUG
, " AT_MAC");
426 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
427 return eap_sim_msg_finish(msg
, data
->k_aut
, (u8
*) "", 0);
431 static struct wpabuf
* eap_aka_response_reauth(struct eap_aka_data
*data
,
432 u8 id
, int counter_too_small
,
435 struct eap_sim_msg
*msg
;
436 unsigned int counter
;
438 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Reauthentication (id=%d)",
440 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, EAP_TYPE_AKA
,
441 EAP_AKA_SUBTYPE_REAUTHENTICATION
);
442 wpa_printf(MSG_DEBUG
, " AT_IV");
443 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
444 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
, EAP_SIM_AT_ENCR_DATA
);
446 if (counter_too_small
) {
447 wpa_printf(MSG_DEBUG
, " *AT_COUNTER_TOO_SMALL");
448 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER_TOO_SMALL
, 0, NULL
, 0);
449 counter
= data
->counter_too_small
;
451 counter
= data
->counter
;
453 wpa_printf(MSG_DEBUG
, " *AT_COUNTER %d", counter
);
454 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
456 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
, EAP_SIM_AT_PADDING
)) {
457 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
459 eap_sim_msg_free(msg
);
462 eap_aka_add_checkcode(data
, msg
);
463 if (data
->use_result_ind
) {
464 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
465 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
467 wpa_printf(MSG_DEBUG
, " AT_MAC");
468 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
469 return eap_sim_msg_finish(msg
, data
->k_aut
, nonce_s
,
470 EAP_SIM_NONCE_S_LEN
);
474 static struct wpabuf
* eap_aka_response_notification(struct eap_aka_data
*data
,
475 u8 id
, u16 notification
)
477 struct eap_sim_msg
*msg
;
478 u8
*k_aut
= (notification
& 0x4000) == 0 ? data
->k_aut
: NULL
;
480 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Notification (id=%d)", id
);
481 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, EAP_TYPE_AKA
,
482 EAP_AKA_SUBTYPE_NOTIFICATION
);
483 if (k_aut
&& data
->reauth
) {
484 wpa_printf(MSG_DEBUG
, " AT_IV");
485 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
486 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
,
487 EAP_SIM_AT_ENCR_DATA
);
488 wpa_printf(MSG_DEBUG
, " *AT_COUNTER %d", data
->counter
);
489 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, data
->counter
,
491 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
,
492 EAP_SIM_AT_PADDING
)) {
493 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
495 eap_sim_msg_free(msg
);
500 wpa_printf(MSG_DEBUG
, " AT_MAC");
501 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
503 return eap_sim_msg_finish(msg
, k_aut
, (u8
*) "", 0);
507 static struct wpabuf
* eap_aka_process_identity(struct eap_sm
*sm
,
508 struct eap_aka_data
*data
,
510 const struct wpabuf
*reqData
,
511 struct eap_sim_attrs
*attr
)
516 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Identity");
519 switch (attr
->id_req
) {
523 if (data
->num_id_req
> 0)
528 if (data
->num_id_req
> 1)
533 if (data
->num_id_req
> 2)
539 wpa_printf(MSG_INFO
, "EAP-AKA: Too many ID requests "
540 "used within one authentication");
541 return eap_aka_client_error(data
, id
,
542 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
545 buf
= eap_aka_response_identity(sm
, data
, id
, attr
->id_req
);
547 if (data
->prev_id
!= id
) {
548 eap_aka_add_id_msg(data
, reqData
);
549 eap_aka_add_id_msg(data
, buf
);
557 static struct wpabuf
* eap_aka_process_challenge(struct eap_sm
*sm
,
558 struct eap_aka_data
*data
,
560 const struct wpabuf
*reqData
,
561 struct eap_sim_attrs
*attr
)
566 struct eap_sim_attrs eattr
;
568 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Challenge");
570 if (attr
->checkcode
&&
571 eap_aka_verify_checkcode(data
, attr
->checkcode
,
572 attr
->checkcode_len
)) {
573 wpa_printf(MSG_WARNING
, "EAP-AKA: Invalid AT_CHECKCODE in the "
575 return eap_aka_client_error(data
, id
,
576 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
580 if (!attr
->mac
|| !attr
->rand
|| !attr
->autn
) {
581 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
582 "did not include%s%s%s",
583 !attr
->mac
? " AT_MAC" : "",
584 !attr
->rand
? " AT_RAND" : "",
585 !attr
->autn
? " AT_AUTN" : "");
586 return eap_aka_client_error(data
, id
,
587 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
589 os_memcpy(data
->rand
, attr
->rand
, EAP_AKA_RAND_LEN
);
590 os_memcpy(data
->autn
, attr
->autn
, EAP_AKA_AUTN_LEN
);
592 res
= eap_aka_umts_auth(sm
, data
);
594 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication "
596 return eap_aka_authentication_reject(data
, id
);
597 } else if (res
== -2) {
598 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication "
599 "failed (AUTN seq# -> AUTS)");
600 return eap_aka_synchronization_failure(data
, id
);
602 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication failed");
603 return eap_aka_client_error(data
, id
,
604 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
606 if (data
->last_eap_identity
) {
607 identity
= data
->last_eap_identity
;
608 identity_len
= data
->last_eap_identity_len
;
609 } else if (data
->pseudonym
) {
610 identity
= data
->pseudonym
;
611 identity_len
= data
->pseudonym_len
;
613 identity
= eap_get_config_identity(sm
, &identity_len
);
614 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA: Selected identity for MK "
615 "derivation", identity
, identity_len
);
616 eap_aka_derive_mk(identity
, identity_len
, data
->ik
, data
->ck
,
618 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
,
620 if (eap_sim_verify_mac(data
->k_aut
, reqData
, attr
->mac
, (u8
*) "", 0))
622 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
623 "used invalid AT_MAC");
624 return eap_aka_client_error(data
, id
,
625 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
628 /* Old reauthentication and pseudonym identities must not be used
629 * anymore. In other words, if no new identities are received, full
630 * authentication will be used on next reauthentication. */
631 eap_aka_clear_identities(data
, CLEAR_PSEUDONYM
| CLEAR_REAUTH_ID
|
634 if (attr
->encr_data
) {
636 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
637 attr
->encr_data_len
, attr
->iv
,
639 if (decrypted
== NULL
) {
640 return eap_aka_client_error(
641 data
, id
, EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
643 eap_aka_learn_ids(data
, &eattr
);
647 if (data
->result_ind
&& attr
->result_ind
)
648 data
->use_result_ind
= 1;
650 if (data
->state
!= FAILURE
&& data
->state
!= RESULT_FAILURE
) {
651 eap_aka_state(data
, data
->use_result_ind
?
652 RESULT_SUCCESS
: SUCCESS
);
655 data
->num_id_req
= 0;
656 data
->num_notification
= 0;
657 /* RFC 4187 specifies that counter is initialized to one after
658 * fullauth, but initializing it to zero makes it easier to implement
659 * reauth verification. */
661 return eap_aka_response_challenge(data
, id
);
665 static int eap_aka_process_notification_reauth(struct eap_aka_data
*data
,
666 struct eap_sim_attrs
*attr
)
668 struct eap_sim_attrs eattr
;
671 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
672 wpa_printf(MSG_WARNING
, "EAP-AKA: Notification message after "
673 "reauth did not include encrypted data");
677 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
678 attr
->encr_data_len
, attr
->iv
, &eattr
,
680 if (decrypted
== NULL
) {
681 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
682 "data from notification message");
686 if (eattr
.counter
< 0 || (size_t) eattr
.counter
!= data
->counter
) {
687 wpa_printf(MSG_WARNING
, "EAP-AKA: Counter in notification "
688 "message does not match with counter in reauth "
699 static int eap_aka_process_notification_auth(struct eap_aka_data
*data
,
700 const struct wpabuf
*reqData
,
701 struct eap_sim_attrs
*attr
)
703 if (attr
->mac
== NULL
) {
704 wpa_printf(MSG_INFO
, "EAP-AKA: no AT_MAC in after_auth "
705 "Notification message");
709 if (eap_sim_verify_mac(data
->k_aut
, reqData
, attr
->mac
, (u8
*) "", 0))
711 wpa_printf(MSG_WARNING
, "EAP-AKA: Notification message "
712 "used invalid AT_MAC");
717 eap_aka_process_notification_reauth(data
, attr
)) {
718 wpa_printf(MSG_WARNING
, "EAP-AKA: Invalid notification "
719 "message after reauth");
727 static struct wpabuf
* eap_aka_process_notification(
728 struct eap_sm
*sm
, struct eap_aka_data
*data
, u8 id
,
729 const struct wpabuf
*reqData
, struct eap_sim_attrs
*attr
)
731 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Notification");
732 if (data
->num_notification
> 0) {
733 wpa_printf(MSG_INFO
, "EAP-AKA: too many notification "
734 "rounds (only one allowed)");
735 return eap_aka_client_error(data
, id
,
736 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
738 data
->num_notification
++;
739 if (attr
->notification
== -1) {
740 wpa_printf(MSG_INFO
, "EAP-AKA: no AT_NOTIFICATION in "
741 "Notification message");
742 return eap_aka_client_error(data
, id
,
743 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
746 if ((attr
->notification
& 0x4000) == 0 &&
747 eap_aka_process_notification_auth(data
, reqData
, attr
)) {
748 return eap_aka_client_error(data
, id
,
749 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
752 eap_sim_report_notification(sm
->msg_ctx
, attr
->notification
, 1);
753 if (attr
->notification
>= 0 && attr
->notification
< 32768) {
754 eap_aka_state(data
, FAILURE
);
755 } else if (attr
->notification
== EAP_SIM_SUCCESS
&&
756 data
->state
== RESULT_SUCCESS
)
757 eap_aka_state(data
, SUCCESS
);
758 return eap_aka_response_notification(data
, id
, attr
->notification
);
762 static struct wpabuf
* eap_aka_process_reauthentication(
763 struct eap_sm
*sm
, struct eap_aka_data
*data
, u8 id
,
764 const struct wpabuf
*reqData
, struct eap_sim_attrs
*attr
)
766 struct eap_sim_attrs eattr
;
769 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Reauthentication");
771 if (attr
->checkcode
&&
772 eap_aka_verify_checkcode(data
, attr
->checkcode
,
773 attr
->checkcode_len
)) {
774 wpa_printf(MSG_WARNING
, "EAP-AKA: Invalid AT_CHECKCODE in the "
776 return eap_aka_client_error(data
, id
,
777 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
780 if (data
->reauth_id
== NULL
) {
781 wpa_printf(MSG_WARNING
, "EAP-AKA: Server is trying "
782 "reauthentication, but no reauth_id available");
783 return eap_aka_client_error(data
, id
,
784 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
788 if (eap_sim_verify_mac(data
->k_aut
, reqData
, attr
->mac
, (u8
*) "", 0))
790 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
791 "did not have valid AT_MAC");
792 return eap_aka_client_error(data
, id
,
793 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
796 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
797 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
798 "message did not include encrypted data");
799 return eap_aka_client_error(data
, id
,
800 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
803 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
804 attr
->encr_data_len
, attr
->iv
, &eattr
,
806 if (decrypted
== NULL
) {
807 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
808 "data from reauthentication message");
809 return eap_aka_client_error(data
, id
,
810 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
813 if (eattr
.nonce_s
== NULL
|| eattr
.counter
< 0) {
814 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No%s%s in reauth packet",
815 !eattr
.nonce_s
? " AT_NONCE_S" : "",
816 eattr
.counter
< 0 ? " AT_COUNTER" : "");
818 return eap_aka_client_error(data
, id
,
819 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
822 if (eattr
.counter
< 0 || (size_t) eattr
.counter
<= data
->counter
) {
824 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) Invalid counter "
825 "(%d <= %d)", eattr
.counter
, data
->counter
);
826 data
->counter_too_small
= eattr
.counter
;
828 eap_sim_derive_keys_reauth(eattr
.counter
, data
->reauth_id
,
829 data
->reauth_id_len
, eattr
.nonce_s
,
830 data
->mk
, NULL
, NULL
);
832 /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
833 * reauth_id must not be used to start a new reauthentication.
834 * However, since it was used in the last EAP-Response-Identity
835 * packet, it has to saved for the following fullauth to be
836 * used in MK derivation. */
837 os_free(data
->last_eap_identity
);
838 data
->last_eap_identity
= data
->reauth_id
;
839 data
->last_eap_identity_len
= data
->reauth_id_len
;
840 data
->reauth_id
= NULL
;
841 data
->reauth_id_len
= 0;
843 res
= eap_aka_response_reauth(data
, id
, 1, eattr
.nonce_s
);
848 data
->counter
= eattr
.counter
;
850 os_memcpy(data
->nonce_s
, eattr
.nonce_s
, EAP_SIM_NONCE_S_LEN
);
851 wpa_hexdump(MSG_DEBUG
, "EAP-AKA: (encr) AT_NONCE_S",
852 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
);
854 eap_sim_derive_keys_reauth(data
->counter
,
855 data
->reauth_id
, data
->reauth_id_len
,
856 data
->nonce_s
, data
->mk
, data
->msk
,
858 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
| CLEAR_EAP_ID
);
859 eap_aka_learn_ids(data
, &eattr
);
861 if (data
->result_ind
&& attr
->result_ind
)
862 data
->use_result_ind
= 1;
864 if (data
->state
!= FAILURE
&& data
->state
!= RESULT_FAILURE
) {
865 eap_aka_state(data
, data
->use_result_ind
?
866 RESULT_SUCCESS
: SUCCESS
);
869 data
->num_id_req
= 0;
870 data
->num_notification
= 0;
871 if (data
->counter
> EAP_AKA_MAX_FAST_REAUTHS
) {
872 wpa_printf(MSG_DEBUG
, "EAP-AKA: Maximum number of "
873 "fast reauths performed - force fullauth");
874 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
| CLEAR_EAP_ID
);
877 return eap_aka_response_reauth(data
, id
, 0, data
->nonce_s
);
881 static struct wpabuf
* eap_aka_process(struct eap_sm
*sm
, void *priv
,
882 struct eap_method_ret
*ret
,
883 const struct wpabuf
*reqData
)
885 struct eap_aka_data
*data
= priv
;
886 const struct eap_hdr
*req
;
890 struct eap_sim_attrs attr
;
893 wpa_hexdump_buf(MSG_DEBUG
, "EAP-AKA: EAP data", reqData
);
894 if (eap_get_config_identity(sm
, &len
) == NULL
) {
895 wpa_printf(MSG_INFO
, "EAP-AKA: Identity not configured");
896 eap_sm_request_identity(sm
);
901 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_AKA
, reqData
, &len
);
902 if (pos
== NULL
|| len
< 1) {
906 req
= wpabuf_head(reqData
);
907 id
= req
->identifier
;
908 len
= be_to_host16(req
->length
);
911 ret
->methodState
= METHOD_MAY_CONT
;
912 ret
->decision
= DECISION_FAIL
;
913 ret
->allowNotifications
= TRUE
;
916 wpa_printf(MSG_DEBUG
, "EAP-AKA: Subtype=%d", subtype
);
917 pos
+= 2; /* Reserved */
919 if (eap_sim_parse_attr(pos
, wpabuf_head_u8(reqData
) + len
, &attr
, 1,
921 res
= eap_aka_client_error(data
, id
,
922 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
927 case EAP_AKA_SUBTYPE_IDENTITY
:
928 res
= eap_aka_process_identity(sm
, data
, id
, reqData
, &attr
);
930 case EAP_AKA_SUBTYPE_CHALLENGE
:
931 res
= eap_aka_process_challenge(sm
, data
, id
, reqData
, &attr
);
933 case EAP_AKA_SUBTYPE_NOTIFICATION
:
934 res
= eap_aka_process_notification(sm
, data
, id
, reqData
,
937 case EAP_AKA_SUBTYPE_REAUTHENTICATION
:
938 res
= eap_aka_process_reauthentication(sm
, data
, id
, reqData
,
941 case EAP_AKA_SUBTYPE_CLIENT_ERROR
:
942 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Client-Error");
943 res
= eap_aka_client_error(data
, id
,
944 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
947 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown subtype=%d", subtype
);
948 res
= eap_aka_client_error(data
, id
,
949 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
954 if (data
->state
== FAILURE
) {
955 ret
->decision
= DECISION_FAIL
;
956 ret
->methodState
= METHOD_DONE
;
957 } else if (data
->state
== SUCCESS
) {
958 ret
->decision
= data
->use_result_ind
?
959 DECISION_UNCOND_SUCC
: DECISION_COND_SUCC
;
961 * It is possible for the server to reply with AKA
962 * Notification, so we must allow the method to continue and
963 * not only accept EAP-Success at this point.
965 ret
->methodState
= data
->use_result_ind
?
966 METHOD_DONE
: METHOD_MAY_CONT
;
967 } else if (data
->state
== RESULT_FAILURE
)
968 ret
->methodState
= METHOD_CONT
;
969 else if (data
->state
== RESULT_SUCCESS
)
970 ret
->methodState
= METHOD_CONT
;
972 if (ret
->methodState
== METHOD_DONE
) {
973 ret
->allowNotifications
= FALSE
;
980 static Boolean
eap_aka_has_reauth_data(struct eap_sm
*sm
, void *priv
)
982 struct eap_aka_data
*data
= priv
;
983 return data
->pseudonym
|| data
->reauth_id
;
987 static void eap_aka_deinit_for_reauth(struct eap_sm
*sm
, void *priv
)
989 struct eap_aka_data
*data
= priv
;
990 eap_aka_clear_identities(data
, CLEAR_EAP_ID
);
992 wpabuf_free(data
->id_msgs
);
993 data
->id_msgs
= NULL
;
994 data
->use_result_ind
= 0;
998 static void * eap_aka_init_for_reauth(struct eap_sm
*sm
, void *priv
)
1000 struct eap_aka_data
*data
= priv
;
1001 data
->num_id_req
= 0;
1002 data
->num_notification
= 0;
1003 eap_aka_state(data
, CONTINUE
);
1008 static const u8
* eap_aka_get_identity(struct eap_sm
*sm
, void *priv
,
1011 struct eap_aka_data
*data
= priv
;
1013 if (data
->reauth_id
) {
1014 *len
= data
->reauth_id_len
;
1015 return data
->reauth_id
;
1018 if (data
->pseudonym
) {
1019 *len
= data
->pseudonym_len
;
1020 return data
->pseudonym
;
1027 static Boolean
eap_aka_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
1029 struct eap_aka_data
*data
= priv
;
1030 return data
->state
== SUCCESS
;
1034 static u8
* eap_aka_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
1036 struct eap_aka_data
*data
= priv
;
1039 if (data
->state
!= SUCCESS
)
1042 key
= os_malloc(EAP_SIM_KEYING_DATA_LEN
);
1046 *len
= EAP_SIM_KEYING_DATA_LEN
;
1047 os_memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
1053 static u8
* eap_aka_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
1055 struct eap_aka_data
*data
= priv
;
1058 if (data
->state
!= SUCCESS
)
1061 key
= os_malloc(EAP_EMSK_LEN
);
1065 *len
= EAP_EMSK_LEN
;
1066 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
1072 int eap_peer_aka_register(void)
1074 struct eap_method
*eap
;
1077 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
1078 EAP_VENDOR_IETF
, EAP_TYPE_AKA
, "AKA");
1082 eap
->init
= eap_aka_init
;
1083 eap
->deinit
= eap_aka_deinit
;
1084 eap
->process
= eap_aka_process
;
1085 eap
->isKeyAvailable
= eap_aka_isKeyAvailable
;
1086 eap
->getKey
= eap_aka_getKey
;
1087 eap
->has_reauth_data
= eap_aka_has_reauth_data
;
1088 eap
->deinit_for_reauth
= eap_aka_deinit_for_reauth
;
1089 eap
->init_for_reauth
= eap_aka_init_for_reauth
;
1090 eap
->get_identity
= eap_aka_get_identity
;
1091 eap
->get_emsk
= eap_aka_get_emsk
;
1093 ret
= eap_peer_method_register(eap
);
1095 eap_peer_method_free(eap
);