GC wpa_supplicant 0.4.9
[dragonfly/port-amd64.git] / contrib / hostapd-0.4.9 / eap_sim.c
blobfa60cf54d1c705656fbd80f001f67a44d68cf29c
1 /*
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
10 * license.
12 * See README and COPYING for more details.
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <netinet/in.h>
20 #include "hostapd.h"
21 #include "common.h"
22 #include "crypto.h"
23 #include "eap_i.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
43 #define KC_LEN 8
44 #define SRES_LEN 4
45 #define EAP_SIM_MAX_FAST_REAUTHS 1000
47 #define EAP_SIM_MAX_CHAL 3
49 struct eap_sim_data {
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];
58 int num_chal;
59 enum { START, CHALLENGE, SUCCESS, FAILURE } state;
63 static const char * eap_sim_state_txt(int state)
65 switch (state) {
66 case START:
67 return "START";
68 case CHALLENGE:
69 return "CHALLENGE";
70 case SUCCESS:
71 return "SUCCESS";
72 case FAILURE:
73 return "FAILURE";
74 default:
75 return "Unknown?!";
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));
85 data->state = 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");
95 return NULL;
98 data = malloc(sizeof(*data));
99 if (data == NULL)
100 return data;
101 memset(data, 0, sizeof(*data));
102 data->state = START;
104 return data;
108 static void eap_sim_reset(struct eap_sm *sm, void *priv)
110 struct eap_sim_data *data = priv;
111 free(data);
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;
119 u8 ver[2];
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,
124 sm->identity_len)) {
125 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
127 ver[0] = 0;
128 ver[1] = EAP_SIM_VERSION;
129 eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
130 ver, 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,
152 size_t *reqDataLen)
154 struct eap_sim_data *data = priv;
156 switch (data->state) {
157 case START:
158 return eap_sim_build_start(sm, data, id, reqDataLen);
159 case CHALLENGE:
160 return eap_sim_build_challenge(sm, data, id, reqDataLen);
161 default:
162 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
163 "buildReq", data->state);
164 break;
166 return NULL;
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;
175 u8 *pos, subtype;
176 size_t len;
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");
183 return TRUE;
185 subtype = pos[1];
187 if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
188 return FALSE;
190 switch (data->state) {
191 case START:
192 if (subtype != EAP_SIM_SUBTYPE_START) {
193 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
194 "subtype %d", subtype);
195 return TRUE;
197 break;
198 case CHALLENGE:
199 if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
200 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
201 "subtype %d", subtype);
202 return TRUE;
204 break;
205 default:
206 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
207 "processing a response", data->state);
208 return TRUE;
211 return FALSE;
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];
228 size_t len[5];
230 addr[0] = identity;
231 addr[1] = kc;
232 addr[2] = nonce_mt;
233 addr[3] = ver_list;
234 addr[4] = sel_ver;
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);
242 ver_list[0] = 0;
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);
264 return;
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);
271 return;
274 if (attr->identity) {
275 free(sm->identity);
276 sm->identity = malloc(attr->identity_len);
277 if (sm->identity) {
278 memcpy(sm->identity, attr->identity,
279 attr->identity_len);
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"
287 " user name");
288 eap_sim_state(data, FAILURE);
289 return;
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,
297 EAP_SIM_MAX_CHAL,
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);
303 return;
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,
309 (u8 *) data->kc);
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);
327 return;
330 wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
331 "correct AT_MAC");
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;
352 u8 *pos, subtype;
353 size_t len;
354 struct eap_sim_attrs attr;
356 resp = (struct eap_hdr *) respData;
357 pos = (u8 *) (resp + 1);
358 subtype = pos[1];
359 len = ntohs(resp->length);
360 pos += 4;
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);
365 return;
368 if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
369 eap_sim_process_client_error(sm, data, respData, len, &attr);
370 return;
373 switch (data->state) {
374 case START:
375 eap_sim_process_start(sm, data, respData, len, &attr);
376 break;
377 case CHALLENGE:
378 eap_sim_process_challenge(sm, data, respData, len, &attr);
379 break;
380 default:
381 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
382 "process", data->state);
383 break;
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;
398 u8 *key;
400 if (data->state != SUCCESS)
401 return NULL;
403 key = malloc(EAP_SIM_KEYING_DATA_LEN);
404 if (key == NULL)
405 return NULL;
406 memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
407 *len = EAP_SIM_KEYING_DATA_LEN;
408 return key;
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,
422 .name = "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,