2 * EAP peer method: EAP-AKA (RFC 4187)
3 * Copyright (c) 2004-2006, 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.
20 #include "pcsc_funcs.h"
21 #include "eap_sim_common.h"
25 u8 ik
[EAP_AKA_IK_LEN
], ck
[EAP_AKA_CK_LEN
], res
[EAP_AKA_RES_MAX_LEN
];
27 u8 nonce_s
[EAP_SIM_NONCE_S_LEN
];
28 u8 mk
[EAP_SIM_MK_LEN
];
29 u8 k_aut
[EAP_SIM_K_AUT_LEN
];
30 u8 k_encr
[EAP_SIM_K_ENCR_LEN
];
31 u8 msk
[EAP_SIM_KEYING_DATA_LEN
];
32 u8 emsk
[EAP_EMSK_LEN
];
33 u8 rand
[EAP_AKA_RAND_LEN
], autn
[EAP_AKA_AUTN_LEN
];
34 u8 auts
[EAP_AKA_AUTS_LEN
];
36 int num_id_req
, num_notification
;
42 unsigned int counter
, counter_too_small
;
43 u8
*last_eap_identity
;
44 size_t last_eap_identity_len
;
45 enum { CONTINUE
, SUCCESS
, FAILURE
} state
;
49 static void * eap_aka_init(struct eap_sm
*sm
)
51 struct eap_aka_data
*data
;
52 data
= os_zalloc(sizeof(*data
));
56 data
->state
= CONTINUE
;
62 static void eap_aka_deinit(struct eap_sm
*sm
, void *priv
)
64 struct eap_aka_data
*data
= priv
;
66 os_free(data
->pseudonym
);
67 os_free(data
->reauth_id
);
68 os_free(data
->last_eap_identity
);
74 static int eap_aka_umts_auth(struct eap_sm
*sm
, struct eap_aka_data
*data
)
76 wpa_printf(MSG_DEBUG
, "EAP-AKA: UMTS authentication algorithm");
78 return scard_umts_auth(sm
->scard_ctx
, data
->rand
,
79 data
->autn
, data
->res
, &data
->res_len
,
80 data
->ik
, data
->ck
, data
->auts
);
81 #else /* PCSC_FUNCS */
82 /* These hardcoded Kc and SRES values are used for testing.
83 * Could consider making them configurable. */
84 os_memset(data
->res
, '2', EAP_AKA_RES_MAX_LEN
);
85 data
->res_len
= EAP_AKA_RES_MAX_LEN
;
86 os_memset(data
->ik
, '3', EAP_AKA_IK_LEN
);
87 os_memset(data
->ck
, '4', EAP_AKA_CK_LEN
);
89 u8 autn
[EAP_AKA_AUTN_LEN
];
90 os_memset(autn
, '1', EAP_AKA_AUTN_LEN
);
91 if (os_memcmp(autn
, data
->autn
, EAP_AKA_AUTN_LEN
) != 0) {
92 wpa_printf(MSG_WARNING
, "EAP-AKA: AUTN did not match "
93 "with expected value");
99 static int test_resync
= 1;
101 /* Test Resynchronization */
108 #endif /* PCSC_FUNCS */
112 #define CLEAR_PSEUDONYM 0x01
113 #define CLEAR_REAUTH_ID 0x02
114 #define CLEAR_EAP_ID 0x04
116 static void eap_aka_clear_identities(struct eap_aka_data
*data
, int id
)
118 wpa_printf(MSG_DEBUG
, "EAP-AKA: forgetting old%s%s%s",
119 id
& CLEAR_PSEUDONYM
? " pseudonym" : "",
120 id
& CLEAR_REAUTH_ID
? " reauth_id" : "",
121 id
& CLEAR_EAP_ID
? " eap_id" : "");
122 if (id
& CLEAR_PSEUDONYM
) {
123 os_free(data
->pseudonym
);
124 data
->pseudonym
= NULL
;
125 data
->pseudonym_len
= 0;
127 if (id
& CLEAR_REAUTH_ID
) {
128 os_free(data
->reauth_id
);
129 data
->reauth_id
= NULL
;
130 data
->reauth_id_len
= 0;
132 if (id
& CLEAR_EAP_ID
) {
133 os_free(data
->last_eap_identity
);
134 data
->last_eap_identity
= NULL
;
135 data
->last_eap_identity_len
= 0;
140 static int eap_aka_learn_ids(struct eap_aka_data
*data
,
141 struct eap_sim_attrs
*attr
)
143 if (attr
->next_pseudonym
) {
144 os_free(data
->pseudonym
);
145 data
->pseudonym
= os_malloc(attr
->next_pseudonym_len
);
146 if (data
->pseudonym
== NULL
) {
147 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No memory for "
151 os_memcpy(data
->pseudonym
, attr
->next_pseudonym
,
152 attr
->next_pseudonym_len
);
153 data
->pseudonym_len
= attr
->next_pseudonym_len
;
154 wpa_hexdump_ascii(MSG_DEBUG
,
155 "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
157 data
->pseudonym_len
);
160 if (attr
->next_reauth_id
) {
161 os_free(data
->reauth_id
);
162 data
->reauth_id
= os_malloc(attr
->next_reauth_id_len
);
163 if (data
->reauth_id
== NULL
) {
164 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No memory for "
168 os_memcpy(data
->reauth_id
, attr
->next_reauth_id
,
169 attr
->next_reauth_id_len
);
170 data
->reauth_id_len
= attr
->next_reauth_id_len
;
171 wpa_hexdump_ascii(MSG_DEBUG
,
172 "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
174 data
->reauth_id_len
);
181 static u8
* eap_aka_client_error(struct eap_aka_data
*data
,
182 const struct eap_hdr
*req
,
183 size_t *respDataLen
, int err
)
185 struct eap_sim_msg
*msg
;
187 data
->state
= FAILURE
;
188 data
->num_id_req
= 0;
189 data
->num_notification
= 0;
191 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
192 EAP_TYPE_AKA
, EAP_AKA_SUBTYPE_CLIENT_ERROR
);
193 eap_sim_msg_add(msg
, EAP_SIM_AT_CLIENT_ERROR_CODE
, err
, NULL
, 0);
194 return eap_sim_msg_finish(msg
, respDataLen
, NULL
, NULL
, 0);
198 static u8
* eap_aka_authentication_reject(struct eap_aka_data
*data
,
199 const struct eap_hdr
*req
,
202 struct eap_sim_msg
*msg
;
204 data
->state
= FAILURE
;
205 data
->num_id_req
= 0;
206 data
->num_notification
= 0;
208 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Authentication-Reject "
209 "(id=%d)", req
->identifier
);
210 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
212 EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
);
213 return eap_sim_msg_finish(msg
, respDataLen
, NULL
, NULL
, 0);
217 static u8
* eap_aka_synchronization_failure(struct eap_aka_data
*data
,
218 const struct eap_hdr
*req
,
221 struct eap_sim_msg
*msg
;
223 data
->num_id_req
= 0;
224 data
->num_notification
= 0;
226 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Synchronization-Failure "
227 "(id=%d)", req
->identifier
);
228 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
230 EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
);
231 wpa_printf(MSG_DEBUG
, " AT_AUTS");
232 eap_sim_msg_add_full(msg
, EAP_SIM_AT_AUTS
, data
->auts
,
234 return eap_sim_msg_finish(msg
, respDataLen
, NULL
, NULL
, 0);
238 static u8
* eap_aka_response_identity(struct eap_sm
*sm
,
239 struct eap_aka_data
*data
,
240 const struct eap_hdr
*req
,
242 enum eap_sim_id_req id_req
)
244 const u8
*identity
= NULL
;
245 size_t identity_len
= 0;
246 struct eap_sim_msg
*msg
;
249 if (id_req
== ANY_ID
&& data
->reauth_id
) {
250 identity
= data
->reauth_id
;
251 identity_len
= data
->reauth_id_len
;
253 } else if ((id_req
== ANY_ID
|| id_req
== FULLAUTH_ID
) &&
255 identity
= data
->pseudonym
;
256 identity_len
= data
->pseudonym_len
;
257 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
);
258 } else if (id_req
!= NO_ID_REQ
) {
259 identity
= eap_get_config_identity(sm
, &identity_len
);
261 eap_aka_clear_identities(data
, CLEAR_PSEUDONYM
|
265 if (id_req
!= NO_ID_REQ
)
266 eap_aka_clear_identities(data
, CLEAR_EAP_ID
);
268 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Identity (id=%d)",
270 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
271 EAP_TYPE_AKA
, EAP_AKA_SUBTYPE_IDENTITY
);
274 wpa_hexdump_ascii(MSG_DEBUG
, " AT_IDENTITY",
275 identity
, identity_len
);
276 eap_sim_msg_add(msg
, EAP_SIM_AT_IDENTITY
, identity_len
,
277 identity
, identity_len
);
280 return eap_sim_msg_finish(msg
, respDataLen
, NULL
, NULL
, 0);
284 static u8
* eap_aka_response_challenge(struct eap_aka_data
*data
,
285 const struct eap_hdr
*req
,
288 struct eap_sim_msg
*msg
;
290 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Challenge (id=%d)",
292 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
293 EAP_TYPE_AKA
, EAP_AKA_SUBTYPE_CHALLENGE
);
294 wpa_printf(MSG_DEBUG
, " AT_RES");
295 eap_sim_msg_add(msg
, EAP_SIM_AT_RES
, data
->res_len
,
296 data
->res
, data
->res_len
);
297 wpa_printf(MSG_DEBUG
, " AT_MAC");
298 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
299 return eap_sim_msg_finish(msg
, respDataLen
, data
->k_aut
, (u8
*) "", 0);
303 static u8
* eap_aka_response_reauth(struct eap_aka_data
*data
,
304 const struct eap_hdr
*req
,
305 size_t *respDataLen
, int counter_too_small
,
308 struct eap_sim_msg
*msg
;
309 unsigned int counter
;
311 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Reauthentication (id=%d)",
313 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
315 EAP_AKA_SUBTYPE_REAUTHENTICATION
);
316 wpa_printf(MSG_DEBUG
, " AT_IV");
317 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
318 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
, EAP_SIM_AT_ENCR_DATA
);
320 if (counter_too_small
) {
321 wpa_printf(MSG_DEBUG
, " *AT_COUNTER_TOO_SMALL");
322 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER_TOO_SMALL
, 0, NULL
, 0);
323 counter
= data
->counter_too_small
;
325 counter
= data
->counter
;
327 wpa_printf(MSG_DEBUG
, " *AT_COUNTER %d", counter
);
328 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
330 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
, EAP_SIM_AT_PADDING
)) {
331 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
333 eap_sim_msg_free(msg
);
336 wpa_printf(MSG_DEBUG
, " AT_MAC");
337 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
338 return eap_sim_msg_finish(msg
, respDataLen
, data
->k_aut
, nonce_s
,
339 EAP_SIM_NONCE_S_LEN
);
343 static u8
* eap_aka_response_notification(struct eap_aka_data
*data
,
344 const struct eap_hdr
*req
,
348 struct eap_sim_msg
*msg
;
349 u8
*k_aut
= (notification
& 0x4000) == 0 ? data
->k_aut
: NULL
;
351 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Notification (id=%d)",
353 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
354 EAP_TYPE_AKA
, EAP_AKA_SUBTYPE_NOTIFICATION
);
355 if (k_aut
&& data
->reauth
) {
356 wpa_printf(MSG_DEBUG
, " AT_IV");
357 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
358 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
,
359 EAP_SIM_AT_ENCR_DATA
);
360 wpa_printf(MSG_DEBUG
, " *AT_COUNTER %d", data
->counter
);
361 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, data
->counter
,
363 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
,
364 EAP_SIM_AT_PADDING
)) {
365 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
367 eap_sim_msg_free(msg
);
372 wpa_printf(MSG_DEBUG
, " AT_MAC");
373 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
375 return eap_sim_msg_finish(msg
, respDataLen
, k_aut
, (u8
*) "", 0);
379 static u8
* eap_aka_process_identity(struct eap_sm
*sm
,
380 struct eap_aka_data
*data
,
381 const struct eap_hdr
*req
,
383 struct eap_sim_attrs
*attr
)
387 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Identity");
390 switch (attr
->id_req
) {
394 if (data
->num_id_req
> 0)
399 if (data
->num_id_req
> 1)
404 if (data
->num_id_req
> 2)
410 wpa_printf(MSG_INFO
, "EAP-AKA: Too many ID requests "
411 "used within one authentication");
412 return eap_aka_client_error(data
, req
, respDataLen
,
413 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
416 return eap_aka_response_identity(sm
, data
, req
, respDataLen
,
421 static u8
* eap_aka_process_challenge(struct eap_sm
*sm
,
422 struct eap_aka_data
*data
,
423 const struct eap_hdr
*req
,
426 struct eap_sim_attrs
*attr
)
431 struct eap_sim_attrs eattr
;
433 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Challenge");
435 if (!attr
->mac
|| !attr
->rand
|| !attr
->autn
) {
436 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
437 "did not include%s%s%s",
438 !attr
->mac
? " AT_MAC" : "",
439 !attr
->rand
? " AT_RAND" : "",
440 !attr
->autn
? " AT_AUTN" : "");
441 return eap_aka_client_error(data
, req
, respDataLen
,
442 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
444 os_memcpy(data
->rand
, attr
->rand
, EAP_AKA_RAND_LEN
);
445 os_memcpy(data
->autn
, attr
->autn
, EAP_AKA_AUTN_LEN
);
447 res
= eap_aka_umts_auth(sm
, data
);
449 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication "
451 return eap_aka_authentication_reject(data
, req
, respDataLen
);
452 } else if (res
== -2) {
453 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication "
454 "failed (AUTN seq# -> AUTS)");
455 return eap_aka_synchronization_failure(data
, req
, respDataLen
);
457 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication failed");
458 return eap_aka_client_error(data
, req
, respDataLen
,
459 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
461 if (data
->last_eap_identity
) {
462 identity
= data
->last_eap_identity
;
463 identity_len
= data
->last_eap_identity_len
;
464 } else if (data
->pseudonym
) {
465 identity
= data
->pseudonym
;
466 identity_len
= data
->pseudonym_len
;
468 identity
= eap_get_config_identity(sm
, &identity_len
);
469 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA: Selected identity for MK "
470 "derivation", identity
, identity_len
);
471 eap_aka_derive_mk(identity
, identity_len
, data
->ik
, data
->ck
,
473 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
,
475 if (eap_sim_verify_mac(data
->k_aut
, (const u8
*) req
, reqDataLen
,
476 attr
->mac
, (u8
*) "", 0)) {
477 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
478 "used invalid AT_MAC");
479 return eap_aka_client_error(data
, req
, respDataLen
,
480 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
483 /* Old reauthentication and pseudonym identities must not be used
484 * anymore. In other words, if no new identities are received, full
485 * authentication will be used on next reauthentication. */
486 eap_aka_clear_identities(data
, CLEAR_PSEUDONYM
| CLEAR_REAUTH_ID
|
489 if (attr
->encr_data
) {
491 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
492 attr
->encr_data_len
, attr
->iv
,
494 if (decrypted
== NULL
) {
495 return eap_aka_client_error(
496 data
, req
, respDataLen
,
497 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
499 eap_aka_learn_ids(data
, &eattr
);
503 if (data
->state
!= FAILURE
)
504 data
->state
= SUCCESS
;
506 data
->num_id_req
= 0;
507 data
->num_notification
= 0;
508 /* RFC 4187 specifies that counter is initialized to one after
509 * fullauth, but initializing it to zero makes it easier to implement
510 * reauth verification. */
512 return eap_aka_response_challenge(data
, req
, respDataLen
);
516 static int eap_aka_process_notification_reauth(struct eap_aka_data
*data
,
517 struct eap_sim_attrs
*attr
)
519 struct eap_sim_attrs eattr
;
522 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
523 wpa_printf(MSG_WARNING
, "EAP-AKA: Notification message after "
524 "reauth did not include encrypted data");
528 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
529 attr
->encr_data_len
, attr
->iv
, &eattr
,
531 if (decrypted
== NULL
) {
532 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
533 "data from notification message");
537 if (eattr
.counter
< 0 || (size_t) eattr
.counter
!= data
->counter
) {
538 wpa_printf(MSG_WARNING
, "EAP-AKA: Counter in notification "
539 "message does not match with counter in reauth "
550 static int eap_aka_process_notification_auth(struct eap_aka_data
*data
,
551 const struct eap_hdr
*req
,
553 struct eap_sim_attrs
*attr
)
555 if (attr
->mac
== NULL
) {
556 wpa_printf(MSG_INFO
, "EAP-AKA: no AT_MAC in after_auth "
557 "Notification message");
561 if (eap_sim_verify_mac(data
->k_aut
, (const u8
*) req
, reqDataLen
,
562 attr
->mac
, (u8
*) "", 0)) {
563 wpa_printf(MSG_WARNING
, "EAP-AKA: Notification message "
564 "used invalid AT_MAC");
569 eap_aka_process_notification_reauth(data
, attr
)) {
570 wpa_printf(MSG_WARNING
, "EAP-AKA: Invalid notification "
571 "message after reauth");
579 static u8
* eap_aka_process_notification(struct eap_sm
*sm
,
580 struct eap_aka_data
*data
,
581 const struct eap_hdr
*req
,
584 struct eap_sim_attrs
*attr
)
586 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Notification");
587 if (data
->num_notification
> 0) {
588 wpa_printf(MSG_INFO
, "EAP-AKA: too many notification "
589 "rounds (only one allowed)");
590 return eap_aka_client_error(data
, req
, respDataLen
,
591 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
593 data
->num_notification
++;
594 if (attr
->notification
== -1) {
595 wpa_printf(MSG_INFO
, "EAP-AKA: no AT_NOTIFICATION in "
596 "Notification message");
597 return eap_aka_client_error(data
, req
, respDataLen
,
598 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
601 if ((attr
->notification
& 0x4000) == 0 &&
602 eap_aka_process_notification_auth(data
, req
, reqDataLen
, attr
)) {
603 return eap_aka_client_error(data
, req
, respDataLen
,
604 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
607 eap_sim_report_notification(sm
->msg_ctx
, attr
->notification
, 1);
608 if (attr
->notification
>= 0 && attr
->notification
< 32768) {
609 data
->state
= FAILURE
;
611 return eap_aka_response_notification(data
, req
, respDataLen
,
616 static u8
* eap_aka_process_reauthentication(struct eap_sm
*sm
,
617 struct eap_aka_data
*data
,
618 const struct eap_hdr
*req
,
621 struct eap_sim_attrs
*attr
)
623 struct eap_sim_attrs eattr
;
626 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Reauthentication");
628 if (data
->reauth_id
== NULL
) {
629 wpa_printf(MSG_WARNING
, "EAP-AKA: Server is trying "
630 "reauthentication, but no reauth_id available");
631 return eap_aka_client_error(data
, req
, respDataLen
,
632 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
636 if (eap_sim_verify_mac(data
->k_aut
, (const u8
*) req
, reqDataLen
,
637 attr
->mac
, (u8
*) "", 0)) {
638 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
639 "did not have valid AT_MAC");
640 return eap_aka_client_error(data
, req
, respDataLen
,
641 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
644 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
645 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
646 "message did not include encrypted data");
647 return eap_aka_client_error(data
, req
, respDataLen
,
648 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
651 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
652 attr
->encr_data_len
, attr
->iv
, &eattr
,
654 if (decrypted
== NULL
) {
655 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
656 "data from reauthentication message");
657 return eap_aka_client_error(data
, req
, respDataLen
,
658 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
661 if (eattr
.nonce_s
== NULL
|| eattr
.counter
< 0) {
662 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No%s%s in reauth packet",
663 !eattr
.nonce_s
? " AT_NONCE_S" : "",
664 eattr
.counter
< 0 ? " AT_COUNTER" : "");
666 return eap_aka_client_error(data
, req
, respDataLen
,
667 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
670 if (eattr
.counter
< 0 || (size_t) eattr
.counter
<= data
->counter
) {
672 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) Invalid counter "
673 "(%d <= %d)", eattr
.counter
, data
->counter
);
674 data
->counter_too_small
= eattr
.counter
;
676 eap_sim_derive_keys_reauth(eattr
.counter
, data
->reauth_id
,
677 data
->reauth_id_len
, eattr
.nonce_s
,
678 data
->mk
, NULL
, NULL
);
680 /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
681 * reauth_id must not be used to start a new reauthentication.
682 * However, since it was used in the last EAP-Response-Identity
683 * packet, it has to saved for the following fullauth to be
684 * used in MK derivation. */
685 os_free(data
->last_eap_identity
);
686 data
->last_eap_identity
= data
->reauth_id
;
687 data
->last_eap_identity_len
= data
->reauth_id_len
;
688 data
->reauth_id
= NULL
;
689 data
->reauth_id_len
= 0;
691 res
= eap_aka_response_reauth(data
, req
, respDataLen
, 1,
697 data
->counter
= eattr
.counter
;
699 os_memcpy(data
->nonce_s
, eattr
.nonce_s
, EAP_SIM_NONCE_S_LEN
);
700 wpa_hexdump(MSG_DEBUG
, "EAP-AKA: (encr) AT_NONCE_S",
701 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
);
703 eap_sim_derive_keys_reauth(data
->counter
,
704 data
->reauth_id
, data
->reauth_id_len
,
705 data
->nonce_s
, data
->mk
, data
->msk
,
707 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
| CLEAR_EAP_ID
);
708 eap_aka_learn_ids(data
, &eattr
);
710 if (data
->state
!= FAILURE
)
711 data
->state
= SUCCESS
;
713 data
->num_id_req
= 0;
714 data
->num_notification
= 0;
715 if (data
->counter
> EAP_AKA_MAX_FAST_REAUTHS
) {
716 wpa_printf(MSG_DEBUG
, "EAP-AKA: Maximum number of "
717 "fast reauths performed - force fullauth");
718 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
| CLEAR_EAP_ID
);
721 return eap_aka_response_reauth(data
, req
, respDataLen
, 0,
726 static u8
* eap_aka_process(struct eap_sm
*sm
, void *priv
,
727 struct eap_method_ret
*ret
,
728 const u8
*reqData
, size_t reqDataLen
,
731 struct eap_aka_data
*data
= priv
;
732 const struct eap_hdr
*req
;
735 struct eap_sim_attrs attr
;
738 wpa_hexdump(MSG_DEBUG
, "EAP-AKA: EAP data", reqData
, reqDataLen
);
739 if (eap_get_config_identity(sm
, &len
) == NULL
) {
740 wpa_printf(MSG_INFO
, "EAP-AKA: Identity not configured");
741 eap_sm_request_identity(sm
);
746 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_AKA
,
747 reqData
, reqDataLen
, &len
);
748 if (pos
== NULL
|| len
< 1) {
752 req
= (const struct eap_hdr
*) reqData
;
753 len
= be_to_host16(req
->length
);
756 ret
->methodState
= METHOD_MAY_CONT
;
757 ret
->decision
= DECISION_FAIL
;
758 ret
->allowNotifications
= TRUE
;
761 wpa_printf(MSG_DEBUG
, "EAP-AKA: Subtype=%d", subtype
);
762 pos
+= 2; /* Reserved */
764 if (eap_sim_parse_attr(pos
, reqData
+ len
, &attr
, 1, 0)) {
765 res
= eap_aka_client_error(data
, req
, respDataLen
,
766 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
771 case EAP_AKA_SUBTYPE_IDENTITY
:
772 res
= eap_aka_process_identity(sm
, data
, req
,
775 case EAP_AKA_SUBTYPE_CHALLENGE
:
776 res
= eap_aka_process_challenge(sm
, data
, req
, len
,
779 case EAP_AKA_SUBTYPE_NOTIFICATION
:
780 res
= eap_aka_process_notification(sm
, data
, req
, len
,
783 case EAP_AKA_SUBTYPE_REAUTHENTICATION
:
784 res
= eap_aka_process_reauthentication(sm
, data
, req
, len
,
787 case EAP_AKA_SUBTYPE_CLIENT_ERROR
:
788 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Client-Error");
789 res
= eap_aka_client_error(data
, req
, respDataLen
,
790 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
793 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown subtype=%d", subtype
);
794 res
= eap_aka_client_error(data
, req
, respDataLen
,
795 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
800 if (data
->state
== FAILURE
) {
801 ret
->decision
= DECISION_FAIL
;
802 ret
->methodState
= METHOD_DONE
;
803 } else if (data
->state
== SUCCESS
) {
804 ret
->decision
= DECISION_COND_SUCC
;
806 * It is possible for the server to reply with AKA
807 * Notification, so we must allow the method to continue and
808 * not only accept EAP-Success at this point.
810 ret
->methodState
= METHOD_MAY_CONT
;
813 if (ret
->methodState
== METHOD_DONE
) {
814 ret
->allowNotifications
= FALSE
;
821 static Boolean
eap_aka_has_reauth_data(struct eap_sm
*sm
, void *priv
)
823 struct eap_aka_data
*data
= priv
;
824 return data
->pseudonym
|| data
->reauth_id
;
828 static void eap_aka_deinit_for_reauth(struct eap_sm
*sm
, void *priv
)
830 struct eap_aka_data
*data
= priv
;
831 eap_aka_clear_identities(data
, CLEAR_EAP_ID
);
835 static void * eap_aka_init_for_reauth(struct eap_sm
*sm
, void *priv
)
837 struct eap_aka_data
*data
= priv
;
838 data
->num_id_req
= 0;
839 data
->num_notification
= 0;
840 data
->state
= CONTINUE
;
845 static const u8
* eap_aka_get_identity(struct eap_sm
*sm
, void *priv
,
848 struct eap_aka_data
*data
= priv
;
850 if (data
->reauth_id
) {
851 *len
= data
->reauth_id_len
;
852 return data
->reauth_id
;
855 if (data
->pseudonym
) {
856 *len
= data
->pseudonym_len
;
857 return data
->pseudonym
;
864 static Boolean
eap_aka_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
866 struct eap_aka_data
*data
= priv
;
867 return data
->state
== SUCCESS
;
871 static u8
* eap_aka_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
873 struct eap_aka_data
*data
= priv
;
876 if (data
->state
!= SUCCESS
)
879 key
= os_malloc(EAP_SIM_KEYING_DATA_LEN
);
883 *len
= EAP_SIM_KEYING_DATA_LEN
;
884 os_memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
890 static u8
* eap_aka_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
892 struct eap_aka_data
*data
= priv
;
895 if (data
->state
!= SUCCESS
)
898 key
= os_malloc(EAP_EMSK_LEN
);
903 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
909 int eap_peer_aka_register(void)
911 struct eap_method
*eap
;
914 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
915 EAP_VENDOR_IETF
, EAP_TYPE_AKA
, "AKA");
919 eap
->init
= eap_aka_init
;
920 eap
->deinit
= eap_aka_deinit
;
921 eap
->process
= eap_aka_process
;
922 eap
->isKeyAvailable
= eap_aka_isKeyAvailable
;
923 eap
->getKey
= eap_aka_getKey
;
924 eap
->has_reauth_data
= eap_aka_has_reauth_data
;
925 eap
->deinit_for_reauth
= eap_aka_deinit_for_reauth
;
926 eap
->init_for_reauth
= eap_aka_init_for_reauth
;
927 eap
->get_identity
= eap_aka_get_identity
;
928 eap
->get_emsk
= eap_aka_get_emsk
;
930 ret
= eap_peer_method_register(eap
);
932 eap_peer_method_free(eap
);