2 * hostapd / EAP-SIM (draft-haverinen-pppext-eap-sim-15.txt)
3 * Copyright (c) 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.
18 #include <netinet/in.h>
24 #include "eap_sim_common.h"
25 #include "eap_sim_db.h"
28 #define EAP_SIM_VERSION 1
30 /* EAP-SIM Subtypes */
31 #define EAP_SIM_SUBTYPE_START 10
32 #define EAP_SIM_SUBTYPE_CHALLENGE 11
33 #define EAP_SIM_SUBTYPE_NOTIFICATION 12
34 #define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
35 #define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
37 /* AT_CLIENT_ERROR_CODE error codes */
38 #define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
39 #define EAP_SIM_UNSUPPORTED_VERSION 1
40 #define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
41 #define EAP_SIM_RAND_NOT_FRESH 3
45 #define EAP_SIM_MAX_FAST_REAUTHS 1000
47 #define EAP_SIM_MAX_CHAL 3
50 u8 mk[EAP_SIM_MK_LEN];
51 u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
52 u8 k_aut[EAP_SIM_K_AUT_LEN];
53 u8 k_encr[EAP_SIM_K_ENCR_LEN];
54 u8 msk[EAP_SIM_KEYING_DATA_LEN];
55 u8 kc[EAP_SIM_MAX_CHAL][KC_LEN];
56 u8 sres[EAP_SIM_MAX_CHAL][SRES_LEN];
57 u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
59 enum { START, CHALLENGE, SUCCESS, FAILURE } state;
63 static const char * eap_sim_state_txt(int state)
80 static void eap_sim_state(struct eap_sim_data *data, int state)
82 wpa_printf(MSG_DEBUG, "EAP-SIM %s -> %s",
83 eap_sim_state_txt(data->state),
84 eap_sim_state_txt(state));
89 static void * eap_sim_init(struct eap_sm *sm)
91 struct eap_sim_data *data;
93 if (sm->eap_sim_db_priv == NULL) {
94 wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
98 data = malloc(sizeof(*data));
101 memset(data, 0, sizeof(*data));
108 static void eap_sim_reset(struct eap_sm *sm, void *priv)
110 struct eap_sim_data *data = priv;
115 static u8 * eap_sim_build_start(struct eap_sm *sm, struct eap_sim_data *data,
116 int id, size_t *reqDataLen)
118 struct eap_sim_msg *msg;
121 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
122 EAP_SIM_SUBTYPE_START);
123 if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
125 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
128 ver[1] = EAP_SIM_VERSION;
129 eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
131 return eap_sim_msg_finish(msg, reqDataLen, NULL, NULL, 0);
135 static u8 * eap_sim_build_challenge(struct eap_sm *sm,
136 struct eap_sim_data *data,
137 int id, size_t *reqDataLen)
139 struct eap_sim_msg *msg;
141 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
142 EAP_SIM_SUBTYPE_CHALLENGE);
143 eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
144 data->num_chal * GSM_RAND_LEN);
145 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
146 return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, data->nonce_mt,
147 EAP_SIM_NONCE_MT_LEN);
151 static u8 * eap_sim_buildReq(struct eap_sm *sm, void *priv, int id,
154 struct eap_sim_data *data = priv;
156 switch (data->state) {
158 return eap_sim_build_start(sm, data, id, reqDataLen);
160 return eap_sim_build_challenge(sm, data, id, reqDataLen);
162 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
163 "buildReq", data->state);
170 static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
171 u8 *respData, size_t respDataLen)
173 struct eap_sim_data *data = priv;
174 struct eap_hdr *resp;
178 resp = (struct eap_hdr *) respData;
179 pos = (u8 *) (resp + 1);
180 if (respDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_SIM ||
181 (len = ntohs(resp->length)) > respDataLen) {
182 wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
187 if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
190 switch (data->state) {
192 if (subtype != EAP_SIM_SUBTYPE_START) {
193 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
194 "subtype %d", subtype);
199 if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
200 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
201 "subtype %d", subtype);
206 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
207 "processing a response", data->state);
215 static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
217 return version == EAP_SIM_VERSION;
221 static void eap_sim_derive_mk(struct eap_sim_data *data,
222 const u8 *identity, size_t identity_len,
223 const u8 *nonce_mt, int selected_version,
224 int num_chal, const u8 *kc)
226 u8 sel_ver[2], ver_list[2];
227 const unsigned char *addr[5];
236 len[0] = identity_len;
237 len[1] = num_chal * KC_LEN;
238 len[2] = EAP_SIM_NONCE_MT_LEN;
239 len[3] = sizeof(ver_list);
240 len[4] = sizeof(sel_ver);
243 ver_list[1] = EAP_SIM_VERSION;
244 sel_ver[0] = selected_version >> 8;
245 sel_ver[1] = selected_version & 0xff;
247 /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
248 sha1_vector(5, addr, len, data->mk);
249 wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", data->mk, EAP_SIM_MK_LEN);
253 static void eap_sim_process_start(struct eap_sm *sm,
254 struct eap_sim_data *data,
255 u8 *respData, size_t respDataLen,
256 struct eap_sim_attrs *attr)
258 wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
260 if (attr->nonce_mt == NULL || attr->selected_version < 0) {
261 wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
262 "required attributes");
263 eap_sim_state(data, FAILURE);
267 if (!eap_sim_supported_ver(data, attr->selected_version)) {
268 wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
269 "version %d", attr->selected_version);
270 eap_sim_state(data, FAILURE);
274 if (attr->identity) {
276 sm->identity = malloc(attr->identity_len);
278 memcpy(sm->identity, attr->identity,
280 sm->identity_len = attr->identity_len;
284 if (sm->identity == NULL || sm->identity_len < 1 ||
285 sm->identity[0] != '1') {
286 wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
288 eap_sim_state(data, FAILURE);
292 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
293 sm->identity, sm->identity_len);
295 data->num_chal = eap_sim_db_get_gsm_triplets(
296 sm->eap_sim_db_priv, sm->identity, sm->identity_len,
298 (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres);
299 if (data->num_chal < 2) {
300 wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
301 "authentication triplets for the peer");
302 eap_sim_state(data, FAILURE);
306 memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
307 eap_sim_derive_mk(data, sm->identity, sm->identity_len, attr->nonce_mt,
308 attr->selected_version, data->num_chal,
310 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
312 eap_sim_state(data, CHALLENGE);
316 static void eap_sim_process_challenge(struct eap_sm *sm,
317 struct eap_sim_data *data,
318 u8 *respData, size_t respDataLen,
319 struct eap_sim_attrs *attr)
321 if (attr->mac == NULL ||
322 eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
323 (u8 *) data->sres, data->num_chal * SRES_LEN)) {
324 wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
325 "did not include valid AT_MAC");
326 eap_sim_state(data, FAILURE);
330 wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
332 eap_sim_state(data, SUCCESS);
336 static void eap_sim_process_client_error(struct eap_sm *sm,
337 struct eap_sim_data *data,
338 u8 *respData, size_t respDataLen,
339 struct eap_sim_attrs *attr)
341 wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
342 attr->client_error_code);
343 eap_sim_state(data, FAILURE);
347 static void eap_sim_process(struct eap_sm *sm, void *priv,
348 u8 *respData, size_t respDataLen)
350 struct eap_sim_data *data = priv;
351 struct eap_hdr *resp;
354 struct eap_sim_attrs attr;
356 resp = (struct eap_hdr *) respData;
357 pos = (u8 *) (resp + 1);
359 len = ntohs(resp->length);
362 if (eap_sim_parse_attr(pos, respData + len, &attr, 0, 0)) {
363 wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
364 eap_sim_state(data, FAILURE);
368 if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
369 eap_sim_process_client_error(sm, data, respData, len, &attr);
373 switch (data->state) {
375 eap_sim_process_start(sm, data, respData, len, &attr);
378 eap_sim_process_challenge(sm, data, respData, len, &attr);
381 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
382 "process", data->state);
388 static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
390 struct eap_sim_data *data = priv;
391 return data->state == SUCCESS || data->state == FAILURE;
395 static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
397 struct eap_sim_data *data = priv;
400 if (data->state != SUCCESS)
403 key = malloc(EAP_SIM_KEYING_DATA_LEN);
406 memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
407 *len = EAP_SIM_KEYING_DATA_LEN;
412 static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
414 struct eap_sim_data *data = priv;
415 return data->state == SUCCESS;
419 const struct eap_method eap_method_sim =
421 .method = EAP_TYPE_SIM,
423 .init = eap_sim_init,
424 .reset = eap_sim_reset,
425 .buildReq = eap_sim_buildReq,
426 .check = eap_sim_check,
427 .process = eap_sim_process,
428 .isDone = eap_sim_isDone,
429 .getKey = eap_sim_getKey,
430 .isSuccess = eap_sim_isSuccess,