2 * WPA Supplicant / EAP-AKA (draft-arkko-pppext-eap-aka-12.txt)
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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.
21 #include "wpa_supplicant.h"
22 #include "config_ssid.h"
24 #include "pcsc_funcs.h"
25 #include "eap_sim_common.h"
27 /* EAP-AKA Subtypes */
28 #define EAP_AKA_SUBTYPE_CHALLENGE 1
29 #define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2
30 #define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4
31 #define EAP_AKA_SUBTYPE_IDENTITY 5
32 #define EAP_AKA_SUBTYPE_NOTIFICATION 12
33 #define EAP_AKA_SUBTYPE_REAUTHENTICATION 13
34 #define EAP_AKA_SUBTYPE_CLIENT_ERROR 14
36 /* AT_CLIENT_ERROR_CODE error codes */
37 #define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0
39 #define AKA_AUTS_LEN 14
40 #define RES_MAX_LEN 16
43 #define EAP_AKA_MAX_FAST_REAUTHS 1000
46 u8 ik
[IK_LEN
], ck
[CK_LEN
], res
[RES_MAX_LEN
];
48 u8 nonce_s
[EAP_SIM_NONCE_S_LEN
];
49 u8 mk
[EAP_SIM_MK_LEN
];
50 u8 k_aut
[EAP_SIM_K_AUT_LEN
];
51 u8 k_encr
[EAP_SIM_K_ENCR_LEN
];
52 u8 msk
[EAP_SIM_KEYING_DATA_LEN
];
53 u8 rand
[AKA_RAND_LEN
], autn
[AKA_AUTN_LEN
];
54 u8 auts
[AKA_AUTS_LEN
];
56 int num_id_req
, num_notification
;
62 unsigned int counter
, counter_too_small
;
63 u8
*last_eap_identity
;
64 size_t last_eap_identity_len
;
65 enum { CONTINUE
, SUCCESS
, FAILURE
} state
;
69 static void * eap_aka_init(struct eap_sm
*sm
)
71 struct eap_aka_data
*data
;
72 data
= malloc(sizeof(*data
));
75 memset(data
, 0, sizeof(*data
));
77 data
->state
= CONTINUE
;
83 static void eap_aka_deinit(struct eap_sm
*sm
, void *priv
)
85 struct eap_aka_data
*data
= priv
;
87 free(data
->pseudonym
);
88 free(data
->reauth_id
);
89 free(data
->last_eap_identity
);
95 static int eap_aka_umts_auth(struct eap_sm
*sm
, struct eap_aka_data
*data
)
97 wpa_printf(MSG_DEBUG
, "EAP-AKA: UMTS authentication algorithm");
99 return scard_umts_auth(sm
->scard_ctx
, data
->rand
,
100 data
->autn
, data
->res
, &data
->res_len
,
101 data
->ik
, data
->ck
, data
->auts
);
102 #else /* PCSC_FUNCS */
103 /* These hardcoded Kc and SRES values are used for testing.
104 * Could consider making them configurable. */
105 memset(data
->res
, '2', RES_MAX_LEN
);
107 memset(data
->ik
, '3', IK_LEN
);
108 memset(data
->ck
, '4', CK_LEN
);
110 u8 autn
[AKA_AUTN_LEN
];
111 memset(autn
, '1', AKA_AUTN_LEN
);
112 if (memcmp(autn
, data
->autn
, AKA_AUTN_LEN
) != 0) {
113 wpa_printf(MSG_WARNING
, "EAP-AKA: AUTN did not match "
114 "with expected value");
119 #endif /* PCSC_FUNCS */
123 static void eap_aka_derive_mk(struct eap_aka_data
*data
,
124 const u8
*identity
, size_t identity_len
)
130 len
[0] = identity_len
;
136 /* MK = SHA1(Identity|IK|CK) */
137 sha1_vector(3, addr
, len
, data
->mk
);
138 wpa_hexdump_key(MSG_DEBUG
, "EAP-AKA: IK", data
->ik
, IK_LEN
);
139 wpa_hexdump_key(MSG_DEBUG
, "EAP-AKA: CK", data
->ck
, CK_LEN
);
140 wpa_hexdump_key(MSG_DEBUG
, "EAP-AKA: MK", data
->mk
, EAP_SIM_MK_LEN
);
144 #define CLEAR_PSEUDONYM 0x01
145 #define CLEAR_REAUTH_ID 0x02
146 #define CLEAR_EAP_ID 0x04
148 static void eap_aka_clear_identities(struct eap_aka_data
*data
, int id
)
150 wpa_printf(MSG_DEBUG
, "EAP-AKA: forgetting old%s%s%s",
151 id
& CLEAR_PSEUDONYM
? " pseudonym" : "",
152 id
& CLEAR_REAUTH_ID
? " reauth_id" : "",
153 id
& CLEAR_EAP_ID
? " eap_id" : "");
154 if (id
& CLEAR_PSEUDONYM
) {
155 free(data
->pseudonym
);
156 data
->pseudonym
= NULL
;
157 data
->pseudonym_len
= 0;
159 if (id
& CLEAR_REAUTH_ID
) {
160 free(data
->reauth_id
);
161 data
->reauth_id
= NULL
;
162 data
->reauth_id_len
= 0;
164 if (id
& CLEAR_EAP_ID
) {
165 free(data
->last_eap_identity
);
166 data
->last_eap_identity
= NULL
;
167 data
->last_eap_identity_len
= 0;
172 static int eap_aka_learn_ids(struct eap_aka_data
*data
,
173 struct eap_sim_attrs
*attr
)
175 if (attr
->next_pseudonym
) {
176 free(data
->pseudonym
);
177 data
->pseudonym
= malloc(attr
->next_pseudonym_len
);
178 if (data
->pseudonym
== NULL
) {
179 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No memory for "
183 memcpy(data
->pseudonym
, attr
->next_pseudonym
,
184 attr
->next_pseudonym_len
);
185 data
->pseudonym_len
= attr
->next_pseudonym_len
;
186 wpa_hexdump_ascii(MSG_DEBUG
,
187 "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
189 data
->pseudonym_len
);
192 if (attr
->next_reauth_id
) {
193 free(data
->reauth_id
);
194 data
->reauth_id
= malloc(attr
->next_reauth_id_len
);
195 if (data
->reauth_id
== NULL
) {
196 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No memory for "
200 memcpy(data
->reauth_id
, attr
->next_reauth_id
,
201 attr
->next_reauth_id_len
);
202 data
->reauth_id_len
= attr
->next_reauth_id_len
;
203 wpa_hexdump_ascii(MSG_DEBUG
,
204 "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
206 data
->reauth_id_len
);
213 static u8
* eap_aka_client_error(struct eap_sm
*sm
, struct eap_aka_data
*data
,
214 const struct eap_hdr
*req
,
215 size_t *respDataLen
, int err
)
217 struct eap_sim_msg
*msg
;
219 data
->state
= FAILURE
;
220 data
->num_id_req
= 0;
221 data
->num_notification
= 0;
223 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
224 EAP_TYPE_AKA
, EAP_AKA_SUBTYPE_CLIENT_ERROR
);
225 eap_sim_msg_add(msg
, EAP_SIM_AT_CLIENT_ERROR_CODE
, err
, NULL
, 0);
226 return eap_sim_msg_finish(msg
, respDataLen
, NULL
, NULL
, 0);
230 static u8
* eap_aka_authentication_reject(struct eap_sm
*sm
,
231 struct eap_aka_data
*data
,
232 const struct eap_hdr
*req
,
235 struct eap_sim_msg
*msg
;
237 data
->state
= FAILURE
;
238 data
->num_id_req
= 0;
239 data
->num_notification
= 0;
241 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Authentication-Reject "
242 "(id=%d)", req
->identifier
);
243 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
245 EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
);
246 return eap_sim_msg_finish(msg
, respDataLen
, NULL
, NULL
, 0);
250 static u8
* eap_aka_synchronization_failure(struct eap_sm
*sm
,
251 struct eap_aka_data
*data
,
252 const struct eap_hdr
*req
,
255 struct eap_sim_msg
*msg
;
257 data
->state
= FAILURE
;
258 data
->num_id_req
= 0;
259 data
->num_notification
= 0;
261 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Synchronization-Failure "
262 "(id=%d)", req
->identifier
);
263 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
265 EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
);
266 wpa_printf(MSG_DEBUG
, " AT_AUTS");
267 eap_sim_msg_add_full(msg
, EAP_SIM_AT_AUTS
, data
->auts
, AKA_AUTS_LEN
);
268 return eap_sim_msg_finish(msg
, respDataLen
, NULL
, NULL
, 0);
272 static u8
* eap_aka_response_identity(struct eap_sm
*sm
,
273 struct eap_aka_data
*data
,
274 const struct eap_hdr
*req
,
276 enum eap_sim_id_req id_req
)
278 struct wpa_ssid
*config
= eap_get_config(sm
);
280 size_t identity_len
= 0;
281 struct eap_sim_msg
*msg
;
284 if (id_req
== ANY_ID
&& data
->reauth_id
) {
285 identity
= data
->reauth_id
;
286 identity_len
= data
->reauth_id_len
;
288 } else if ((id_req
== ANY_ID
|| id_req
== FULLAUTH_ID
) &&
290 identity
= data
->pseudonym
;
291 identity_len
= data
->pseudonym_len
;
292 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
);
293 } else if (id_req
!= NO_ID_REQ
&& config
&& config
->identity
) {
294 identity
= config
->identity
;
295 identity_len
= config
->identity_len
;
296 eap_aka_clear_identities(data
,
297 CLEAR_PSEUDONYM
| CLEAR_REAUTH_ID
);
299 if (id_req
!= NO_ID_REQ
)
300 eap_aka_clear_identities(data
, CLEAR_EAP_ID
);
302 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Identity (id=%d)",
304 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
305 EAP_TYPE_AKA
, EAP_AKA_SUBTYPE_IDENTITY
);
308 wpa_hexdump_ascii(MSG_DEBUG
, " AT_IDENTITY",
309 identity
, identity_len
);
310 eap_sim_msg_add(msg
, EAP_SIM_AT_IDENTITY
, identity_len
,
311 identity
, identity_len
);
314 return eap_sim_msg_finish(msg
, respDataLen
, NULL
, NULL
, 0);
318 static u8
* eap_aka_response_challenge(struct eap_sm
*sm
,
319 struct eap_aka_data
*data
,
320 const struct eap_hdr
*req
,
323 struct eap_sim_msg
*msg
;
325 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Challenge (id=%d)",
327 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
328 EAP_TYPE_AKA
, EAP_AKA_SUBTYPE_CHALLENGE
);
329 wpa_printf(MSG_DEBUG
, " AT_RES");
330 eap_sim_msg_add(msg
, EAP_SIM_AT_RES
, data
->res_len
,
331 data
->res
, data
->res_len
);
332 wpa_printf(MSG_DEBUG
, " AT_MAC");
333 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
334 return eap_sim_msg_finish(msg
, respDataLen
, data
->k_aut
, (u8
*) "", 0);
338 static u8
* eap_aka_response_reauth(struct eap_sm
*sm
,
339 struct eap_aka_data
*data
,
340 const struct eap_hdr
*req
,
341 size_t *respDataLen
, int counter_too_small
)
343 struct eap_sim_msg
*msg
;
344 unsigned int counter
;
346 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Reauthentication (id=%d)",
348 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
350 EAP_AKA_SUBTYPE_REAUTHENTICATION
);
351 wpa_printf(MSG_DEBUG
, " AT_IV");
352 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
353 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
, EAP_SIM_AT_ENCR_DATA
);
355 if (counter_too_small
) {
356 wpa_printf(MSG_DEBUG
, " *AT_COUNTER_TOO_SMALL");
357 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER_TOO_SMALL
, 0, NULL
, 0);
358 counter
= data
->counter_too_small
;
360 counter
= data
->counter
;
362 wpa_printf(MSG_DEBUG
, " *AT_COUNTER %d", counter
);
363 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
365 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
, EAP_SIM_AT_PADDING
)) {
366 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
368 eap_sim_msg_free(msg
);
371 wpa_printf(MSG_DEBUG
, " AT_MAC");
372 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
373 return eap_sim_msg_finish(msg
, respDataLen
, data
->k_aut
, data
->nonce_s
,
374 EAP_SIM_NONCE_S_LEN
);
378 static u8
* eap_aka_response_notification(struct eap_sm
*sm
,
379 struct eap_aka_data
*data
,
380 const struct eap_hdr
*req
,
384 struct eap_sim_msg
*msg
;
385 u8
*k_aut
= (notification
& 0x4000) == 0 ? data
->k_aut
: NULL
;
387 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Notification (id=%d)",
389 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, req
->identifier
,
390 EAP_TYPE_AKA
, EAP_AKA_SUBTYPE_NOTIFICATION
);
391 wpa_printf(MSG_DEBUG
, " AT_NOTIFICATION");
392 eap_sim_msg_add(msg
, EAP_SIM_AT_NOTIFICATION
, notification
, NULL
, 0);
393 if (k_aut
&& data
->reauth
) {
394 wpa_printf(MSG_DEBUG
, " AT_IV");
395 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
396 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
,
397 EAP_SIM_AT_ENCR_DATA
);
398 wpa_printf(MSG_DEBUG
, " *AT_COUNTER %d", data
->counter
);
399 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, data
->counter
,
401 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
,
402 EAP_SIM_AT_PADDING
)) {
403 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
405 eap_sim_msg_free(msg
);
410 wpa_printf(MSG_DEBUG
, " AT_MAC");
411 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
413 return eap_sim_msg_finish(msg
, respDataLen
, k_aut
, (u8
*) "", 0);
417 static u8
* eap_aka_process_identity(struct eap_sm
*sm
,
418 struct eap_aka_data
*data
,
419 const struct eap_hdr
*req
,
422 struct eap_sim_attrs
*attr
)
426 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Identity");
429 switch (attr
->id_req
) {
433 if (data
->num_id_req
> 0)
438 if (data
->num_id_req
> 1)
443 if (data
->num_id_req
> 2)
449 wpa_printf(MSG_INFO
, "EAP-AKA: Too many ID requests "
450 "used within one authentication");
451 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
452 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
455 return eap_aka_response_identity(sm
, data
, req
, respDataLen
,
460 static u8
* eap_aka_process_challenge(struct eap_sm
*sm
,
461 struct eap_aka_data
*data
,
462 const struct eap_hdr
*req
,
465 struct eap_sim_attrs
*attr
)
467 struct wpa_ssid
*config
= eap_get_config(sm
);
471 struct eap_sim_attrs eattr
;
473 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Challenge");
475 if (!attr
->mac
|| !attr
->rand
|| !attr
->autn
) {
476 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
477 "did not include%s%s%s",
478 !attr
->mac
? " AT_MAC" : "",
479 !attr
->rand
? " AT_RAND" : "",
480 !attr
->autn
? " AT_AUTN" : "");
481 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
482 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
484 memcpy(data
->rand
, attr
->rand
, AKA_RAND_LEN
);
485 memcpy(data
->autn
, attr
->autn
, AKA_AUTN_LEN
);
487 res
= eap_aka_umts_auth(sm
, data
);
489 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication "
491 return eap_aka_authentication_reject(sm
, data
, req
,
493 } else if (res
== -2) {
494 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication "
495 "failed (AUTN seq# -> AUTS)");
496 return eap_aka_synchronization_failure(sm
, data
, req
,
499 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication failed");
500 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
501 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
503 if (data
->last_eap_identity
) {
504 identity
= data
->last_eap_identity
;
505 identity_len
= data
->last_eap_identity_len
;
506 } else if (data
->pseudonym
) {
507 identity
= data
->pseudonym
;
508 identity_len
= data
->pseudonym_len
;
510 identity
= config
->identity
;
511 identity_len
= config
->identity_len
;
513 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA: Selected identity for MK "
514 "derivation", identity
, identity_len
);
515 eap_aka_derive_mk(data
, identity
, identity_len
);
516 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
, data
->msk
);
517 if (eap_sim_verify_mac(data
->k_aut
, (const u8
*) req
, reqDataLen
,
518 attr
->mac
, (u8
*) "", 0)) {
519 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
520 "used invalid AT_MAC");
521 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
522 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
525 /* Old reauthentication and pseudonym identities must not be used
526 * anymore. In other words, if no new identities are received, full
527 * authentication will be used on next reauthentication. */
528 eap_aka_clear_identities(data
, CLEAR_PSEUDONYM
| CLEAR_REAUTH_ID
|
531 if (attr
->encr_data
) {
533 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
534 attr
->encr_data_len
, attr
->iv
,
536 if (decrypted
== NULL
) {
537 return eap_aka_client_error(
538 sm
, data
, req
, respDataLen
,
539 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
541 eap_aka_learn_ids(data
, &eattr
);
545 if (data
->state
!= FAILURE
)
546 data
->state
= SUCCESS
;
548 data
->num_id_req
= 0;
549 data
->num_notification
= 0;
550 /* draft-arkko-pppext-eap-aka-12.txt specifies that counter
551 * is initialized to one after fullauth, but initializing it to
552 * zero makes it easier to implement reauth verification. */
554 return eap_aka_response_challenge(sm
, data
, req
, respDataLen
);
558 static int eap_aka_process_notification_reauth(struct eap_aka_data
*data
,
559 const struct eap_hdr
*req
,
561 struct eap_sim_attrs
*attr
)
563 struct eap_sim_attrs eattr
;
566 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
567 wpa_printf(MSG_WARNING
, "EAP-AKA: Notification message after "
568 "reauth did not include encrypted data");
572 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
573 attr
->encr_data_len
, attr
->iv
, &eattr
,
575 if (decrypted
== NULL
) {
576 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
577 "data from notification message");
581 if (eattr
.counter
!= data
->counter
) {
582 wpa_printf(MSG_WARNING
, "EAP-AKA: Counter in notification "
583 "message does not match with counter in reauth "
594 static int eap_aka_process_notification_auth(struct eap_aka_data
*data
,
595 const struct eap_hdr
*req
,
597 struct eap_sim_attrs
*attr
)
599 if (attr
->mac
== NULL
) {
600 wpa_printf(MSG_INFO
, "EAP-AKA: no AT_MAC in after_auth "
601 "Notification message");
605 if (eap_sim_verify_mac(data
->k_aut
, (const u8
*) req
, reqDataLen
,
606 attr
->mac
, (u8
*) "", 0)) {
607 wpa_printf(MSG_WARNING
, "EAP-AKA: Notification message "
608 "used invalid AT_MAC");
613 eap_aka_process_notification_reauth(data
, req
, reqDataLen
, attr
)) {
614 wpa_printf(MSG_WARNING
, "EAP-AKA: Invalid notification "
615 "message after reauth");
623 static u8
* eap_aka_process_notification(struct eap_sm
*sm
,
624 struct eap_aka_data
*data
,
625 const struct eap_hdr
*req
,
628 struct eap_sim_attrs
*attr
)
630 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Notification");
631 if (data
->num_notification
> 0) {
632 wpa_printf(MSG_INFO
, "EAP-AKA: too many notification "
633 "rounds (only one allowed)");
634 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
635 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
637 data
->num_notification
++;
638 if (attr
->notification
== -1) {
639 wpa_printf(MSG_INFO
, "EAP-AKA: no AT_NOTIFICATION in "
640 "Notification message");
641 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
642 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
645 if ((attr
->notification
& 0x4000) == 0 &&
646 eap_aka_process_notification_auth(data
, req
, reqDataLen
, attr
)) {
647 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
648 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
651 eap_sim_report_notification(sm
->msg_ctx
, attr
->notification
, 1);
652 if (attr
->notification
>= 0 && attr
->notification
< 32768) {
653 data
->state
= FAILURE
;
655 return eap_aka_response_notification(sm
, data
, req
, respDataLen
,
660 static u8
* eap_aka_process_reauthentication(struct eap_sm
*sm
,
661 struct eap_aka_data
*data
,
662 const struct eap_hdr
*req
,
665 struct eap_sim_attrs
*attr
)
667 struct eap_sim_attrs eattr
;
670 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Reauthentication");
672 if (data
->reauth_id
== NULL
) {
673 wpa_printf(MSG_WARNING
, "EAP-AKA: Server is trying "
674 "reauthentication, but no reauth_id available");
675 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
676 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
680 if (eap_sim_verify_mac(data
->k_aut
, (const u8
*) req
, reqDataLen
,
681 attr
->mac
, (u8
*) "", 0)) {
682 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
683 "did not have valid AT_MAC");
684 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
685 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
688 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
689 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
690 "message did not include encrypted data");
691 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
692 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
695 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
696 attr
->encr_data_len
, attr
->iv
, &eattr
,
698 if (decrypted
== NULL
) {
699 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
700 "data from reauthentication message");
701 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
702 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
705 if (eattr
.nonce_s
== NULL
|| eattr
.counter
< 0) {
706 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No%s%s in reauth packet",
707 !eattr
.nonce_s
? " AT_NONCE_S" : "",
708 eattr
.counter
< 0 ? " AT_COUNTER" : "");
710 return eap_aka_client_error(sm
, data
, req
, respDataLen
,
711 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
714 if (eattr
.counter
<= data
->counter
) {
715 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) Invalid counter "
716 "(%d <= %d)", eattr
.counter
, data
->counter
);
717 data
->counter_too_small
= eattr
.counter
;
718 /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
719 * reauth_id must not be used to start a new reauthentication.
720 * However, since it was used in the last EAP-Response-Identity
721 * packet, it has to saved for the following fullauth to be
722 * used in MK derivation. */
723 free(data
->last_eap_identity
);
724 data
->last_eap_identity
= data
->reauth_id
;
725 data
->last_eap_identity_len
= data
->reauth_id_len
;
726 data
->reauth_id
= NULL
;
727 data
->reauth_id_len
= 0;
729 return eap_aka_response_reauth(sm
, data
, req
, respDataLen
, 1);
731 data
->counter
= eattr
.counter
;
733 memcpy(data
->nonce_s
, eattr
.nonce_s
, EAP_SIM_NONCE_S_LEN
);
734 wpa_hexdump(MSG_DEBUG
, "EAP-AKA: (encr) AT_NONCE_S",
735 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
);
737 eap_sim_derive_keys_reauth(data
->counter
,
738 data
->reauth_id
, data
->reauth_id_len
,
739 data
->nonce_s
, data
->mk
, data
->msk
);
740 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
| CLEAR_EAP_ID
);
741 eap_aka_learn_ids(data
, &eattr
);
743 if (data
->state
!= FAILURE
)
744 data
->state
= SUCCESS
;
746 data
->num_id_req
= 0;
747 data
->num_notification
= 0;
748 if (data
->counter
> EAP_AKA_MAX_FAST_REAUTHS
) {
749 wpa_printf(MSG_DEBUG
, "EAP-AKA: Maximum number of "
750 "fast reauths performed - force fullauth");
751 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
| CLEAR_EAP_ID
);
754 return eap_aka_response_reauth(sm
, data
, req
, respDataLen
, 0);
758 static u8
* eap_aka_process(struct eap_sm
*sm
, void *priv
,
759 struct eap_method_ret
*ret
,
760 const u8
*reqData
, size_t reqDataLen
,
763 struct eap_aka_data
*data
= priv
;
764 struct wpa_ssid
*config
= eap_get_config(sm
);
765 const struct eap_hdr
*req
;
768 struct eap_sim_attrs attr
;
771 wpa_hexdump(MSG_DEBUG
, "EAP-AKA: EAP data", reqData
, reqDataLen
);
772 if (config
== NULL
|| config
->identity
== NULL
) {
773 wpa_printf(MSG_INFO
, "EAP-AKA: Identity not configured");
774 eap_sm_request_identity(sm
, config
);
779 pos
= eap_hdr_validate(EAP_TYPE_AKA
, reqData
, reqDataLen
, &len
);
780 if (pos
== NULL
|| len
< 1) {
784 req
= (const struct eap_hdr
*) reqData
;
785 len
= be_to_host16(req
->length
);
788 ret
->methodState
= METHOD_MAY_CONT
;
789 ret
->decision
= DECISION_FAIL
;
790 ret
->allowNotifications
= TRUE
;
793 wpa_printf(MSG_DEBUG
, "EAP-AKA: Subtype=%d", subtype
);
794 pos
+= 2; /* Reserved */
796 if (eap_sim_parse_attr(pos
, reqData
+ len
, &attr
, 1, 0)) {
797 res
= eap_aka_client_error(sm
, data
, req
, respDataLen
,
798 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
803 case EAP_AKA_SUBTYPE_IDENTITY
:
804 res
= eap_aka_process_identity(sm
, data
, req
, len
,
807 case EAP_AKA_SUBTYPE_CHALLENGE
:
808 res
= eap_aka_process_challenge(sm
, data
, req
, len
,
811 case EAP_AKA_SUBTYPE_NOTIFICATION
:
812 res
= eap_aka_process_notification(sm
, data
, req
, len
,
815 case EAP_AKA_SUBTYPE_REAUTHENTICATION
:
816 res
= eap_aka_process_reauthentication(sm
, data
, req
, len
,
819 case EAP_AKA_SUBTYPE_CLIENT_ERROR
:
820 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Client-Error");
821 res
= eap_aka_client_error(sm
, data
, req
, respDataLen
,
822 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
825 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown subtype=%d", subtype
);
826 res
= eap_aka_client_error(sm
, data
, req
, respDataLen
,
827 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
832 if (data
->state
== FAILURE
) {
833 ret
->decision
= DECISION_FAIL
;
834 ret
->methodState
= METHOD_DONE
;
835 } else if (data
->state
== SUCCESS
) {
836 ret
->decision
= DECISION_COND_SUCC
;
837 ret
->methodState
= METHOD_DONE
;
840 if (ret
->methodState
== METHOD_DONE
) {
841 ret
->allowNotifications
= FALSE
;
848 static Boolean
eap_aka_has_reauth_data(struct eap_sm
*sm
, void *priv
)
850 struct eap_aka_data
*data
= priv
;
851 return data
->pseudonym
|| data
->reauth_id
;
855 static void eap_aka_deinit_for_reauth(struct eap_sm
*sm
, void *priv
)
857 struct eap_aka_data
*data
= priv
;
858 eap_aka_clear_identities(data
, CLEAR_EAP_ID
);
862 static void * eap_aka_init_for_reauth(struct eap_sm
*sm
, void *priv
)
864 struct eap_aka_data
*data
= priv
;
865 data
->num_id_req
= 0;
866 data
->num_notification
= 0;
867 data
->state
= CONTINUE
;
872 static const u8
* eap_aka_get_identity(struct eap_sm
*sm
, void *priv
,
875 struct eap_aka_data
*data
= priv
;
877 if (data
->reauth_id
) {
878 *len
= data
->reauth_id_len
;
879 return data
->reauth_id
;
882 if (data
->pseudonym
) {
883 *len
= data
->pseudonym_len
;
884 return data
->pseudonym
;
891 static Boolean
eap_aka_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
893 struct eap_aka_data
*data
= priv
;
894 return data
->state
== SUCCESS
;
898 static u8
* eap_aka_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
900 struct eap_aka_data
*data
= priv
;
903 if (data
->state
!= SUCCESS
)
906 key
= malloc(EAP_SIM_KEYING_DATA_LEN
);
910 *len
= EAP_SIM_KEYING_DATA_LEN
;
911 memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
917 const struct eap_method eap_method_aka
=
919 .method
= EAP_TYPE_AKA
,
921 .init
= eap_aka_init
,
922 .deinit
= eap_aka_deinit
,
923 .process
= eap_aka_process
,
924 .isKeyAvailable
= eap_aka_isKeyAvailable
,
925 .getKey
= eap_aka_getKey
,
926 .has_reauth_data
= eap_aka_has_reauth_data
,
927 .deinit_for_reauth
= eap_aka_deinit_for_reauth
,
928 .init_for_reauth
= eap_aka_init_for_reauth
,
929 .get_identity
= eap_aka_get_identity
,