2 * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
3 * Copyright (c) 2004-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 "pcsc_funcs.h"
19 #include "crypto/crypto.h"
20 #include "crypto/sha1.h"
21 #include "crypto/sha256.h"
22 #include "crypto/milenage.h"
23 #include "eap_common/eap_sim_common.h"
24 #include "eap_config.h"
29 u8 ik
[EAP_AKA_IK_LEN
], ck
[EAP_AKA_CK_LEN
], res
[EAP_AKA_RES_MAX_LEN
];
31 u8 nonce_s
[EAP_SIM_NONCE_S_LEN
];
32 u8 mk
[EAP_SIM_MK_LEN
];
33 u8 k_aut
[EAP_AKA_PRIME_K_AUT_LEN
];
34 u8 k_encr
[EAP_SIM_K_ENCR_LEN
];
35 u8 k_re
[EAP_AKA_PRIME_K_RE_LEN
]; /* EAP-AKA' only */
36 u8 msk
[EAP_SIM_KEYING_DATA_LEN
];
37 u8 emsk
[EAP_EMSK_LEN
];
38 u8 rand
[EAP_AKA_RAND_LEN
], autn
[EAP_AKA_AUTN_LEN
];
39 u8 auts
[EAP_AKA_AUTS_LEN
];
41 int num_id_req
, num_notification
;
47 unsigned int counter
, counter_too_small
;
48 u8
*last_eap_identity
;
49 size_t last_eap_identity_len
;
51 CONTINUE
, RESULT_SUCCESS
, RESULT_FAILURE
, SUCCESS
, FAILURE
54 struct wpabuf
*id_msgs
;
56 int result_ind
, use_result_ind
;
59 size_t network_name_len
;
65 #ifndef CONFIG_NO_STDOUT_DEBUG
66 static const char * eap_aka_state_txt(int state
)
72 return "RESULT_SUCCESS";
74 return "RESULT_FAILURE";
83 #endif /* CONFIG_NO_STDOUT_DEBUG */
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
;
98 const char *phase1
= eap_get_config_phase1(sm
);
100 data
= os_zalloc(sizeof(*data
));
104 data
->eap_method
= EAP_TYPE_AKA
;
106 eap_aka_state(data
, CONTINUE
);
109 data
->result_ind
= phase1
&& os_strstr(phase1
, "result_ind=1") != NULL
;
116 static void * eap_aka_prime_init(struct eap_sm
*sm
)
118 struct eap_aka_data
*data
= eap_aka_init(sm
);
121 data
->eap_method
= EAP_TYPE_AKA_PRIME
;
124 #endif /* EAP_AKA_PRIME */
127 static void eap_aka_deinit(struct eap_sm
*sm
, void *priv
)
129 struct eap_aka_data
*data
= priv
;
131 os_free(data
->pseudonym
);
132 os_free(data
->reauth_id
);
133 os_free(data
->last_eap_identity
);
134 wpabuf_free(data
->id_msgs
);
135 os_free(data
->network_name
);
141 static int eap_aka_umts_auth(struct eap_sm
*sm
, struct eap_aka_data
*data
)
143 struct eap_peer_config
*conf
;
145 wpa_printf(MSG_DEBUG
, "EAP-AKA: UMTS authentication algorithm");
147 conf
= eap_get_config(sm
);
151 return scard_umts_auth(sm
->scard_ctx
, data
->rand
,
152 data
->autn
, data
->res
, &data
->res_len
,
153 data
->ik
, data
->ck
, data
->auts
);
156 #ifdef CONFIG_USIM_SIMULATOR
157 if (conf
->password
) {
158 u8 opc
[16], k
[16], sqn
[6];
160 wpa_printf(MSG_DEBUG
, "EAP-AKA: Use internal Milenage "
161 "implementation for UMTS authentication");
162 if (conf
->password_len
< 78) {
163 wpa_printf(MSG_DEBUG
, "EAP-AKA: invalid Milenage "
167 pos
= (const char *) conf
->password
;
168 if (hexstr2bin(pos
, k
, 16))
175 if (hexstr2bin(pos
, opc
, 16))
182 if (hexstr2bin(pos
, sqn
, 6))
185 return milenage_check(opc
, k
, sqn
, data
->rand
, data
->autn
,
187 data
->res
, &data
->res_len
, data
->auts
);
189 #endif /* CONFIG_USIM_SIMULATOR */
191 #ifdef CONFIG_USIM_HARDCODED
192 wpa_printf(MSG_DEBUG
, "EAP-AKA: Use hardcoded Kc and SRES values for "
195 /* These hardcoded Kc and SRES values are used for testing.
196 * Could consider making them configurable. */
197 os_memset(data
->res
, '2', EAP_AKA_RES_MAX_LEN
);
198 data
->res_len
= EAP_AKA_RES_MAX_LEN
;
199 os_memset(data
->ik
, '3', EAP_AKA_IK_LEN
);
200 os_memset(data
->ck
, '4', EAP_AKA_CK_LEN
);
202 u8 autn
[EAP_AKA_AUTN_LEN
];
203 os_memset(autn
, '1', EAP_AKA_AUTN_LEN
);
204 if (os_memcmp(autn
, data
->autn
, EAP_AKA_AUTN_LEN
) != 0) {
205 wpa_printf(MSG_WARNING
, "EAP-AKA: AUTN did not match "
206 "with expected value");
212 static int test_resync
= 1;
214 /* Test Resynchronization */
222 #else /* CONFIG_USIM_HARDCODED */
224 wpa_printf(MSG_DEBUG
, "EAP-AKA: No UMTS authentication algorith "
228 #endif /* CONFIG_USIM_HARDCODED */
232 #define CLEAR_PSEUDONYM 0x01
233 #define CLEAR_REAUTH_ID 0x02
234 #define CLEAR_EAP_ID 0x04
236 static void eap_aka_clear_identities(struct eap_aka_data
*data
, int id
)
238 wpa_printf(MSG_DEBUG
, "EAP-AKA: forgetting old%s%s%s",
239 id
& CLEAR_PSEUDONYM
? " pseudonym" : "",
240 id
& CLEAR_REAUTH_ID
? " reauth_id" : "",
241 id
& CLEAR_EAP_ID
? " eap_id" : "");
242 if (id
& CLEAR_PSEUDONYM
) {
243 os_free(data
->pseudonym
);
244 data
->pseudonym
= NULL
;
245 data
->pseudonym_len
= 0;
247 if (id
& CLEAR_REAUTH_ID
) {
248 os_free(data
->reauth_id
);
249 data
->reauth_id
= NULL
;
250 data
->reauth_id_len
= 0;
252 if (id
& CLEAR_EAP_ID
) {
253 os_free(data
->last_eap_identity
);
254 data
->last_eap_identity
= NULL
;
255 data
->last_eap_identity_len
= 0;
260 static int eap_aka_learn_ids(struct eap_aka_data
*data
,
261 struct eap_sim_attrs
*attr
)
263 if (attr
->next_pseudonym
) {
264 os_free(data
->pseudonym
);
265 data
->pseudonym
= os_malloc(attr
->next_pseudonym_len
);
266 if (data
->pseudonym
== NULL
) {
267 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No memory for "
271 os_memcpy(data
->pseudonym
, attr
->next_pseudonym
,
272 attr
->next_pseudonym_len
);
273 data
->pseudonym_len
= attr
->next_pseudonym_len
;
274 wpa_hexdump_ascii(MSG_DEBUG
,
275 "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
277 data
->pseudonym_len
);
280 if (attr
->next_reauth_id
) {
281 os_free(data
->reauth_id
);
282 data
->reauth_id
= os_malloc(attr
->next_reauth_id_len
);
283 if (data
->reauth_id
== NULL
) {
284 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No memory for "
288 os_memcpy(data
->reauth_id
, attr
->next_reauth_id
,
289 attr
->next_reauth_id_len
);
290 data
->reauth_id_len
= attr
->next_reauth_id_len
;
291 wpa_hexdump_ascii(MSG_DEBUG
,
292 "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
294 data
->reauth_id_len
);
301 static int eap_aka_add_id_msg(struct eap_aka_data
*data
,
302 const struct wpabuf
*msg
)
307 if (data
->id_msgs
== NULL
) {
308 data
->id_msgs
= wpabuf_dup(msg
);
309 return data
->id_msgs
== NULL
? -1 : 0;
312 if (wpabuf_resize(&data
->id_msgs
, wpabuf_len(msg
)) < 0)
314 wpabuf_put_buf(data
->id_msgs
, msg
);
320 static void eap_aka_add_checkcode(struct eap_aka_data
*data
,
321 struct eap_sim_msg
*msg
)
325 u8 hash
[SHA256_MAC_LEN
];
327 wpa_printf(MSG_DEBUG
, " AT_CHECKCODE");
329 if (data
->id_msgs
== NULL
) {
331 * No EAP-AKA/Identity packets were exchanged - send empty
334 eap_sim_msg_add(msg
, EAP_SIM_AT_CHECKCODE
, 0, NULL
, 0);
338 /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
339 addr
= wpabuf_head(data
->id_msgs
);
340 len
= wpabuf_len(data
->id_msgs
);
341 wpa_hexdump(MSG_MSGDUMP
, "EAP-AKA: AT_CHECKCODE data", addr
, len
);
343 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
)
344 sha256_vector(1, &addr
, &len
, hash
);
346 #endif /* EAP_AKA_PRIME */
347 sha1_vector(1, &addr
, &len
, hash
);
349 eap_sim_msg_add(msg
, EAP_SIM_AT_CHECKCODE
, 0, hash
,
350 data
->eap_method
== EAP_TYPE_AKA_PRIME
?
351 EAP_AKA_PRIME_CHECKCODE_LEN
: EAP_AKA_CHECKCODE_LEN
);
355 static int eap_aka_verify_checkcode(struct eap_aka_data
*data
,
356 const u8
*checkcode
, size_t checkcode_len
)
360 u8 hash
[SHA256_MAC_LEN
];
363 if (checkcode
== NULL
)
366 if (data
->id_msgs
== NULL
) {
367 if (checkcode_len
!= 0) {
368 wpa_printf(MSG_DEBUG
, "EAP-AKA: Checkcode from server "
369 "indicates that AKA/Identity messages were "
370 "used, but they were not");
376 hash_len
= data
->eap_method
== EAP_TYPE_AKA_PRIME
?
377 EAP_AKA_PRIME_CHECKCODE_LEN
: EAP_AKA_CHECKCODE_LEN
;
379 if (checkcode_len
!= hash_len
) {
380 wpa_printf(MSG_DEBUG
, "EAP-AKA: Checkcode from server "
381 "indicates that AKA/Identity message were not "
382 "used, but they were");
386 /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
387 addr
= wpabuf_head(data
->id_msgs
);
388 len
= wpabuf_len(data
->id_msgs
);
390 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
)
391 sha256_vector(1, &addr
, &len
, hash
);
393 #endif /* EAP_AKA_PRIME */
394 sha1_vector(1, &addr
, &len
, hash
);
396 if (os_memcmp(hash
, checkcode
, hash_len
) != 0) {
397 wpa_printf(MSG_DEBUG
, "EAP-AKA: Mismatch in AT_CHECKCODE");
405 static struct wpabuf
* eap_aka_client_error(struct eap_aka_data
*data
, u8 id
,
408 struct eap_sim_msg
*msg
;
410 eap_aka_state(data
, FAILURE
);
411 data
->num_id_req
= 0;
412 data
->num_notification
= 0;
414 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, data
->eap_method
,
415 EAP_AKA_SUBTYPE_CLIENT_ERROR
);
416 eap_sim_msg_add(msg
, EAP_SIM_AT_CLIENT_ERROR_CODE
, err
, NULL
, 0);
417 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
421 static struct wpabuf
* eap_aka_authentication_reject(struct eap_aka_data
*data
,
424 struct eap_sim_msg
*msg
;
426 eap_aka_state(data
, FAILURE
);
427 data
->num_id_req
= 0;
428 data
->num_notification
= 0;
430 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Authentication-Reject "
432 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, data
->eap_method
,
433 EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT
);
434 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
438 static struct wpabuf
* eap_aka_synchronization_failure(
439 struct eap_aka_data
*data
, u8 id
)
441 struct eap_sim_msg
*msg
;
443 data
->num_id_req
= 0;
444 data
->num_notification
= 0;
446 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Synchronization-Failure "
448 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, data
->eap_method
,
449 EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE
);
450 wpa_printf(MSG_DEBUG
, " AT_AUTS");
451 eap_sim_msg_add_full(msg
, EAP_SIM_AT_AUTS
, data
->auts
,
453 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
457 static struct wpabuf
* eap_aka_response_identity(struct eap_sm
*sm
,
458 struct eap_aka_data
*data
,
460 enum eap_sim_id_req id_req
)
462 const u8
*identity
= NULL
;
463 size_t identity_len
= 0;
464 struct eap_sim_msg
*msg
;
467 if (id_req
== ANY_ID
&& data
->reauth_id
) {
468 identity
= data
->reauth_id
;
469 identity_len
= data
->reauth_id_len
;
471 } else if ((id_req
== ANY_ID
|| id_req
== FULLAUTH_ID
) &&
473 identity
= data
->pseudonym
;
474 identity_len
= data
->pseudonym_len
;
475 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
);
476 } else if (id_req
!= NO_ID_REQ
) {
477 identity
= eap_get_config_identity(sm
, &identity_len
);
479 eap_aka_clear_identities(data
, CLEAR_PSEUDONYM
|
483 if (id_req
!= NO_ID_REQ
)
484 eap_aka_clear_identities(data
, CLEAR_EAP_ID
);
486 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Identity (id=%d)", id
);
487 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, data
->eap_method
,
488 EAP_AKA_SUBTYPE_IDENTITY
);
491 wpa_hexdump_ascii(MSG_DEBUG
, " AT_IDENTITY",
492 identity
, identity_len
);
493 eap_sim_msg_add(msg
, EAP_SIM_AT_IDENTITY
, identity_len
,
494 identity
, identity_len
);
497 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
501 static struct wpabuf
* eap_aka_response_challenge(struct eap_aka_data
*data
,
504 struct eap_sim_msg
*msg
;
506 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Challenge (id=%d)", id
);
507 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, data
->eap_method
,
508 EAP_AKA_SUBTYPE_CHALLENGE
);
509 wpa_printf(MSG_DEBUG
, " AT_RES");
510 eap_sim_msg_add(msg
, EAP_SIM_AT_RES
, data
->res_len
* 8,
511 data
->res
, data
->res_len
);
512 eap_aka_add_checkcode(data
, msg
);
513 if (data
->use_result_ind
) {
514 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
515 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
517 wpa_printf(MSG_DEBUG
, " AT_MAC");
518 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
519 return eap_sim_msg_finish(msg
, data
->k_aut
, (u8
*) "", 0);
523 static struct wpabuf
* eap_aka_response_reauth(struct eap_aka_data
*data
,
524 u8 id
, int counter_too_small
,
527 struct eap_sim_msg
*msg
;
528 unsigned int counter
;
530 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Reauthentication (id=%d)",
532 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, data
->eap_method
,
533 EAP_AKA_SUBTYPE_REAUTHENTICATION
);
534 wpa_printf(MSG_DEBUG
, " AT_IV");
535 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
536 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
, EAP_SIM_AT_ENCR_DATA
);
538 if (counter_too_small
) {
539 wpa_printf(MSG_DEBUG
, " *AT_COUNTER_TOO_SMALL");
540 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER_TOO_SMALL
, 0, NULL
, 0);
541 counter
= data
->counter_too_small
;
543 counter
= data
->counter
;
545 wpa_printf(MSG_DEBUG
, " *AT_COUNTER %d", counter
);
546 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, counter
, NULL
, 0);
548 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
, EAP_SIM_AT_PADDING
)) {
549 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
551 eap_sim_msg_free(msg
);
554 eap_aka_add_checkcode(data
, msg
);
555 if (data
->use_result_ind
) {
556 wpa_printf(MSG_DEBUG
, " AT_RESULT_IND");
557 eap_sim_msg_add(msg
, EAP_SIM_AT_RESULT_IND
, 0, NULL
, 0);
559 wpa_printf(MSG_DEBUG
, " AT_MAC");
560 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
561 return eap_sim_msg_finish(msg
, data
->k_aut
, nonce_s
,
562 EAP_SIM_NONCE_S_LEN
);
566 static struct wpabuf
* eap_aka_response_notification(struct eap_aka_data
*data
,
567 u8 id
, u16 notification
)
569 struct eap_sim_msg
*msg
;
570 u8
*k_aut
= (notification
& 0x4000) == 0 ? data
->k_aut
: NULL
;
572 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Notification (id=%d)", id
);
573 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, data
->eap_method
,
574 EAP_AKA_SUBTYPE_NOTIFICATION
);
575 if (k_aut
&& data
->reauth
) {
576 wpa_printf(MSG_DEBUG
, " AT_IV");
577 wpa_printf(MSG_DEBUG
, " AT_ENCR_DATA");
578 eap_sim_msg_add_encr_start(msg
, EAP_SIM_AT_IV
,
579 EAP_SIM_AT_ENCR_DATA
);
580 wpa_printf(MSG_DEBUG
, " *AT_COUNTER %d", data
->counter
);
581 eap_sim_msg_add(msg
, EAP_SIM_AT_COUNTER
, data
->counter
,
583 if (eap_sim_msg_add_encr_end(msg
, data
->k_encr
,
584 EAP_SIM_AT_PADDING
)) {
585 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to encrypt "
587 eap_sim_msg_free(msg
);
592 wpa_printf(MSG_DEBUG
, " AT_MAC");
593 eap_sim_msg_add_mac(msg
, EAP_SIM_AT_MAC
);
595 return eap_sim_msg_finish(msg
, k_aut
, (u8
*) "", 0);
599 static struct wpabuf
* eap_aka_process_identity(struct eap_sm
*sm
,
600 struct eap_aka_data
*data
,
602 const struct wpabuf
*reqData
,
603 struct eap_sim_attrs
*attr
)
608 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Identity");
611 switch (attr
->id_req
) {
615 if (data
->num_id_req
> 0)
620 if (data
->num_id_req
> 1)
625 if (data
->num_id_req
> 2)
631 wpa_printf(MSG_INFO
, "EAP-AKA: Too many ID requests "
632 "used within one authentication");
633 return eap_aka_client_error(data
, id
,
634 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
637 buf
= eap_aka_response_identity(sm
, data
, id
, attr
->id_req
);
639 if (data
->prev_id
!= id
) {
640 eap_aka_add_id_msg(data
, reqData
);
641 eap_aka_add_id_msg(data
, buf
);
649 static int eap_aka_verify_mac(struct eap_aka_data
*data
,
650 const struct wpabuf
*req
,
651 const u8
*mac
, const u8
*extra
,
654 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
)
655 return eap_sim_verify_mac_sha256(data
->k_aut
, req
, mac
, extra
,
657 return eap_sim_verify_mac(data
->k_aut
, req
, mac
, extra
, extra_len
);
662 static struct wpabuf
* eap_aka_prime_kdf_select(struct eap_aka_data
*data
,
665 struct eap_sim_msg
*msg
;
667 data
->kdf_negotiation
= 1;
669 wpa_printf(MSG_DEBUG
, "Generating EAP-AKA Challenge (id=%d) (KDF "
671 msg
= eap_sim_msg_init(EAP_CODE_RESPONSE
, id
, data
->eap_method
,
672 EAP_AKA_SUBTYPE_CHALLENGE
);
673 wpa_printf(MSG_DEBUG
, " AT_KDF");
674 eap_sim_msg_add(msg
, EAP_SIM_AT_KDF
, kdf
, NULL
, 0);
675 return eap_sim_msg_finish(msg
, NULL
, NULL
, 0);
679 static struct wpabuf
* eap_aka_prime_kdf_neg(struct eap_aka_data
*data
,
680 u8 id
, struct eap_sim_attrs
*attr
)
684 for (i
= 0; i
< attr
->kdf_count
; i
++) {
685 if (attr
->kdf
[i
] == EAP_AKA_PRIME_KDF
)
686 return eap_aka_prime_kdf_select(data
, id
,
690 /* No matching KDF found - fail authentication as if AUTN had been
692 return eap_aka_authentication_reject(data
, id
);
696 static int eap_aka_prime_kdf_valid(struct eap_aka_data
*data
,
697 struct eap_sim_attrs
*attr
)
701 if (attr
->kdf_count
== 0)
704 /* The only allowed (and required) duplication of a KDF is the addition
705 * of the selected KDF into the beginning of the list. */
707 if (data
->kdf_negotiation
) {
708 if (attr
->kdf
[0] != data
->kdf
) {
709 wpa_printf(MSG_WARNING
, "EAP-AKA': The server did not "
710 "accept the selected KDF");
714 for (i
= 1; i
< attr
->kdf_count
; i
++) {
715 if (attr
->kdf
[i
] == data
->kdf
)
718 if (i
== attr
->kdf_count
&&
719 attr
->kdf_count
< EAP_AKA_PRIME_KDF_MAX
) {
720 wpa_printf(MSG_WARNING
, "EAP-AKA': The server did not "
721 "duplicate the selected KDF");
725 /* TODO: should check that the list is identical to the one
726 * used in the previous Challenge message apart from the added
727 * entry in the beginning. */
730 for (i
= data
->kdf
? 1 : 0; i
< attr
->kdf_count
; i
++) {
731 for (j
= i
+ 1; j
< attr
->kdf_count
; j
++) {
732 if (attr
->kdf
[i
] == attr
->kdf
[j
]) {
733 wpa_printf(MSG_WARNING
, "EAP-AKA': The server "
734 "included a duplicated KDF");
742 #endif /* EAP_AKA_PRIME */
745 static struct wpabuf
* eap_aka_process_challenge(struct eap_sm
*sm
,
746 struct eap_aka_data
*data
,
748 const struct wpabuf
*reqData
,
749 struct eap_sim_attrs
*attr
)
754 struct eap_sim_attrs eattr
;
756 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Challenge");
758 if (attr
->checkcode
&&
759 eap_aka_verify_checkcode(data
, attr
->checkcode
,
760 attr
->checkcode_len
)) {
761 wpa_printf(MSG_WARNING
, "EAP-AKA: Invalid AT_CHECKCODE in the "
763 return eap_aka_client_error(data
, id
,
764 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
768 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
769 if (!attr
->kdf_input
|| attr
->kdf_input_len
== 0) {
770 wpa_printf(MSG_WARNING
, "EAP-AKA': Challenge message "
771 "did not include non-empty AT_KDF_INPUT");
772 /* Fail authentication as if AUTN had been incorrect */
773 return eap_aka_authentication_reject(data
, id
);
775 os_free(data
->network_name
);
776 data
->network_name
= os_malloc(attr
->kdf_input_len
);
777 if (data
->network_name
== NULL
) {
778 wpa_printf(MSG_WARNING
, "EAP-AKA': No memory for "
779 "storing Network Name");
780 return eap_aka_authentication_reject(data
, id
);
782 os_memcpy(data
->network_name
, attr
->kdf_input
,
783 attr
->kdf_input_len
);
784 data
->network_name_len
= attr
->kdf_input_len
;
785 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA': Network Name "
787 data
->network_name
, data
->network_name_len
);
788 /* TODO: check Network Name per 3GPP.33.402 */
790 if (!eap_aka_prime_kdf_valid(data
, attr
))
791 return eap_aka_authentication_reject(data
, id
);
793 if (attr
->kdf
[0] != EAP_AKA_PRIME_KDF
)
794 return eap_aka_prime_kdf_neg(data
, id
, attr
);
796 data
->kdf
= EAP_AKA_PRIME_KDF
;
797 wpa_printf(MSG_DEBUG
, "EAP-AKA': KDF %d selected", data
->kdf
);
800 if (data
->eap_method
== EAP_TYPE_AKA
&& attr
->bidding
) {
801 u16 flags
= WPA_GET_BE16(attr
->bidding
);
802 if ((flags
& EAP_AKA_BIDDING_FLAG_D
) &&
803 eap_allowed_method(sm
, EAP_VENDOR_IETF
,
804 EAP_TYPE_AKA_PRIME
)) {
805 wpa_printf(MSG_WARNING
, "EAP-AKA: Bidding down from "
806 "AKA' to AKA detected");
807 /* Fail authentication as if AUTN had been incorrect */
808 return eap_aka_authentication_reject(data
, id
);
811 #endif /* EAP_AKA_PRIME */
814 if (!attr
->mac
|| !attr
->rand
|| !attr
->autn
) {
815 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
816 "did not include%s%s%s",
817 !attr
->mac
? " AT_MAC" : "",
818 !attr
->rand
? " AT_RAND" : "",
819 !attr
->autn
? " AT_AUTN" : "");
820 return eap_aka_client_error(data
, id
,
821 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
823 os_memcpy(data
->rand
, attr
->rand
, EAP_AKA_RAND_LEN
);
824 os_memcpy(data
->autn
, attr
->autn
, EAP_AKA_AUTN_LEN
);
826 res
= eap_aka_umts_auth(sm
, data
);
828 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication "
830 return eap_aka_authentication_reject(data
, id
);
831 } else if (res
== -2) {
832 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication "
833 "failed (AUTN seq# -> AUTS)");
834 return eap_aka_synchronization_failure(data
, id
);
836 wpa_printf(MSG_WARNING
, "EAP-AKA: UMTS authentication failed");
837 return eap_aka_client_error(data
, id
,
838 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
841 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
842 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
843 * needed 6-octet SQN ^ AK for CK',IK' derivation */
844 u16 amf
= WPA_GET_BE16(data
->autn
+ 6);
845 if (!(amf
& 0x8000)) {
846 wpa_printf(MSG_WARNING
, "EAP-AKA': AMF separation bit "
847 "not set (AMF=0x%4x)", amf
);
848 return eap_aka_authentication_reject(data
, id
);
850 eap_aka_prime_derive_ck_ik_prime(data
->ck
, data
->ik
,
853 data
->network_name_len
);
855 #endif /* EAP_AKA_PRIME */
856 if (data
->last_eap_identity
) {
857 identity
= data
->last_eap_identity
;
858 identity_len
= data
->last_eap_identity_len
;
859 } else if (data
->pseudonym
) {
860 identity
= data
->pseudonym
;
861 identity_len
= data
->pseudonym_len
;
863 identity
= eap_get_config_identity(sm
, &identity_len
);
864 wpa_hexdump_ascii(MSG_DEBUG
, "EAP-AKA: Selected identity for MK "
865 "derivation", identity
, identity_len
);
866 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
867 eap_aka_prime_derive_keys(identity
, identity_len
, data
->ik
,
868 data
->ck
, data
->k_encr
, data
->k_aut
,
869 data
->k_re
, data
->msk
, data
->emsk
);
871 eap_aka_derive_mk(identity
, identity_len
, data
->ik
, data
->ck
,
873 eap_sim_derive_keys(data
->mk
, data
->k_encr
, data
->k_aut
,
874 data
->msk
, data
->emsk
);
876 if (eap_aka_verify_mac(data
, reqData
, attr
->mac
, (u8
*) "", 0)) {
877 wpa_printf(MSG_WARNING
, "EAP-AKA: Challenge message "
878 "used invalid AT_MAC");
879 return eap_aka_client_error(data
, id
,
880 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
883 /* Old reauthentication and pseudonym identities must not be used
884 * anymore. In other words, if no new identities are received, full
885 * authentication will be used on next reauthentication. */
886 eap_aka_clear_identities(data
, CLEAR_PSEUDONYM
| CLEAR_REAUTH_ID
|
889 if (attr
->encr_data
) {
891 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
892 attr
->encr_data_len
, attr
->iv
,
894 if (decrypted
== NULL
) {
895 return eap_aka_client_error(
896 data
, id
, EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
898 eap_aka_learn_ids(data
, &eattr
);
902 if (data
->result_ind
&& attr
->result_ind
)
903 data
->use_result_ind
= 1;
905 if (data
->state
!= FAILURE
&& data
->state
!= RESULT_FAILURE
) {
906 eap_aka_state(data
, data
->use_result_ind
?
907 RESULT_SUCCESS
: SUCCESS
);
910 data
->num_id_req
= 0;
911 data
->num_notification
= 0;
912 /* RFC 4187 specifies that counter is initialized to one after
913 * fullauth, but initializing it to zero makes it easier to implement
914 * reauth verification. */
916 return eap_aka_response_challenge(data
, id
);
920 static int eap_aka_process_notification_reauth(struct eap_aka_data
*data
,
921 struct eap_sim_attrs
*attr
)
923 struct eap_sim_attrs eattr
;
926 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
927 wpa_printf(MSG_WARNING
, "EAP-AKA: Notification message after "
928 "reauth did not include encrypted data");
932 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
933 attr
->encr_data_len
, attr
->iv
, &eattr
,
935 if (decrypted
== NULL
) {
936 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
937 "data from notification message");
941 if (eattr
.counter
< 0 || (size_t) eattr
.counter
!= data
->counter
) {
942 wpa_printf(MSG_WARNING
, "EAP-AKA: Counter in notification "
943 "message does not match with counter in reauth "
954 static int eap_aka_process_notification_auth(struct eap_aka_data
*data
,
955 const struct wpabuf
*reqData
,
956 struct eap_sim_attrs
*attr
)
958 if (attr
->mac
== NULL
) {
959 wpa_printf(MSG_INFO
, "EAP-AKA: no AT_MAC in after_auth "
960 "Notification message");
964 if (eap_aka_verify_mac(data
, reqData
, attr
->mac
, (u8
*) "", 0)) {
965 wpa_printf(MSG_WARNING
, "EAP-AKA: Notification message "
966 "used invalid AT_MAC");
971 eap_aka_process_notification_reauth(data
, attr
)) {
972 wpa_printf(MSG_WARNING
, "EAP-AKA: Invalid notification "
973 "message after reauth");
981 static struct wpabuf
* eap_aka_process_notification(
982 struct eap_sm
*sm
, struct eap_aka_data
*data
, u8 id
,
983 const struct wpabuf
*reqData
, struct eap_sim_attrs
*attr
)
985 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Notification");
986 if (data
->num_notification
> 0) {
987 wpa_printf(MSG_INFO
, "EAP-AKA: too many notification "
988 "rounds (only one allowed)");
989 return eap_aka_client_error(data
, id
,
990 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
992 data
->num_notification
++;
993 if (attr
->notification
== -1) {
994 wpa_printf(MSG_INFO
, "EAP-AKA: no AT_NOTIFICATION in "
995 "Notification message");
996 return eap_aka_client_error(data
, id
,
997 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1000 if ((attr
->notification
& 0x4000) == 0 &&
1001 eap_aka_process_notification_auth(data
, reqData
, attr
)) {
1002 return eap_aka_client_error(data
, id
,
1003 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1006 eap_sim_report_notification(sm
->msg_ctx
, attr
->notification
, 1);
1007 if (attr
->notification
>= 0 && attr
->notification
< 32768) {
1008 eap_aka_state(data
, FAILURE
);
1009 } else if (attr
->notification
== EAP_SIM_SUCCESS
&&
1010 data
->state
== RESULT_SUCCESS
)
1011 eap_aka_state(data
, SUCCESS
);
1012 return eap_aka_response_notification(data
, id
, attr
->notification
);
1016 static struct wpabuf
* eap_aka_process_reauthentication(
1017 struct eap_sm
*sm
, struct eap_aka_data
*data
, u8 id
,
1018 const struct wpabuf
*reqData
, struct eap_sim_attrs
*attr
)
1020 struct eap_sim_attrs eattr
;
1023 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Reauthentication");
1025 if (attr
->checkcode
&&
1026 eap_aka_verify_checkcode(data
, attr
->checkcode
,
1027 attr
->checkcode_len
)) {
1028 wpa_printf(MSG_WARNING
, "EAP-AKA: Invalid AT_CHECKCODE in the "
1030 return eap_aka_client_error(data
, id
,
1031 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1034 if (data
->reauth_id
== NULL
) {
1035 wpa_printf(MSG_WARNING
, "EAP-AKA: Server is trying "
1036 "reauthentication, but no reauth_id available");
1037 return eap_aka_client_error(data
, id
,
1038 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1042 if (eap_aka_verify_mac(data
, reqData
, attr
->mac
, (u8
*) "", 0)) {
1043 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
1044 "did not have valid AT_MAC");
1045 return eap_aka_client_error(data
, id
,
1046 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1049 if (attr
->encr_data
== NULL
|| attr
->iv
== NULL
) {
1050 wpa_printf(MSG_WARNING
, "EAP-AKA: Reauthentication "
1051 "message did not include encrypted data");
1052 return eap_aka_client_error(data
, id
,
1053 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1056 decrypted
= eap_sim_parse_encr(data
->k_encr
, attr
->encr_data
,
1057 attr
->encr_data_len
, attr
->iv
, &eattr
,
1059 if (decrypted
== NULL
) {
1060 wpa_printf(MSG_WARNING
, "EAP-AKA: Failed to parse encrypted "
1061 "data from reauthentication message");
1062 return eap_aka_client_error(data
, id
,
1063 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1066 if (eattr
.nonce_s
== NULL
|| eattr
.counter
< 0) {
1067 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) No%s%s in reauth packet",
1068 !eattr
.nonce_s
? " AT_NONCE_S" : "",
1069 eattr
.counter
< 0 ? " AT_COUNTER" : "");
1071 return eap_aka_client_error(data
, id
,
1072 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1075 if (eattr
.counter
< 0 || (size_t) eattr
.counter
<= data
->counter
) {
1077 wpa_printf(MSG_INFO
, "EAP-AKA: (encr) Invalid counter "
1078 "(%d <= %d)", eattr
.counter
, data
->counter
);
1079 data
->counter_too_small
= eattr
.counter
;
1081 /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
1082 * reauth_id must not be used to start a new reauthentication.
1083 * However, since it was used in the last EAP-Response-Identity
1084 * packet, it has to saved for the following fullauth to be
1085 * used in MK derivation. */
1086 os_free(data
->last_eap_identity
);
1087 data
->last_eap_identity
= data
->reauth_id
;
1088 data
->last_eap_identity_len
= data
->reauth_id_len
;
1089 data
->reauth_id
= NULL
;
1090 data
->reauth_id_len
= 0;
1092 res
= eap_aka_response_reauth(data
, id
, 1, eattr
.nonce_s
);
1097 data
->counter
= eattr
.counter
;
1099 os_memcpy(data
->nonce_s
, eattr
.nonce_s
, EAP_SIM_NONCE_S_LEN
);
1100 wpa_hexdump(MSG_DEBUG
, "EAP-AKA: (encr) AT_NONCE_S",
1101 data
->nonce_s
, EAP_SIM_NONCE_S_LEN
);
1103 if (data
->eap_method
== EAP_TYPE_AKA_PRIME
) {
1104 eap_aka_prime_derive_keys_reauth(data
->k_re
, data
->counter
,
1106 data
->reauth_id_len
,
1108 data
->msk
, data
->emsk
);
1110 eap_sim_derive_keys_reauth(data
->counter
, data
->reauth_id
,
1111 data
->reauth_id_len
,
1112 data
->nonce_s
, data
->mk
,
1113 data
->msk
, data
->emsk
);
1115 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
| CLEAR_EAP_ID
);
1116 eap_aka_learn_ids(data
, &eattr
);
1118 if (data
->result_ind
&& attr
->result_ind
)
1119 data
->use_result_ind
= 1;
1121 if (data
->state
!= FAILURE
&& data
->state
!= RESULT_FAILURE
) {
1122 eap_aka_state(data
, data
->use_result_ind
?
1123 RESULT_SUCCESS
: SUCCESS
);
1126 data
->num_id_req
= 0;
1127 data
->num_notification
= 0;
1128 if (data
->counter
> EAP_AKA_MAX_FAST_REAUTHS
) {
1129 wpa_printf(MSG_DEBUG
, "EAP-AKA: Maximum number of "
1130 "fast reauths performed - force fullauth");
1131 eap_aka_clear_identities(data
, CLEAR_REAUTH_ID
| CLEAR_EAP_ID
);
1134 return eap_aka_response_reauth(data
, id
, 0, data
->nonce_s
);
1138 static struct wpabuf
* eap_aka_process(struct eap_sm
*sm
, void *priv
,
1139 struct eap_method_ret
*ret
,
1140 const struct wpabuf
*reqData
)
1142 struct eap_aka_data
*data
= priv
;
1143 const struct eap_hdr
*req
;
1147 struct eap_sim_attrs attr
;
1150 wpa_hexdump_buf(MSG_DEBUG
, "EAP-AKA: EAP data", reqData
);
1151 if (eap_get_config_identity(sm
, &len
) == NULL
) {
1152 wpa_printf(MSG_INFO
, "EAP-AKA: Identity not configured");
1153 eap_sm_request_identity(sm
);
1158 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, data
->eap_method
, reqData
,
1160 if (pos
== NULL
|| len
< 1) {
1164 req
= wpabuf_head(reqData
);
1165 id
= req
->identifier
;
1166 len
= be_to_host16(req
->length
);
1168 ret
->ignore
= FALSE
;
1169 ret
->methodState
= METHOD_MAY_CONT
;
1170 ret
->decision
= DECISION_FAIL
;
1171 ret
->allowNotifications
= TRUE
;
1174 wpa_printf(MSG_DEBUG
, "EAP-AKA: Subtype=%d", subtype
);
1175 pos
+= 2; /* Reserved */
1177 if (eap_sim_parse_attr(pos
, wpabuf_head_u8(reqData
) + len
, &attr
,
1178 data
->eap_method
== EAP_TYPE_AKA_PRIME
? 2 : 1,
1180 res
= eap_aka_client_error(data
, id
,
1181 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1186 case EAP_AKA_SUBTYPE_IDENTITY
:
1187 res
= eap_aka_process_identity(sm
, data
, id
, reqData
, &attr
);
1189 case EAP_AKA_SUBTYPE_CHALLENGE
:
1190 res
= eap_aka_process_challenge(sm
, data
, id
, reqData
, &attr
);
1192 case EAP_AKA_SUBTYPE_NOTIFICATION
:
1193 res
= eap_aka_process_notification(sm
, data
, id
, reqData
,
1196 case EAP_AKA_SUBTYPE_REAUTHENTICATION
:
1197 res
= eap_aka_process_reauthentication(sm
, data
, id
, reqData
,
1200 case EAP_AKA_SUBTYPE_CLIENT_ERROR
:
1201 wpa_printf(MSG_DEBUG
, "EAP-AKA: subtype Client-Error");
1202 res
= eap_aka_client_error(data
, id
,
1203 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1206 wpa_printf(MSG_DEBUG
, "EAP-AKA: Unknown subtype=%d", subtype
);
1207 res
= eap_aka_client_error(data
, id
,
1208 EAP_AKA_UNABLE_TO_PROCESS_PACKET
);
1213 if (data
->state
== FAILURE
) {
1214 ret
->decision
= DECISION_FAIL
;
1215 ret
->methodState
= METHOD_DONE
;
1216 } else if (data
->state
== SUCCESS
) {
1217 ret
->decision
= data
->use_result_ind
?
1218 DECISION_UNCOND_SUCC
: DECISION_COND_SUCC
;
1220 * It is possible for the server to reply with AKA
1221 * Notification, so we must allow the method to continue and
1222 * not only accept EAP-Success at this point.
1224 ret
->methodState
= data
->use_result_ind
?
1225 METHOD_DONE
: METHOD_MAY_CONT
;
1226 } else if (data
->state
== RESULT_FAILURE
)
1227 ret
->methodState
= METHOD_CONT
;
1228 else if (data
->state
== RESULT_SUCCESS
)
1229 ret
->methodState
= METHOD_CONT
;
1231 if (ret
->methodState
== METHOD_DONE
) {
1232 ret
->allowNotifications
= FALSE
;
1239 static Boolean
eap_aka_has_reauth_data(struct eap_sm
*sm
, void *priv
)
1241 struct eap_aka_data
*data
= priv
;
1242 return data
->pseudonym
|| data
->reauth_id
;
1246 static void eap_aka_deinit_for_reauth(struct eap_sm
*sm
, void *priv
)
1248 struct eap_aka_data
*data
= priv
;
1249 eap_aka_clear_identities(data
, CLEAR_EAP_ID
);
1251 wpabuf_free(data
->id_msgs
);
1252 data
->id_msgs
= NULL
;
1253 data
->use_result_ind
= 0;
1254 data
->kdf_negotiation
= 0;
1258 static void * eap_aka_init_for_reauth(struct eap_sm
*sm
, void *priv
)
1260 struct eap_aka_data
*data
= priv
;
1261 data
->num_id_req
= 0;
1262 data
->num_notification
= 0;
1263 eap_aka_state(data
, CONTINUE
);
1268 static const u8
* eap_aka_get_identity(struct eap_sm
*sm
, void *priv
,
1271 struct eap_aka_data
*data
= priv
;
1273 if (data
->reauth_id
) {
1274 *len
= data
->reauth_id_len
;
1275 return data
->reauth_id
;
1278 if (data
->pseudonym
) {
1279 *len
= data
->pseudonym_len
;
1280 return data
->pseudonym
;
1287 static Boolean
eap_aka_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
1289 struct eap_aka_data
*data
= priv
;
1290 return data
->state
== SUCCESS
;
1294 static u8
* eap_aka_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
1296 struct eap_aka_data
*data
= priv
;
1299 if (data
->state
!= SUCCESS
)
1302 key
= os_malloc(EAP_SIM_KEYING_DATA_LEN
);
1306 *len
= EAP_SIM_KEYING_DATA_LEN
;
1307 os_memcpy(key
, data
->msk
, EAP_SIM_KEYING_DATA_LEN
);
1313 static u8
* eap_aka_get_emsk(struct eap_sm
*sm
, void *priv
, size_t *len
)
1315 struct eap_aka_data
*data
= priv
;
1318 if (data
->state
!= SUCCESS
)
1321 key
= os_malloc(EAP_EMSK_LEN
);
1325 *len
= EAP_EMSK_LEN
;
1326 os_memcpy(key
, data
->emsk
, EAP_EMSK_LEN
);
1332 int eap_peer_aka_register(void)
1334 struct eap_method
*eap
;
1337 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
1338 EAP_VENDOR_IETF
, EAP_TYPE_AKA
, "AKA");
1342 eap
->init
= eap_aka_init
;
1343 eap
->deinit
= eap_aka_deinit
;
1344 eap
->process
= eap_aka_process
;
1345 eap
->isKeyAvailable
= eap_aka_isKeyAvailable
;
1346 eap
->getKey
= eap_aka_getKey
;
1347 eap
->has_reauth_data
= eap_aka_has_reauth_data
;
1348 eap
->deinit_for_reauth
= eap_aka_deinit_for_reauth
;
1349 eap
->init_for_reauth
= eap_aka_init_for_reauth
;
1350 eap
->get_identity
= eap_aka_get_identity
;
1351 eap
->get_emsk
= eap_aka_get_emsk
;
1353 ret
= eap_peer_method_register(eap
);
1355 eap_peer_method_free(eap
);
1360 #ifdef EAP_AKA_PRIME
1361 int eap_peer_aka_prime_register(void)
1363 struct eap_method
*eap
;
1366 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
1367 EAP_VENDOR_IETF
, EAP_TYPE_AKA_PRIME
,
1372 eap
->init
= eap_aka_prime_init
;
1373 eap
->deinit
= eap_aka_deinit
;
1374 eap
->process
= eap_aka_process
;
1375 eap
->isKeyAvailable
= eap_aka_isKeyAvailable
;
1376 eap
->getKey
= eap_aka_getKey
;
1377 eap
->has_reauth_data
= eap_aka_has_reauth_data
;
1378 eap
->deinit_for_reauth
= eap_aka_deinit_for_reauth
;
1379 eap
->init_for_reauth
= eap_aka_init_for_reauth
;
1380 eap
->get_identity
= eap_aka_get_identity
;
1381 eap
->get_emsk
= eap_aka_get_emsk
;
1383 ret
= eap_peer_method_register(eap
);
1385 eap_peer_method_free(eap
);
1389 #endif /* EAP_AKA_PRIME */