Merged EAP-AKA' into eap_aka.c and added it to defconfig/ChangeLog
This commit is contained in:
parent
01b0569437
commit
a9d1364c5f
14 changed files with 579 additions and 2722 deletions
|
@ -15,6 +15,7 @@ ChangeLog for hostapd
|
|||
information (added if ieee80211d=1 in configuration)
|
||||
* fixed WEP authentication (both Open System and Shared Key) with
|
||||
mac80211
|
||||
* added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
|
||||
|
||||
2008-11-23 - v0.6.6
|
||||
* added a new configuration option, wpa_ptk_rekey, that can be used to
|
||||
|
|
|
@ -214,8 +214,6 @@ endif
|
|||
|
||||
ifdef CONFIG_EAP_AKA_PRIME
|
||||
CFLAGS += -DEAP_AKA_PRIME
|
||||
OBJS += ../src/eap_server/eap_aka_prime.o
|
||||
CONFIG_EAP_SIM_COMMON=y
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EAP_SIM_COMMON
|
||||
|
|
|
@ -80,6 +80,10 @@ CONFIG_EAP_TTLS=y
|
|||
# EAP-AKA for the integrated EAP server
|
||||
#CONFIG_EAP_AKA=y
|
||||
|
||||
# EAP-AKA' for the integrated EAP server
|
||||
# This requires CONFIG_EAP_AKA to be enabled, too.
|
||||
#CONFIG_EAP_AKA_PRIME=y
|
||||
|
||||
# EAP-PAX for the integrated EAP server
|
||||
#CONFIG_EAP_PAX=y
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
|
|||
void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac,
|
||||
const u8 *extra, size_t extra_len);
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
|
||||
const u8 *ik, const u8 *ck, u8 *k_encr,
|
||||
u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk);
|
||||
|
@ -109,6 +110,32 @@ void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
|
|||
void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak,
|
||||
const u8 *network_name,
|
||||
size_t network_name_len);
|
||||
#else /* EAP_AKA_PRIME */
|
||||
static inline void eap_aka_prime_derive_keys(const u8 *identity,
|
||||
size_t identity_len,
|
||||
const u8 *ik, const u8 *ck,
|
||||
u8 *k_encr, u8 *k_aut, u8 *k_re,
|
||||
u8 *msk, u8 *emsk)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
|
||||
const u8 *identity,
|
||||
size_t identity_len,
|
||||
const u8 *nonce_s, u8 *msk,
|
||||
u8 *emsk)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int eap_sim_verify_mac_sha256(const u8 *k_aut,
|
||||
const struct wpabuf *req,
|
||||
const u8 *mac, const u8 *extra,
|
||||
size_t extra_len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
||||
|
||||
/* EAP-SIM/AKA Attributes (0..127 non-skippable) */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* EAP peer method: EAP-AKA (RFC 4187)
|
||||
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
|
||||
* EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
|
||||
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -19,6 +19,7 @@
|
|||
#include "pcsc_funcs.h"
|
||||
#include "eap_common/eap_sim_common.h"
|
||||
#include "sha1.h"
|
||||
#include "sha256.h"
|
||||
#include "crypto.h"
|
||||
#include "eap_peer/eap_config.h"
|
||||
#ifdef CONFIG_USIM_SIMULATOR
|
||||
|
@ -31,8 +32,9 @@ struct eap_aka_data {
|
|||
size_t res_len;
|
||||
u8 nonce_s[EAP_SIM_NONCE_S_LEN];
|
||||
u8 mk[EAP_SIM_MK_LEN];
|
||||
u8 k_aut[EAP_SIM_K_AUT_LEN];
|
||||
u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
|
||||
u8 k_encr[EAP_SIM_K_ENCR_LEN];
|
||||
u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
|
||||
u8 msk[EAP_SIM_KEYING_DATA_LEN];
|
||||
u8 emsk[EAP_EMSK_LEN];
|
||||
u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
|
||||
|
@ -54,6 +56,10 @@ struct eap_aka_data {
|
|||
struct wpabuf *id_msgs;
|
||||
int prev_id;
|
||||
int result_ind, use_result_ind;
|
||||
u8 eap_method;
|
||||
u8 *network_name;
|
||||
size_t network_name_len;
|
||||
u16 kdf;
|
||||
};
|
||||
|
||||
|
||||
|
@ -96,6 +102,8 @@ static void * eap_aka_init(struct eap_sm *sm)
|
|||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
data->eap_method = EAP_TYPE_AKA;
|
||||
|
||||
eap_aka_state(data, CONTINUE);
|
||||
data->prev_id = -1;
|
||||
|
||||
|
@ -105,6 +113,18 @@ static void * eap_aka_init(struct eap_sm *sm)
|
|||
}
|
||||
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
static void * eap_aka_prime_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_aka_data *data = eap_aka_init(sm);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
data->eap_method = EAP_TYPE_AKA_PRIME;
|
||||
return data;
|
||||
}
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
||||
|
||||
static void eap_aka_deinit(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_aka_data *data = priv;
|
||||
|
@ -113,6 +133,7 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv)
|
|||
os_free(data->reauth_id);
|
||||
os_free(data->last_eap_identity);
|
||||
wpabuf_free(data->id_msgs);
|
||||
os_free(data->network_name);
|
||||
os_free(data);
|
||||
}
|
||||
}
|
||||
|
@ -302,7 +323,7 @@ static void eap_aka_add_checkcode(struct eap_aka_data *data,
|
|||
{
|
||||
const u8 *addr;
|
||||
size_t len;
|
||||
u8 hash[SHA1_MAC_LEN];
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
|
||||
wpa_printf(MSG_DEBUG, " AT_CHECKCODE");
|
||||
|
||||
|
@ -315,14 +336,18 @@ static void eap_aka_add_checkcode(struct eap_aka_data *data,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
|
||||
/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
|
||||
addr = wpabuf_head(data->id_msgs);
|
||||
len = wpabuf_len(data->id_msgs);
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME)
|
||||
sha256_vector(1, &addr, &len, hash);
|
||||
else
|
||||
sha1_vector(1, &addr, &len, hash);
|
||||
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
|
||||
EAP_AKA_CHECKCODE_LEN);
|
||||
data->eap_method == EAP_TYPE_AKA_PRIME ?
|
||||
EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
|
||||
}
|
||||
|
||||
|
||||
|
@ -331,7 +356,8 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data,
|
|||
{
|
||||
const u8 *addr;
|
||||
size_t len;
|
||||
u8 hash[SHA1_MAC_LEN];
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
size_t hash_len;
|
||||
|
||||
if (checkcode == NULL)
|
||||
return -1;
|
||||
|
@ -346,19 +372,25 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (checkcode_len != EAP_AKA_CHECKCODE_LEN) {
|
||||
hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
|
||||
EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
|
||||
|
||||
if (checkcode_len != hash_len) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
|
||||
"indicates that AKA/Identity message were not "
|
||||
"used, but they were");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
|
||||
/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
|
||||
addr = wpabuf_head(data->id_msgs);
|
||||
len = wpabuf_len(data->id_msgs);
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME)
|
||||
sha256_vector(1, &addr, &len, hash);
|
||||
else
|
||||
sha1_vector(1, &addr, &len, hash);
|
||||
|
||||
if (os_memcmp(hash, checkcode, EAP_AKA_CHECKCODE_LEN) != 0) {
|
||||
if (os_memcmp(hash, checkcode, hash_len) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
|
||||
return -1;
|
||||
}
|
||||
|
@ -376,7 +408,7 @@ static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
|
|||
data->num_id_req = 0;
|
||||
data->num_notification = 0;
|
||||
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_CLIENT_ERROR);
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
|
||||
return eap_sim_msg_finish(msg, NULL, NULL, 0);
|
||||
|
@ -394,7 +426,7 @@ static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
|
|||
|
||||
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
|
||||
"(id=%d)", id);
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
|
||||
return eap_sim_msg_finish(msg, NULL, NULL, 0);
|
||||
}
|
||||
|
@ -410,7 +442,7 @@ static struct wpabuf * eap_aka_synchronization_failure(
|
|||
|
||||
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
|
||||
"(id=%d)", id);
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
|
||||
wpa_printf(MSG_DEBUG, " AT_AUTS");
|
||||
eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
|
||||
|
@ -449,7 +481,7 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
|
|||
eap_aka_clear_identities(data, CLEAR_EAP_ID);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_IDENTITY);
|
||||
|
||||
if (identity) {
|
||||
|
@ -469,7 +501,7 @@ static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data,
|
|||
struct eap_sim_msg *msg;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id);
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_CHALLENGE);
|
||||
wpa_printf(MSG_DEBUG, " AT_RES");
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8,
|
||||
|
@ -494,7 +526,7 @@ static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data,
|
|||
|
||||
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
|
||||
id);
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_REAUTHENTICATION);
|
||||
wpa_printf(MSG_DEBUG, " AT_IV");
|
||||
wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
|
||||
|
@ -535,7 +567,7 @@ static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data,
|
|||
u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id);
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_NOTIFICATION);
|
||||
if (k_aut && data->reauth) {
|
||||
wpa_printf(MSG_DEBUG, " AT_IV");
|
||||
|
@ -611,6 +643,101 @@ static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
|
|||
}
|
||||
|
||||
|
||||
static int eap_aka_verify_mac(struct eap_aka_data *data,
|
||||
const struct wpabuf *req,
|
||||
const u8 *mac, const u8 *extra,
|
||||
size_t extra_len)
|
||||
{
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME)
|
||||
return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
|
||||
extra_len);
|
||||
return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
|
||||
}
|
||||
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
|
||||
u8 id, u16 kdf)
|
||||
{
|
||||
struct eap_sim_msg *msg;
|
||||
|
||||
data->kdf = kdf;
|
||||
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF "
|
||||
"select)", id);
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_CHALLENGE);
|
||||
wpa_printf(MSG_DEBUG, " AT_KDF");
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
|
||||
return eap_sim_msg_finish(msg, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data,
|
||||
u8 id, struct eap_sim_attrs *attr)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < attr->kdf_count; i++) {
|
||||
if (attr->kdf[i] == EAP_AKA_PRIME_KDF)
|
||||
return eap_aka_prime_kdf_select(data, id,
|
||||
EAP_AKA_PRIME_KDF);
|
||||
}
|
||||
|
||||
/* No matching KDF found - fail authentication as if AUTN had been
|
||||
* incorrect */
|
||||
return eap_aka_authentication_reject(data, id);
|
||||
}
|
||||
|
||||
|
||||
static int eap_aka_prime_kdf_valid(struct eap_aka_data *data,
|
||||
struct eap_sim_attrs *attr)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
if (attr->kdf_count == 0)
|
||||
return 0;
|
||||
|
||||
/* The only allowed (and required) duplication of a KDF is the addition
|
||||
* of the selected KDF into the beginning of the list. */
|
||||
|
||||
if (data->kdf) {
|
||||
if (attr->kdf[0] != data->kdf) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
|
||||
"accept the selected KDF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 1; i < attr->kdf_count; i++) {
|
||||
if (attr->kdf[i] == data->kdf)
|
||||
break;
|
||||
}
|
||||
if (i == attr->kdf_count &&
|
||||
attr->kdf_count < EAP_AKA_PRIME_KDF_MAX) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
|
||||
"duplicate the selected KDF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: should check that the list is identical to the one
|
||||
* used in the previous Challenge message apart from the added
|
||||
* entry in the beginning. */
|
||||
}
|
||||
|
||||
for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) {
|
||||
for (j = i + 1; j < attr->kdf_count; j++) {
|
||||
if (attr->kdf[i] == attr->kdf[j]) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA': The server "
|
||||
"included a duplicated KDF");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
||||
|
||||
static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
|
||||
struct eap_aka_data *data,
|
||||
u8 id,
|
||||
|
@ -633,6 +760,52 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
|
|||
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
|
||||
}
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
if (!attr->kdf_input || attr->kdf_input_len == 0) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message "
|
||||
"did not include non-empty AT_KDF_INPUT");
|
||||
/* Fail authentication as if AUTN had been incorrect */
|
||||
return eap_aka_authentication_reject(data, id);
|
||||
}
|
||||
os_free(data->network_name);
|
||||
data->network_name = os_malloc(attr->kdf_input_len);
|
||||
if (data->network_name == NULL) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
|
||||
"storing Network Name");
|
||||
return eap_aka_authentication_reject(data, id);
|
||||
}
|
||||
os_memcpy(data->network_name, attr->kdf_input,
|
||||
attr->kdf_input_len);
|
||||
data->network_name_len = attr->kdf_input_len;
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
|
||||
"(AT_KDF_INPUT)",
|
||||
data->network_name, data->network_name_len);
|
||||
/* TODO: check Network Name per 3GPP.33.402 */
|
||||
|
||||
if (!eap_aka_prime_kdf_valid(data, attr))
|
||||
return eap_aka_authentication_reject(data, id);
|
||||
|
||||
if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
|
||||
return eap_aka_prime_kdf_neg(data, id, attr);
|
||||
|
||||
data->kdf = EAP_AKA_PRIME_KDF;
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
|
||||
}
|
||||
|
||||
if (data->eap_method == EAP_TYPE_AKA && attr->bidding) {
|
||||
u16 flags = WPA_GET_BE16(attr->bidding);
|
||||
if ((flags & EAP_AKA_BIDDING_FLAG_D) &&
|
||||
eap_allowed_method(sm, EAP_VENDOR_IETF,
|
||||
EAP_TYPE_AKA_PRIME)) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from "
|
||||
"AKA' to AKA detected");
|
||||
/* Fail authentication as if AUTN had been incorrect */
|
||||
return eap_aka_authentication_reject(data, id);
|
||||
}
|
||||
}
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
||||
data->reauth = 0;
|
||||
if (!attr->mac || !attr->rand || !attr->autn) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
|
||||
|
@ -660,6 +833,16 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
|
|||
return eap_aka_client_error(data, id,
|
||||
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
|
||||
}
|
||||
#ifdef EAP_AKA_PRIME
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
|
||||
* needed 6-octet SQN ^AK for CK',IK' derivation */
|
||||
eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
|
||||
data->autn,
|
||||
data->network_name,
|
||||
data->network_name_len);
|
||||
}
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
if (data->last_eap_identity) {
|
||||
identity = data->last_eap_identity;
|
||||
identity_len = data->last_eap_identity_len;
|
||||
|
@ -670,12 +853,17 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
|
|||
identity = eap_get_config_identity(sm, &identity_len);
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
|
||||
"derivation", identity, identity_len);
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
eap_aka_prime_derive_keys(identity, identity_len, data->ik,
|
||||
data->ck, data->k_encr, data->k_aut,
|
||||
data->k_re, data->msk, data->emsk);
|
||||
} else {
|
||||
eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
|
||||
data->mk);
|
||||
eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
|
||||
data->emsk);
|
||||
if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
|
||||
{
|
||||
eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
|
||||
data->msk, data->emsk);
|
||||
}
|
||||
if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
|
||||
"used invalid AT_MAC");
|
||||
return eap_aka_client_error(data, id,
|
||||
|
@ -763,8 +951,7 @@ static int eap_aka_process_notification_auth(struct eap_aka_data *data,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
|
||||
{
|
||||
if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
|
||||
"used invalid AT_MAC");
|
||||
return -1;
|
||||
|
@ -842,8 +1029,7 @@ static struct wpabuf * eap_aka_process_reauthentication(
|
|||
}
|
||||
|
||||
data->reauth = 1;
|
||||
if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
|
||||
{
|
||||
if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
|
||||
"did not have valid AT_MAC");
|
||||
return eap_aka_client_error(data, id,
|
||||
|
@ -882,10 +1068,6 @@ static struct wpabuf * eap_aka_process_reauthentication(
|
|||
"(%d <= %d)", eattr.counter, data->counter);
|
||||
data->counter_too_small = eattr.counter;
|
||||
|
||||
eap_sim_derive_keys_reauth(eattr.counter, data->reauth_id,
|
||||
data->reauth_id_len, eattr.nonce_s,
|
||||
data->mk, NULL, NULL);
|
||||
|
||||
/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
|
||||
* reauth_id must not be used to start a new reauthentication.
|
||||
* However, since it was used in the last EAP-Response-Identity
|
||||
|
@ -908,10 +1090,18 @@ static struct wpabuf * eap_aka_process_reauthentication(
|
|||
wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
|
||||
data->nonce_s, EAP_SIM_NONCE_S_LEN);
|
||||
|
||||
eap_sim_derive_keys_reauth(data->counter,
|
||||
data->reauth_id, data->reauth_id_len,
|
||||
data->nonce_s, data->mk, data->msk,
|
||||
data->emsk);
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
|
||||
data->reauth_id,
|
||||
data->reauth_id_len,
|
||||
data->nonce_s,
|
||||
data->msk, data->emsk);
|
||||
} else {
|
||||
eap_sim_derive_keys_reauth(data->counter, data->reauth_id,
|
||||
data->reauth_id_len,
|
||||
data->nonce_s, data->mk,
|
||||
data->msk, data->emsk);
|
||||
}
|
||||
eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
|
||||
eap_aka_learn_ids(data, &eattr);
|
||||
|
||||
|
@ -955,7 +1145,8 @@ static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_AKA, reqData, &len);
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
|
||||
&len);
|
||||
if (pos == NULL || len < 1) {
|
||||
ret->ignore = TRUE;
|
||||
return NULL;
|
||||
|
@ -973,7 +1164,8 @@ static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
|
|||
wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
|
||||
pos += 2; /* Reserved */
|
||||
|
||||
if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 1,
|
||||
if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr,
|
||||
data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
|
||||
0)) {
|
||||
res = eap_aka_client_error(data, id,
|
||||
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
|
||||
|
@ -1152,3 +1344,35 @@ int eap_peer_aka_register(void)
|
|||
eap_peer_method_free(eap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
int eap_peer_aka_prime_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
int ret;
|
||||
|
||||
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
|
||||
EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
|
||||
"AKA'");
|
||||
if (eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap->init = eap_aka_prime_init;
|
||||
eap->deinit = eap_aka_deinit;
|
||||
eap->process = eap_aka_process;
|
||||
eap->isKeyAvailable = eap_aka_isKeyAvailable;
|
||||
eap->getKey = eap_aka_getKey;
|
||||
eap->has_reauth_data = eap_aka_has_reauth_data;
|
||||
eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
|
||||
eap->init_for_reauth = eap_aka_init_for_reauth;
|
||||
eap->get_identity = eap_aka_get_identity;
|
||||
eap->get_emsk = eap_aka_get_emsk;
|
||||
|
||||
ret = eap_peer_method_register(eap);
|
||||
if (ret)
|
||||
eap_peer_method_free(eap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* hostapd / EAP-AKA (RFC 4187)
|
||||
* hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
|
||||
* Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -19,14 +19,16 @@
|
|||
#include "eap_common/eap_sim_common.h"
|
||||
#include "eap_server/eap_sim_db.h"
|
||||
#include "sha1.h"
|
||||
#include "sha256.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
struct eap_aka_data {
|
||||
u8 mk[EAP_SIM_MK_LEN];
|
||||
u8 nonce_s[EAP_SIM_NONCE_S_LEN];
|
||||
u8 k_aut[EAP_SIM_K_AUT_LEN];
|
||||
u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
|
||||
u8 k_encr[EAP_SIM_K_ENCR_LEN];
|
||||
u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
|
||||
u8 msk[EAP_SIM_KEYING_DATA_LEN];
|
||||
u8 emsk[EAP_EMSK_LEN];
|
||||
u8 rand[EAP_AKA_RAND_LEN];
|
||||
|
@ -49,6 +51,10 @@ struct eap_aka_data {
|
|||
|
||||
struct wpabuf *id_msgs;
|
||||
int pending_id;
|
||||
u8 eap_method;
|
||||
u8 *network_name;
|
||||
size_t network_name_len;
|
||||
u16 kdf;
|
||||
};
|
||||
|
||||
|
||||
|
@ -99,6 +105,9 @@ static void * eap_aka_init(struct eap_sm *sm)
|
|||
data = os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
data->eap_method = EAP_TYPE_AKA;
|
||||
|
||||
data->state = IDENTITY;
|
||||
eap_aka_determine_identity(sm, data, 1, 0);
|
||||
data->pending_id = -1;
|
||||
|
@ -107,12 +116,48 @@ static void * eap_aka_init(struct eap_sm *sm)
|
|||
}
|
||||
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
static void * eap_aka_prime_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_aka_data *data;
|
||||
/* TODO: make ANID configurable; see 3GPP TS 24.302 */
|
||||
char *network_name = "WLAN";
|
||||
|
||||
if (sm->eap_sim_db_priv == NULL) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
data->eap_method = EAP_TYPE_AKA_PRIME;
|
||||
data->network_name = os_malloc(os_strlen(network_name));
|
||||
if (data->network_name == NULL) {
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data->network_name_len = os_strlen(network_name);
|
||||
os_memcpy(data->network_name, network_name, data->network_name_len);
|
||||
|
||||
data->state = IDENTITY;
|
||||
eap_aka_determine_identity(sm, data, 1, 0);
|
||||
data->pending_id = -1;
|
||||
|
||||
return data;
|
||||
}
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
||||
|
||||
static void eap_aka_reset(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_aka_data *data = priv;
|
||||
os_free(data->next_pseudonym);
|
||||
os_free(data->next_reauth_id);
|
||||
wpabuf_free(data->id_msgs);
|
||||
os_free(data->network_name);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
@ -141,7 +186,7 @@ static void eap_aka_add_checkcode(struct eap_aka_data *data,
|
|||
{
|
||||
const u8 *addr;
|
||||
size_t len;
|
||||
u8 hash[SHA1_MAC_LEN];
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
|
||||
wpa_printf(MSG_DEBUG, " AT_CHECKCODE");
|
||||
|
||||
|
@ -158,10 +203,14 @@ static void eap_aka_add_checkcode(struct eap_aka_data *data,
|
|||
addr = wpabuf_head(data->id_msgs);
|
||||
len = wpabuf_len(data->id_msgs);
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME)
|
||||
sha256_vector(1, &addr, &len, hash);
|
||||
else
|
||||
sha1_vector(1, &addr, &len, hash);
|
||||
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
|
||||
EAP_AKA_CHECKCODE_LEN);
|
||||
data->eap_method == EAP_TYPE_AKA_PRIME ?
|
||||
EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
|
||||
}
|
||||
|
||||
|
||||
|
@ -170,7 +219,8 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data,
|
|||
{
|
||||
const u8 *addr;
|
||||
size_t len;
|
||||
u8 hash[SHA1_MAC_LEN];
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
size_t hash_len;
|
||||
|
||||
if (checkcode == NULL)
|
||||
return -1;
|
||||
|
@ -185,7 +235,10 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (checkcode_len != EAP_AKA_CHECKCODE_LEN) {
|
||||
hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
|
||||
EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
|
||||
|
||||
if (checkcode_len != hash_len) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
|
||||
"that AKA/Identity message were not used, but they "
|
||||
"were");
|
||||
|
@ -195,9 +248,12 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data,
|
|||
/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
|
||||
addr = wpabuf_head(data->id_msgs);
|
||||
len = wpabuf_len(data->id_msgs);
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME)
|
||||
sha256_vector(1, &addr, &len, hash);
|
||||
else
|
||||
sha1_vector(1, &addr, &len, hash);
|
||||
|
||||
if (os_memcmp(hash, checkcode, EAP_AKA_CHECKCODE_LEN) != 0) {
|
||||
if (os_memcmp(hash, checkcode, hash_len) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
|
||||
return -1;
|
||||
}
|
||||
|
@ -213,7 +269,7 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
|
|||
struct wpabuf *buf;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
|
||||
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_IDENTITY);
|
||||
if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
|
||||
sm->identity_len)) {
|
||||
|
@ -309,11 +365,23 @@ static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
|
|||
struct eap_sim_msg *msg;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
|
||||
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_CHALLENGE);
|
||||
wpa_printf(MSG_DEBUG, " AT_RAND");
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
if (data->kdf) {
|
||||
/* Add the selected KDF into the beginning */
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
|
||||
NULL, 0);
|
||||
}
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
|
||||
NULL, 0);
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
|
||||
data->network_name_len,
|
||||
data->network_name, data->network_name_len);
|
||||
}
|
||||
|
||||
if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
|
||||
eap_sim_msg_free(msg);
|
||||
|
@ -327,6 +395,35 @@ static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
|
|||
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
|
||||
}
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
if (data->eap_method == EAP_TYPE_AKA) {
|
||||
u16 flags = 0;
|
||||
int i;
|
||||
int aka_prime_preferred = 0;
|
||||
|
||||
i = 0;
|
||||
while (sm->user && i < EAP_MAX_METHODS &&
|
||||
(sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
|
||||
sm->user->methods[i].method != EAP_TYPE_NONE)) {
|
||||
if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
|
||||
if (sm->user->methods[i].method ==
|
||||
EAP_TYPE_AKA)
|
||||
break;
|
||||
if (sm->user->methods[i].method ==
|
||||
EAP_TYPE_AKA_PRIME) {
|
||||
aka_prime_preferred = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (aka_prime_preferred)
|
||||
flags |= EAP_AKA_BIDDING_FLAG_D;
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
|
||||
}
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
||||
wpa_printf(MSG_DEBUG, " AT_MAC");
|
||||
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
|
||||
return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
|
||||
|
@ -345,13 +442,21 @@ static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
|
|||
wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
|
||||
data->nonce_s, EAP_SIM_NONCE_S_LEN);
|
||||
|
||||
eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
|
||||
data->emsk);
|
||||
eap_sim_derive_keys_reauth(data->counter, sm->identity,
|
||||
sm->identity_len, data->nonce_s, data->mk,
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
|
||||
sm->identity,
|
||||
sm->identity_len,
|
||||
data->nonce_s,
|
||||
data->msk, data->emsk);
|
||||
} else {
|
||||
eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
|
||||
data->msk, data->emsk);
|
||||
eap_sim_derive_keys_reauth(data->counter, sm->identity,
|
||||
sm->identity_len, data->nonce_s,
|
||||
data->mk, data->msk, data->emsk);
|
||||
}
|
||||
|
||||
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_REAUTHENTICATION);
|
||||
|
||||
if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
|
||||
|
@ -379,7 +484,7 @@ static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
|
|||
struct eap_sim_msg *msg;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
|
||||
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
|
||||
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
|
||||
EAP_AKA_SUBTYPE_NOTIFICATION);
|
||||
wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification);
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
|
||||
|
@ -437,10 +542,12 @@ static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
|
|||
static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
|
||||
struct wpabuf *respData)
|
||||
{
|
||||
struct eap_aka_data *data = priv;
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_AKA, respData, &len);
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
|
||||
&len);
|
||||
if (pos == NULL || len < 3) {
|
||||
wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
|
||||
return TRUE;
|
||||
|
@ -523,17 +630,36 @@ static void eap_aka_determine_identity(struct eap_sm *sm,
|
|||
data->reauth = eap_sim_db_get_reauth_entry(
|
||||
sm->eap_sim_db_priv, sm->identity,
|
||||
sm->identity_len);
|
||||
if (data->reauth &&
|
||||
data->reauth->aka_prime !=
|
||||
(data->eap_method == EAP_TYPE_AKA_PRIME)) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
|
||||
"was for different AKA version");
|
||||
data->reauth = NULL;
|
||||
}
|
||||
if (data->reauth) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
|
||||
"re-authentication");
|
||||
identity = data->reauth->identity;
|
||||
identity_len = data->reauth->identity_len;
|
||||
data->counter = data->reauth->counter;
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
os_memcpy(data->k_encr,
|
||||
data->reauth->k_encr,
|
||||
EAP_SIM_K_ENCR_LEN);
|
||||
os_memcpy(data->k_aut,
|
||||
data->reauth->k_aut,
|
||||
EAP_AKA_PRIME_K_AUT_LEN);
|
||||
os_memcpy(data->k_re,
|
||||
data->reauth->k_re,
|
||||
EAP_AKA_PRIME_K_RE_LEN);
|
||||
} else {
|
||||
os_memcpy(data->mk, data->reauth->mk,
|
||||
EAP_SIM_MK_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (identity == NULL ||
|
||||
eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
|
||||
|
@ -571,6 +697,17 @@ static void eap_aka_determine_identity(struct eap_sm *sm,
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
|
||||
* needed 6-octet SQN ^AK for CK',IK' derivation */
|
||||
eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
|
||||
data->autn,
|
||||
data->network_name,
|
||||
data->network_name_len);
|
||||
}
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
||||
data->reauth = NULL;
|
||||
data->counter = 0; /* reset re-auth counter since this is full auth */
|
||||
|
||||
|
@ -596,10 +733,16 @@ static void eap_aka_determine_identity(struct eap_sm *sm,
|
|||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
|
||||
sm->identity, identity_len);
|
||||
|
||||
eap_aka_derive_mk(sm->identity, identity_len, data->ik, data->ck,
|
||||
data->mk);
|
||||
eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
|
||||
data->emsk);
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
eap_aka_prime_derive_keys(identity, identity_len, data->ik,
|
||||
data->ck, data->k_encr, data->k_aut,
|
||||
data->k_re, data->msk, data->emsk);
|
||||
} else {
|
||||
eap_aka_derive_mk(sm->identity, identity_len, data->ik,
|
||||
data->ck, data->mk);
|
||||
eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
|
||||
data->msk, data->emsk);
|
||||
}
|
||||
|
||||
eap_aka_state(data, CHALLENGE);
|
||||
}
|
||||
|
@ -638,6 +781,18 @@ static void eap_aka_process_identity(struct eap_sm *sm,
|
|||
}
|
||||
|
||||
|
||||
static int eap_aka_verify_mac(struct eap_aka_data *data,
|
||||
const struct wpabuf *req,
|
||||
const u8 *mac, const u8 *extra,
|
||||
size_t extra_len)
|
||||
{
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME)
|
||||
return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
|
||||
extra_len);
|
||||
return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
|
||||
}
|
||||
|
||||
|
||||
static void eap_aka_process_challenge(struct eap_sm *sm,
|
||||
struct eap_aka_data *data,
|
||||
struct wpabuf *respData,
|
||||
|
@ -648,6 +803,31 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
|
|||
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
#if 0
|
||||
/* KDF negotiation; to be enabled only after more than one KDF is
|
||||
* supported */
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME &&
|
||||
attr->kdf_count == 1 && attr->mac == NULL) {
|
||||
if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
|
||||
"unknown KDF");
|
||||
data->notification =
|
||||
EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
|
||||
eap_aka_state(data, NOTIFICATION);
|
||||
return;
|
||||
}
|
||||
|
||||
data->kdf = attr->kdf[0];
|
||||
|
||||
/* Allow negotiation to continue with the selected KDF by
|
||||
* sending another Challenge message */
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
||||
if (attr->checkcode &&
|
||||
eap_aka_verify_checkcode(data, attr->checkcode,
|
||||
attr->checkcode_len)) {
|
||||
|
@ -658,7 +838,7 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
|
|||
return;
|
||||
}
|
||||
if (attr->mac == NULL ||
|
||||
eap_sim_verify_mac(data->k_aut, respData, attr->mac, NULL, 0)) {
|
||||
eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
|
||||
"did not include valid AT_MAC");
|
||||
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
|
||||
|
@ -707,10 +887,21 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
|
|||
data->next_pseudonym = NULL;
|
||||
}
|
||||
if (data->next_reauth_id) {
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
|
||||
identity,
|
||||
identity_len,
|
||||
data->next_reauth_id,
|
||||
data->counter + 1,
|
||||
data->k_encr, data->k_aut,
|
||||
data->k_re);
|
||||
} else {
|
||||
eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
|
||||
identity_len,
|
||||
data->next_reauth_id, data->counter + 1,
|
||||
data->next_reauth_id,
|
||||
data->counter + 1,
|
||||
data->mk);
|
||||
}
|
||||
data->next_reauth_id = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -763,7 +954,7 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
|
|||
wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
|
||||
|
||||
if (attr->mac == NULL ||
|
||||
eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
|
||||
eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
|
||||
EAP_SIM_NONCE_S_LEN)) {
|
||||
wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
|
||||
"did not include valid AT_MAC");
|
||||
|
@ -833,9 +1024,21 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
|
|||
data->next_pseudonym = NULL;
|
||||
}
|
||||
if (data->next_reauth_id) {
|
||||
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
|
||||
eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
|
||||
identity,
|
||||
identity_len,
|
||||
data->next_reauth_id,
|
||||
data->counter + 1,
|
||||
data->k_encr, data->k_aut,
|
||||
data->k_re);
|
||||
} else {
|
||||
eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
|
||||
identity_len, data->next_reauth_id,
|
||||
data->counter + 1, data->mk);
|
||||
identity_len,
|
||||
data->next_reauth_id,
|
||||
data->counter + 1,
|
||||
data->mk);
|
||||
}
|
||||
data->next_reauth_id = NULL;
|
||||
} else {
|
||||
eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
|
||||
|
@ -898,7 +1101,8 @@ static void eap_aka_process(struct eap_sm *sm, void *priv,
|
|||
size_t len;
|
||||
struct eap_sim_attrs attr;
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_AKA, respData, &len);
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
|
||||
&len);
|
||||
if (pos == NULL || len < 3)
|
||||
return;
|
||||
|
||||
|
@ -914,7 +1118,9 @@ static void eap_aka_process(struct eap_sm *sm, void *priv,
|
|||
return;
|
||||
}
|
||||
|
||||
if (eap_sim_parse_attr(pos, end, &attr, 1, 0)) {
|
||||
if (eap_sim_parse_attr(pos, end, &attr,
|
||||
data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
|
||||
0)) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
|
||||
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
|
||||
eap_aka_state(data, NOTIFICATION);
|
||||
|
@ -1031,3 +1237,34 @@ int eap_server_aka_register(void)
|
|||
eap_server_method_free(eap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
int eap_server_aka_prime_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
int ret;
|
||||
|
||||
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
|
||||
EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
|
||||
"AKA'");
|
||||
if (eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap->init = eap_aka_prime_init;
|
||||
eap->reset = eap_aka_reset;
|
||||
eap->buildReq = eap_aka_buildReq;
|
||||
eap->check = eap_aka_check;
|
||||
eap->process = eap_aka_process;
|
||||
eap->isDone = eap_aka_isDone;
|
||||
eap->getKey = eap_aka_getKey;
|
||||
eap->isSuccess = eap_aka_isSuccess;
|
||||
eap->get_emsk = eap_aka_get_emsk;
|
||||
|
||||
ret = eap_server_method_register(eap);
|
||||
if (ret)
|
||||
eap_server_method_free(eap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,6 +10,8 @@ ChangeLog for wpa_supplicant
|
|||
wpa_supplicant.conf (see WPS section in the example configuration
|
||||
file); new wpa_cli commands wps_pin, wps_pbc, and wps_reg are used to
|
||||
manage WPS negotiation; see README-WPS for more details
|
||||
* added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
|
||||
|
||||
2008-11-23 - v0.6.6
|
||||
* added Milenage SIM/USIM emulator for EAP-SIM/EAP-AKA
|
||||
(can be used to simulate test SIM/USIM card with a known private key;
|
||||
|
|
|
@ -431,14 +431,9 @@ ifdef CONFIG_EAP_AKA_PRIME
|
|||
# EAP-AKA'
|
||||
ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
|
||||
CFLAGS += -DEAP_AKA_PRIME_DYNAMIC
|
||||
EAPDYN += ../src/eap_peer/eap_aka_prime.so
|
||||
else
|
||||
CFLAGS += -DEAP_AKA_PRIME
|
||||
OBJS += ../src/eap_peer/eap_aka_prime.o
|
||||
OBJS_h += ../src/eap_server/eap_aka_prime.o
|
||||
endif
|
||||
CONFIG_IEEE8021X_EAPOL=y
|
||||
CONFIG_EAP_SIM_COMMON=y
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EAP_SIM_COMMON
|
||||
|
|
|
@ -156,6 +156,10 @@ CONFIG_EAP_LEAP=y
|
|||
# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
|
||||
#CONFIG_EAP_AKA=y
|
||||
|
||||
# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
|
||||
# This requires CONFIG_EAP_AKA to be enabled, too.
|
||||
#CONFIG_EAP_AKA_PRIME=y
|
||||
|
||||
# Enable USIM simulator (Milenage) for EAP-AKA
|
||||
#CONFIG_USIM_SIMULATOR=y
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ EAP-TTLS/EAP-GPSK - - - - - - - - - - + -
|
|||
EAP-TTLS + TNC - - - - - + - - - - + -
|
||||
EAP-SIM + - - ? - + - ? - - + -
|
||||
EAP-AKA - - - - - + - - - - + -
|
||||
EAP-AKA' - - - - - - - - - - + -
|
||||
EAP-PSK +7 - - - - + - - - - + -
|
||||
EAP-PAX - - - - - + - - - - + -
|
||||
EAP-SAKE - - - - - - - - - - + -
|
||||
|
|
|
@ -53,6 +53,7 @@ RADIUS backend authentication server) ("WPA-Enterprise")</li>
|
|||
<li>EAP-TTLS/CHAP</li>
|
||||
<li>EAP-SIM</li>
|
||||
<li>EAP-AKA</li>
|
||||
<li>EAP-AKA'</li>
|
||||
<li>EAP-PAX</li>
|
||||
<li>EAP-PSK</li>
|
||||
<li>EAP-SAKE</li>
|
||||
|
@ -266,7 +267,7 @@ Internet Systems Consortium (ISC).
|
|||
<address><a href="mailto:j@w1.fi">Jouni Malinen</a></address>
|
||||
<!-- Created: Sun Jan 2 17:20:17 PST 2005 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Fri Nov 28 18:27:51 EET 2008
|
||||
Last modified: Sun Dec 7 19:24:25 EET 2008
|
||||
<!-- hhmts end -->
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -63,6 +63,7 @@ build for x86 target).</p>
|
|||
<li>EAP-TTLS/CHAP</li>
|
||||
<li>EAP-SIM</li>
|
||||
<li>EAP-AKA</li>
|
||||
<li>EAP-AKA'</li>
|
||||
<li>EAP-PSK</li>
|
||||
<li>EAP-FAST</li>
|
||||
<li>EAP-PAX</li>
|
||||
|
@ -356,7 +357,7 @@ Internet Systems Consortium (ISC).
|
|||
<address><a href="mailto:j@w1.fi">Jouni Malinen</a></address>
|
||||
<!-- Created: Sat May 22 21:41:58 PDT 2004 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Fri Nov 28 18:27:42 EET 2008
|
||||
Last modified: Sun Dec 7 19:24:16 EET 2008
|
||||
<!-- hhmts end -->
|
||||
</div>
|
||||
</body>
|
||||
|
|
Loading…
Reference in a new issue