?? eap_aka.c
字號:
/* * 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 * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include "common.h"#include "eap_server/eap_i.h"#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_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]; u8 autn[EAP_AKA_AUTN_LEN]; u8 ck[EAP_AKA_CK_LEN]; u8 ik[EAP_AKA_IK_LEN]; u8 res[EAP_AKA_RES_MAX_LEN]; size_t res_len; enum { IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE } state; char *next_pseudonym; char *next_reauth_id; u16 counter; struct eap_sim_reauth *reauth; int auts_reported; /* whether the current AUTS has been reported to the * eap_sim_db */ u16 notification; int use_result_ind; struct wpabuf *id_msgs; int pending_id; u8 eap_method; u8 *network_name; size_t network_name_len; u16 kdf;};static void eap_aka_determine_identity(struct eap_sm *sm, struct eap_aka_data *data, int before_identity, int after_reauth);static const char * eap_aka_state_txt(int state){ switch (state) { case IDENTITY: return "IDENTITY"; case CHALLENGE: return "CHALLENGE"; case REAUTH: return "REAUTH"; case SUCCESS: return "SUCCESS"; case FAILURE: return "FAILURE"; case NOTIFICATION: return "NOTIFICATION"; default: return "Unknown?!"; }}static void eap_aka_state(struct eap_aka_data *data, int state){ wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s", eap_aka_state_txt(data->state), eap_aka_state_txt(state)); data->state = state;}static void * eap_aka_init(struct eap_sm *sm){ struct eap_aka_data *data; 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; data->state = IDENTITY; eap_aka_determine_identity(sm, data, 1, 0); data->pending_id = -1; return data;}#ifdef EAP_AKA_PRIMEstatic 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);}static int eap_aka_add_id_msg(struct eap_aka_data *data, const struct wpabuf *msg){ if (msg == NULL) return -1; if (data->id_msgs == NULL) { data->id_msgs = wpabuf_dup(msg); return data->id_msgs == NULL ? -1 : 0; } if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0) return -1; wpabuf_put_buf(data->id_msgs, msg); return 0;}static void eap_aka_add_checkcode(struct eap_aka_data *data, struct eap_sim_msg *msg){ const u8 *addr; size_t len; u8 hash[SHA256_MAC_LEN]; wpa_printf(MSG_DEBUG, " AT_CHECKCODE"); if (data->id_msgs == NULL) { /* * No EAP-AKA/Identity packets were exchanged - send empty * checkcode. */ eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0); return; } /* Checkcode is SHA1 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, data->eap_method == EAP_TYPE_AKA_PRIME ? EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);}static int eap_aka_verify_checkcode(struct eap_aka_data *data, const u8 *checkcode, size_t checkcode_len){ const u8 *addr; size_t len; u8 hash[SHA256_MAC_LEN]; size_t hash_len; if (checkcode == NULL) return -1; if (data->id_msgs == NULL) { if (checkcode_len != 0) { wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer " "indicates that AKA/Identity messages were " "used, but they were not"); return -1; } return 0; } 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"); return -1; } /* 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, hash_len) != 0) { wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE"); return -1; } return 0;}static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm, struct eap_aka_data *data, u8 id){ struct eap_sim_msg *msg; struct wpabuf *buf; wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity"); 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)) { wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); } else { /* * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is * ignored and the AKA/Identity is used to request the * identity. */ wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); } buf = eap_sim_msg_finish(msg, NULL, NULL, 0); if (eap_aka_add_id_msg(data, buf) < 0) { wpabuf_free(buf); return NULL; } data->pending_id = id; return buf;}static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data, struct eap_sim_msg *msg, u16 counter, const u8 *nonce_s){ os_free(data->next_pseudonym); data->next_pseudonym = eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1); os_free(data->next_reauth_id); if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) { data->next_reauth_id = eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1); } else { wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication " "count exceeded - force full authentication"); data->next_reauth_id = NULL; } if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && counter == 0 && nonce_s == NULL) return 0; wpa_printf(MSG_DEBUG, " AT_IV"); wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); if (counter > 0) { wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); } if (nonce_s) { wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, EAP_SIM_NONCE_S_LEN); } if (data->next_pseudonym) { wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", data->next_pseudonym); eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, os_strlen(data->next_pseudonym), (u8 *) data->next_pseudonym, os_strlen(data->next_pseudonym)); } if (data->next_reauth_id) { wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", data->next_reauth_id); eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, os_strlen(data->next_reauth_id), (u8 *) data->next_reauth_id, os_strlen(data->next_reauth_id)); } if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " "AT_ENCR_DATA"); return -1; } return 0;}static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, struct eap_aka_data *data, u8 id){ struct eap_sim_msg *msg; wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge"); 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); wpa_printf(MSG_DEBUG, " AT_AUTN"); 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 */ wpa_printf(MSG_DEBUG, " AT_KDF"); eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf, NULL, 0); } wpa_printf(MSG_DEBUG, " AT_KDF"); eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF, NULL, 0); wpa_printf(MSG_DEBUG, " AT_KDF_INPUT"); 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); return NULL; } eap_aka_add_checkcode(data, msg); if (sm->eap_sim_aka_result_ind) { wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 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);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -