Branch data Line data Source code
1 : : /*
2 : : * EAP peer method: EAP-SIM (RFC 4186)
3 : : * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : */
8 : :
9 : : #include "includes.h"
10 : :
11 : : #include "common.h"
12 : : #include "pcsc_funcs.h"
13 : : #include "crypto/milenage.h"
14 : : #include "crypto/random.h"
15 : : #include "eap_peer/eap_i.h"
16 : : #include "eap_config.h"
17 : : #include "eap_common/eap_sim_common.h"
18 : :
19 : :
20 : : struct eap_sim_data {
21 : : u8 *ver_list;
22 : : size_t ver_list_len;
23 : : int selected_version;
24 : : size_t min_num_chal, num_chal;
25 : :
26 : : u8 kc[3][EAP_SIM_KC_LEN];
27 : : u8 sres[3][EAP_SIM_SRES_LEN];
28 : : u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN];
29 : : u8 mk[EAP_SIM_MK_LEN];
30 : : u8 k_aut[EAP_SIM_K_AUT_LEN];
31 : : u8 k_encr[EAP_SIM_K_ENCR_LEN];
32 : : u8 msk[EAP_SIM_KEYING_DATA_LEN];
33 : : u8 emsk[EAP_EMSK_LEN];
34 : : u8 rand[3][GSM_RAND_LEN];
35 : :
36 : : int num_id_req, num_notification;
37 : : u8 *pseudonym;
38 : : size_t pseudonym_len;
39 : : u8 *reauth_id;
40 : : size_t reauth_id_len;
41 : : int reauth;
42 : : unsigned int counter, counter_too_small;
43 : : u8 *last_eap_identity;
44 : : size_t last_eap_identity_len;
45 : : enum {
46 : : CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
47 : : } state;
48 : : int result_ind, use_result_ind;
49 : : };
50 : :
51 : :
52 : : #ifndef CONFIG_NO_STDOUT_DEBUG
53 : 20 : static const char * eap_sim_state_txt(int state)
54 : : {
55 [ + - - + : 20 : switch (state) {
- - ]
56 : : case CONTINUE:
57 : 14 : return "CONTINUE";
58 : : case RESULT_SUCCESS:
59 : 0 : return "RESULT_SUCCESS";
60 : : case RESULT_FAILURE:
61 : 0 : return "RESULT_FAILURE";
62 : : case SUCCESS:
63 : 6 : return "SUCCESS";
64 : : case FAILURE:
65 : 0 : return "FAILURE";
66 : : default:
67 : 20 : return "?";
68 : : }
69 : : }
70 : : #endif /* CONFIG_NO_STDOUT_DEBUG */
71 : :
72 : :
73 : 10 : static void eap_sim_state(struct eap_sim_data *data, int state)
74 : : {
75 : 10 : wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
76 : 10 : eap_sim_state_txt(data->state),
77 : : eap_sim_state_txt(state));
78 : 10 : data->state = state;
79 : 10 : }
80 : :
81 : :
82 : 4 : static void * eap_sim_init(struct eap_sm *sm)
83 : : {
84 : : struct eap_sim_data *data;
85 : 4 : struct eap_peer_config *config = eap_get_config(sm);
86 : :
87 : 4 : data = os_zalloc(sizeof(*data));
88 [ - + ]: 4 : if (data == NULL)
89 : 0 : return NULL;
90 : :
91 [ - + ]: 4 : if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
92 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
93 : : "for NONCE_MT");
94 : 0 : os_free(data);
95 : 0 : return NULL;
96 : : }
97 : :
98 : 4 : data->min_num_chal = 2;
99 [ + - ][ - + ]: 4 : if (config && config->phase1) {
100 : 0 : char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
101 [ # # ]: 0 : if (pos) {
102 : 0 : data->min_num_chal = atoi(pos + 17);
103 [ # # ][ # # ]: 0 : if (data->min_num_chal < 2 || data->min_num_chal > 3) {
104 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
105 : : "sim_min_num_chal configuration "
106 : : "(%lu, expected 2 or 3)",
107 : : (unsigned long) data->min_num_chal);
108 : 0 : os_free(data);
109 : 0 : return NULL;
110 : : }
111 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
112 : : "challenges to %lu",
113 : : (unsigned long) data->min_num_chal);
114 : : }
115 : :
116 : 0 : data->result_ind = os_strstr(config->phase1, "result_ind=1") !=
117 : : NULL;
118 : : }
119 : :
120 [ + - ][ - + ]: 4 : if (config && config->anonymous_identity) {
121 : 0 : data->pseudonym = os_malloc(config->anonymous_identity_len);
122 [ # # ]: 0 : if (data->pseudonym) {
123 : 0 : os_memcpy(data->pseudonym, config->anonymous_identity,
124 : : config->anonymous_identity_len);
125 : 0 : data->pseudonym_len = config->anonymous_identity_len;
126 : : }
127 : : }
128 : :
129 : 4 : eap_sim_state(data, CONTINUE);
130 : :
131 : 4 : return data;
132 : : }
133 : :
134 : :
135 : 4 : static void eap_sim_deinit(struct eap_sm *sm, void *priv)
136 : : {
137 : 4 : struct eap_sim_data *data = priv;
138 [ + - ]: 4 : if (data) {
139 : 4 : os_free(data->ver_list);
140 : 4 : os_free(data->pseudonym);
141 : 4 : os_free(data->reauth_id);
142 : 4 : os_free(data->last_eap_identity);
143 : 4 : os_free(data);
144 : : }
145 : 4 : }
146 : :
147 : :
148 : 2 : static int eap_sim_ext_sim_req(struct eap_sm *sm, struct eap_sim_data *data)
149 : : {
150 : : char req[200], *pos, *end;
151 : : size_t i;
152 : :
153 : 2 : wpa_printf(MSG_DEBUG, "EAP-SIM: Use external SIM processing");
154 : 2 : pos = req;
155 : 2 : end = pos + sizeof(req);
156 : 2 : pos += os_snprintf(pos, end - pos, "GSM-AUTH");
157 [ + + ]: 8 : for (i = 0; i < data->num_chal; i++) {
158 : 6 : pos += os_snprintf(pos, end - pos, ":");
159 : 6 : pos += wpa_snprintf_hex(pos, end - pos, data->rand[i],
160 : : GSM_RAND_LEN);
161 : : }
162 : :
163 : 2 : eap_sm_request_sim(sm, req);
164 : 2 : return 1;
165 : : }
166 : :
167 : :
168 : 2 : static int eap_sim_ext_sim_result(struct eap_sm *sm, struct eap_sim_data *data,
169 : : struct eap_peer_config *conf)
170 : : {
171 : : char *resp, *pos;
172 : : size_t i;
173 : :
174 : 2 : wpa_printf(MSG_DEBUG,
175 : : "EAP-SIM: Use result from external SIM processing");
176 : :
177 : 2 : resp = conf->external_sim_resp;
178 : 2 : conf->external_sim_resp = NULL;
179 : :
180 [ - + ]: 2 : if (os_strncmp(resp, "GSM-AUTH:", 9) != 0) {
181 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized external SIM processing response");
182 : 0 : os_free(resp);
183 : 0 : return -1;
184 : : }
185 : :
186 : 2 : pos = resp + 9;
187 [ + + ]: 8 : for (i = 0; i < data->num_chal; i++) {
188 : 6 : wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
189 : 6 : data->rand[i], GSM_RAND_LEN);
190 : :
191 [ - + ]: 6 : if (hexstr2bin(pos, data->kc[i], EAP_SIM_KC_LEN) < 0)
192 : 0 : goto invalid;
193 : 6 : wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
194 : 6 : data->kc[i], EAP_SIM_KC_LEN);
195 : 6 : pos += EAP_SIM_KC_LEN * 2;
196 [ - + ]: 6 : if (*pos != ':')
197 : 0 : goto invalid;
198 : 6 : pos++;
199 : :
200 [ - + ]: 6 : if (hexstr2bin(pos, data->sres[i], EAP_SIM_SRES_LEN) < 0)
201 : 0 : goto invalid;
202 : 6 : wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
203 : 6 : data->sres[i], EAP_SIM_SRES_LEN);
204 : 6 : pos += EAP_SIM_SRES_LEN * 2;
205 [ + + ]: 6 : if (i + 1 < data->num_chal) {
206 [ - + ]: 4 : if (*pos != ':')
207 : 0 : goto invalid;
208 : 4 : pos++;
209 : : }
210 : : }
211 : :
212 : 2 : os_free(resp);
213 : 2 : return 0;
214 : :
215 : : invalid:
216 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: Invalid external SIM processing GSM-AUTH response");
217 : 0 : os_free(resp);
218 : 2 : return -1;
219 : : }
220 : :
221 : :
222 : 6 : static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
223 : : {
224 : : struct eap_peer_config *conf;
225 : :
226 : 6 : wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm");
227 : :
228 : 6 : conf = eap_get_config(sm);
229 [ - + ]: 6 : if (conf == NULL)
230 : 0 : return -1;
231 : :
232 [ + + ]: 6 : if (sm->external_sim) {
233 [ + + ]: 4 : if (conf->external_sim_resp)
234 : 2 : return eap_sim_ext_sim_result(sm, data, conf);
235 : : else
236 : 2 : return eap_sim_ext_sim_req(sm, data);
237 : : }
238 : :
239 [ - + ]: 2 : if (conf->pcsc) {
240 [ # # ]: 0 : if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
241 [ # # ]: 0 : data->sres[0], data->kc[0]) ||
242 : 0 : scard_gsm_auth(sm->scard_ctx, data->rand[1],
243 [ # # ]: 0 : data->sres[1], data->kc[1]) ||
244 [ # # ]: 0 : (data->num_chal > 2 &&
245 : 0 : scard_gsm_auth(sm->scard_ctx, data->rand[2],
246 : : data->sres[2], data->kc[2]))) {
247 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM "
248 : : "authentication could not be completed");
249 : 0 : return -1;
250 : : }
251 : 0 : return 0;
252 : : }
253 : :
254 : : #ifdef CONFIG_SIM_SIMULATOR
255 [ + - ]: 2 : if (conf->password) {
256 : : u8 opc[16], k[16];
257 : : const char *pos;
258 : : size_t i;
259 : 2 : wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage "
260 : : "implementation for authentication");
261 [ - + ]: 2 : if (conf->password_len < 65) {
262 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage "
263 : : "password");
264 : 0 : return -1;
265 : : }
266 : 2 : pos = (const char *) conf->password;
267 [ - + ]: 2 : if (hexstr2bin(pos, k, 16))
268 : 0 : return -1;
269 : 2 : pos += 32;
270 [ - + ]: 2 : if (*pos != ':')
271 : 0 : return -1;
272 : 2 : pos++;
273 : :
274 [ - + ]: 2 : if (hexstr2bin(pos, opc, 16))
275 : 0 : return -1;
276 : :
277 [ + + ]: 8 : for (i = 0; i < data->num_chal; i++) {
278 [ - + ]: 6 : if (gsm_milenage(opc, k, data->rand[i],
279 : 12 : data->sres[i], data->kc[i])) {
280 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: "
281 : : "GSM-Milenage authentication "
282 : : "could not be completed");
283 : 0 : return -1;
284 : : }
285 : 6 : wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
286 : 6 : data->rand[i], GSM_RAND_LEN);
287 : 6 : wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
288 : 6 : data->sres[i], EAP_SIM_SRES_LEN);
289 : 6 : wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
290 : 6 : data->kc[i], EAP_SIM_KC_LEN);
291 : : }
292 : 2 : return 0;
293 : : }
294 : : #endif /* CONFIG_SIM_SIMULATOR */
295 : :
296 : : #ifdef CONFIG_SIM_HARDCODED
297 : : /* These hardcoded Kc and SRES values are used for testing. RAND to
298 : : * KC/SREC mapping is very bogus as far as real authentication is
299 : : * concerned, but it is quite useful for cases where the AS is rotating
300 : : * the order of pre-configured values. */
301 : : {
302 : : size_t i;
303 : :
304 : : wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES "
305 : : "values for testing");
306 : :
307 : : for (i = 0; i < data->num_chal; i++) {
308 : : if (data->rand[i][0] == 0xaa) {
309 : : os_memcpy(data->kc[i],
310 : : "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
311 : : EAP_SIM_KC_LEN);
312 : : os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
313 : : EAP_SIM_SRES_LEN);
314 : : } else if (data->rand[i][0] == 0xbb) {
315 : : os_memcpy(data->kc[i],
316 : : "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
317 : : EAP_SIM_KC_LEN);
318 : : os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
319 : : EAP_SIM_SRES_LEN);
320 : : } else {
321 : : os_memcpy(data->kc[i],
322 : : "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
323 : : EAP_SIM_KC_LEN);
324 : : os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
325 : : EAP_SIM_SRES_LEN);
326 : : }
327 : : }
328 : : }
329 : :
330 : : return 0;
331 : :
332 : : #else /* CONFIG_SIM_HARDCODED */
333 : :
334 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm "
335 : : "enabled");
336 : 6 : return -1;
337 : :
338 : : #endif /* CONFIG_SIM_HARDCODED */
339 : : }
340 : :
341 : :
342 : 5 : static int eap_sim_supported_ver(int version)
343 : : {
344 : 5 : return version == EAP_SIM_VERSION;
345 : : }
346 : :
347 : :
348 : : #define CLEAR_PSEUDONYM 0x01
349 : : #define CLEAR_REAUTH_ID 0x02
350 : : #define CLEAR_EAP_ID 0x04
351 : :
352 : 15 : static void eap_sim_clear_identities(struct eap_sm *sm,
353 : : struct eap_sim_data *data, int id)
354 : : {
355 [ + + ][ - + ]: 15 : if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
356 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
357 : 0 : os_free(data->pseudonym);
358 : 0 : data->pseudonym = NULL;
359 : 0 : data->pseudonym_len = 0;
360 : 0 : eap_set_anon_id(sm, NULL, 0);
361 : : }
362 [ + + ][ + + ]: 15 : if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
363 : 1 : wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
364 : 1 : os_free(data->reauth_id);
365 : 1 : data->reauth_id = NULL;
366 : 1 : data->reauth_id_len = 0;
367 : : }
368 [ + + ][ - + ]: 15 : if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
369 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id");
370 : 0 : os_free(data->last_eap_identity);
371 : 0 : data->last_eap_identity = NULL;
372 : 0 : data->last_eap_identity_len = 0;
373 : : }
374 : 15 : }
375 : :
376 : :
377 : 5 : static int eap_sim_learn_ids(struct eap_sm *sm, struct eap_sim_data *data,
378 : : struct eap_sim_attrs *attr)
379 : : {
380 [ + + ]: 5 : if (attr->next_pseudonym) {
381 : 4 : const u8 *identity = NULL;
382 : 4 : size_t identity_len = 0;
383 : 4 : const u8 *realm = NULL;
384 : 4 : size_t realm_len = 0;
385 : :
386 : 4 : wpa_hexdump_ascii(MSG_DEBUG,
387 : : "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
388 : 4 : attr->next_pseudonym,
389 : : attr->next_pseudonym_len);
390 : 4 : os_free(data->pseudonym);
391 : : /* Look for the realm of the permanent identity */
392 : 4 : identity = eap_get_config_identity(sm, &identity_len);
393 [ + - ]: 4 : if (identity) {
394 [ + + ]: 68 : for (realm = identity, realm_len = identity_len;
395 : 64 : realm_len > 0; realm_len--, realm++) {
396 [ + + ]: 67 : if (*realm == '@')
397 : 3 : break;
398 : : }
399 : : }
400 : 4 : data->pseudonym = os_malloc(attr->next_pseudonym_len +
401 : : realm_len);
402 [ - + ]: 4 : if (data->pseudonym == NULL) {
403 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
404 : : "next pseudonym");
405 : 0 : data->pseudonym_len = 0;
406 : 0 : return -1;
407 : : }
408 : 4 : os_memcpy(data->pseudonym, attr->next_pseudonym,
409 : : attr->next_pseudonym_len);
410 [ + + ]: 4 : if (realm_len) {
411 : 3 : os_memcpy(data->pseudonym + attr->next_pseudonym_len,
412 : : realm, realm_len);
413 : : }
414 : 4 : data->pseudonym_len = attr->next_pseudonym_len + realm_len;
415 : 4 : eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
416 : : }
417 : :
418 [ + - ]: 5 : if (attr->next_reauth_id) {
419 : 5 : os_free(data->reauth_id);
420 : 5 : data->reauth_id = os_malloc(attr->next_reauth_id_len);
421 [ - + ]: 5 : if (data->reauth_id == NULL) {
422 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
423 : : "next reauth_id");
424 : 0 : data->reauth_id_len = 0;
425 : 0 : return -1;
426 : : }
427 : 5 : os_memcpy(data->reauth_id, attr->next_reauth_id,
428 : : attr->next_reauth_id_len);
429 : 5 : data->reauth_id_len = attr->next_reauth_id_len;
430 : 5 : wpa_hexdump_ascii(MSG_DEBUG,
431 : : "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
432 : 5 : data->reauth_id,
433 : : data->reauth_id_len);
434 : : }
435 : :
436 : 5 : return 0;
437 : : }
438 : :
439 : :
440 : 0 : static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
441 : : int err)
442 : : {
443 : : struct eap_sim_msg *msg;
444 : :
445 : 0 : eap_sim_state(data, FAILURE);
446 : 0 : data->num_id_req = 0;
447 : 0 : data->num_notification = 0;
448 : :
449 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: Send Client-Error (error code %d)",
450 : : err);
451 : 0 : msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
452 : : EAP_SIM_SUBTYPE_CLIENT_ERROR);
453 : 0 : eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
454 : 0 : return eap_sim_msg_finish(msg, NULL, NULL, 0);
455 : : }
456 : :
457 : :
458 : 5 : static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
459 : : struct eap_sim_data *data, u8 id,
460 : : enum eap_sim_id_req id_req)
461 : : {
462 : 5 : const u8 *identity = NULL;
463 : 5 : size_t identity_len = 0;
464 : : struct eap_sim_msg *msg;
465 : :
466 : 5 : data->reauth = 0;
467 [ + - ][ + + ]: 5 : if (id_req == ANY_ID && data->reauth_id) {
468 : 1 : identity = data->reauth_id;
469 : 1 : identity_len = data->reauth_id_len;
470 : 1 : data->reauth = 1;
471 [ - + ][ # # ]: 4 : } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
[ - + ]
472 : 4 : data->pseudonym) {
473 : 0 : identity = data->pseudonym;
474 : 0 : identity_len = data->pseudonym_len;
475 : 0 : eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
476 [ + - ]: 4 : } else if (id_req != NO_ID_REQ) {
477 : 4 : identity = eap_get_config_identity(sm, &identity_len);
478 [ + - ]: 4 : if (identity) {
479 : 4 : eap_sim_clear_identities(sm, data, CLEAR_PSEUDONYM |
480 : : CLEAR_REAUTH_ID);
481 : : }
482 : : }
483 [ + - ]: 5 : if (id_req != NO_ID_REQ)
484 : 5 : eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
485 : :
486 : 5 : wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
487 : 5 : msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
488 : : EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
489 [ + + ]: 5 : if (!data->reauth) {
490 : 4 : wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT",
491 : 4 : data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
492 : 4 : eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
493 : 4 : data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
494 : 4 : wpa_printf(MSG_DEBUG, " AT_SELECTED_VERSION %d",
495 : : data->selected_version);
496 : 4 : eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
497 : 4 : data->selected_version, NULL, 0);
498 : : }
499 : :
500 [ + - ]: 5 : if (identity) {
501 : 5 : wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY",
502 : : identity, identity_len);
503 : 5 : eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
504 : : identity, identity_len);
505 : : }
506 : :
507 : 5 : return eap_sim_msg_finish(msg, NULL, NULL, 0);
508 : : }
509 : :
510 : :
511 : 4 : static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
512 : : u8 id)
513 : : {
514 : : struct eap_sim_msg *msg;
515 : :
516 : 4 : wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id);
517 : 4 : msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
518 : : EAP_SIM_SUBTYPE_CHALLENGE);
519 [ - + ]: 4 : if (data->use_result_ind) {
520 : 0 : wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
521 : 0 : eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
522 : : }
523 : 4 : wpa_printf(MSG_DEBUG, " AT_MAC");
524 : 4 : eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
525 : 4 : return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres,
526 : 4 : data->num_chal * EAP_SIM_SRES_LEN);
527 : : }
528 : :
529 : :
530 : 1 : static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
531 : : u8 id, int counter_too_small,
532 : : const u8 *nonce_s)
533 : : {
534 : : struct eap_sim_msg *msg;
535 : : unsigned int counter;
536 : :
537 : 1 : wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)",
538 : : id);
539 : 1 : msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
540 : : EAP_SIM_SUBTYPE_REAUTHENTICATION);
541 : 1 : wpa_printf(MSG_DEBUG, " AT_IV");
542 : 1 : wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
543 : 1 : eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
544 : :
545 [ - + ]: 1 : if (counter_too_small) {
546 : 0 : wpa_printf(MSG_DEBUG, " *AT_COUNTER_TOO_SMALL");
547 : 0 : eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
548 : 0 : counter = data->counter_too_small;
549 : : } else
550 : 1 : counter = data->counter;
551 : :
552 : 1 : wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", counter);
553 : 1 : eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
554 : :
555 [ - + ]: 1 : if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
556 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
557 : : "AT_ENCR_DATA");
558 : 0 : eap_sim_msg_free(msg);
559 : 0 : return NULL;
560 : : }
561 [ - + ]: 1 : if (data->use_result_ind) {
562 : 0 : wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
563 : 0 : eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
564 : : }
565 : 1 : wpa_printf(MSG_DEBUG, " AT_MAC");
566 : 1 : eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
567 : 1 : return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
568 : : EAP_SIM_NONCE_S_LEN);
569 : : }
570 : :
571 : :
572 : 0 : static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
573 : : u8 id, u16 notification)
574 : : {
575 : : struct eap_sim_msg *msg;
576 [ # # ]: 0 : u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
577 : :
578 : 0 : wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
579 : 0 : msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
580 : : EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
581 [ # # ][ # # ]: 0 : if (k_aut && data->reauth) {
582 : 0 : wpa_printf(MSG_DEBUG, " AT_IV");
583 : 0 : wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
584 : 0 : eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
585 : : EAP_SIM_AT_ENCR_DATA);
586 : 0 : wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", data->counter);
587 : 0 : eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
588 : : NULL, 0);
589 [ # # ]: 0 : if (eap_sim_msg_add_encr_end(msg, data->k_encr,
590 : : EAP_SIM_AT_PADDING)) {
591 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
592 : : "AT_ENCR_DATA");
593 : 0 : eap_sim_msg_free(msg);
594 : 0 : return NULL;
595 : : }
596 : : }
597 [ # # ]: 0 : if (k_aut) {
598 : 0 : wpa_printf(MSG_DEBUG, " AT_MAC");
599 : 0 : eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
600 : : }
601 : 0 : return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
602 : : }
603 : :
604 : :
605 : 5 : static struct wpabuf * eap_sim_process_start(struct eap_sm *sm,
606 : : struct eap_sim_data *data, u8 id,
607 : : struct eap_sim_attrs *attr)
608 : : {
609 : 5 : int selected_version = -1, id_error;
610 : : size_t i;
611 : : u8 *pos;
612 : :
613 : 5 : wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
614 [ - + ]: 5 : if (attr->version_list == NULL) {
615 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
616 : : "SIM/Start");
617 : 0 : return eap_sim_client_error(data, id,
618 : : EAP_SIM_UNSUPPORTED_VERSION);
619 : : }
620 : :
621 : 5 : os_free(data->ver_list);
622 : 5 : data->ver_list = os_malloc(attr->version_list_len);
623 [ - + ]: 5 : if (data->ver_list == NULL) {
624 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
625 : : "memory for version list");
626 : 0 : return eap_sim_client_error(data, id,
627 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
628 : : }
629 : 5 : os_memcpy(data->ver_list, attr->version_list, attr->version_list_len);
630 : 5 : data->ver_list_len = attr->version_list_len;
631 : 5 : pos = data->ver_list;
632 [ + - ]: 5 : for (i = 0; i < data->ver_list_len / 2; i++) {
633 : 5 : int ver = pos[0] * 256 + pos[1];
634 : 5 : pos += 2;
635 [ + - ]: 5 : if (eap_sim_supported_ver(ver)) {
636 : 5 : selected_version = ver;
637 : 5 : break;
638 : : }
639 : : }
640 [ - + ]: 5 : if (selected_version < 0) {
641 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
642 : : "version");
643 : 0 : return eap_sim_client_error(data, id,
644 : : EAP_SIM_UNSUPPORTED_VERSION);
645 : : }
646 : 5 : wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
647 : : selected_version);
648 : 5 : data->selected_version = selected_version;
649 : :
650 : 5 : id_error = 0;
651 [ - + - - : 5 : switch (attr->id_req) {
- ]
652 : : case NO_ID_REQ:
653 : 0 : break;
654 : : case ANY_ID:
655 [ - + ]: 5 : if (data->num_id_req > 0)
656 : 0 : id_error++;
657 : 5 : data->num_id_req++;
658 : 5 : break;
659 : : case FULLAUTH_ID:
660 [ # # ]: 0 : if (data->num_id_req > 1)
661 : 0 : id_error++;
662 : 0 : data->num_id_req++;
663 : 0 : break;
664 : : case PERMANENT_ID:
665 [ # # ]: 0 : if (data->num_id_req > 2)
666 : 0 : id_error++;
667 : 0 : data->num_id_req++;
668 : 0 : break;
669 : : }
670 [ - + ]: 5 : if (id_error) {
671 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
672 : : "used within one authentication");
673 : 0 : return eap_sim_client_error(data, id,
674 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
675 : : }
676 : :
677 : 5 : return eap_sim_response_start(sm, data, id, attr->id_req);
678 : : }
679 : :
680 : :
681 : 6 : static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
682 : : struct eap_sim_data *data,
683 : : u8 id,
684 : : const struct wpabuf *reqData,
685 : : struct eap_sim_attrs *attr)
686 : : {
687 : : const u8 *identity;
688 : : size_t identity_len;
689 : : struct eap_sim_attrs eattr;
690 : : int res;
691 : :
692 : 6 : wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
693 : 6 : data->reauth = 0;
694 [ + - ][ - + ]: 6 : if (!attr->mac || !attr->rand) {
695 [ # # ][ # # ]: 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
696 : : "did not include%s%s",
697 : 0 : !attr->mac ? " AT_MAC" : "",
698 : 0 : !attr->rand ? " AT_RAND" : "");
699 : 0 : return eap_sim_client_error(data, id,
700 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
701 : : }
702 : :
703 : 6 : wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges",
704 : : (unsigned long) attr->num_chal);
705 [ - + ]: 6 : if (attr->num_chal < data->min_num_chal) {
706 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
707 : : "challenges (%lu)", (unsigned long) attr->num_chal);
708 : 0 : return eap_sim_client_error(data, id,
709 : : EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
710 : : }
711 [ - + ]: 6 : if (attr->num_chal > 3) {
712 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
713 : : "(%lu)", (unsigned long) attr->num_chal);
714 : 0 : return eap_sim_client_error(data, id,
715 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
716 : : }
717 : :
718 : : /* Verify that RANDs are different */
719 [ + - ]: 6 : if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
720 [ + - ]: 6 : GSM_RAND_LEN) == 0 ||
721 [ + - ]: 6 : (attr->num_chal > 2 &&
722 : 6 : (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
723 [ - + ]: 6 : GSM_RAND_LEN) == 0 ||
724 : 6 : os_memcmp(attr->rand + GSM_RAND_LEN,
725 : : attr->rand + 2 * GSM_RAND_LEN,
726 : : GSM_RAND_LEN) == 0))) {
727 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
728 : 0 : return eap_sim_client_error(data, id,
729 : : EAP_SIM_RAND_NOT_FRESH);
730 : : }
731 : :
732 : 6 : os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
733 : 6 : data->num_chal = attr->num_chal;
734 : :
735 : 6 : res = eap_sim_gsm_auth(sm, data);
736 [ + + ]: 6 : if (res > 0) {
737 : 2 : wpa_printf(MSG_DEBUG, "EAP-SIM: Wait for external SIM processing");
738 : 2 : return NULL;
739 : : }
740 [ - + ]: 4 : if (res) {
741 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
742 : 0 : return eap_sim_client_error(data, id,
743 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
744 : : }
745 [ - + ]: 4 : if (data->last_eap_identity) {
746 : 0 : identity = data->last_eap_identity;
747 : 0 : identity_len = data->last_eap_identity_len;
748 [ - + ]: 4 : } else if (data->pseudonym) {
749 : 0 : identity = data->pseudonym;
750 : 0 : identity_len = data->pseudonym_len;
751 : : } else
752 : 4 : identity = eap_get_config_identity(sm, &identity_len);
753 : 4 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
754 : : "derivation", identity, identity_len);
755 : 4 : eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
756 : 4 : data->selected_version, data->ver_list,
757 : 4 : data->ver_list_len, data->num_chal,
758 : 4 : (const u8 *) data->kc, data->mk);
759 : 4 : eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
760 : 4 : data->emsk);
761 [ - + ]: 4 : if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt,
762 : : EAP_SIM_NONCE_MT_LEN)) {
763 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
764 : : "used invalid AT_MAC");
765 : 0 : return eap_sim_client_error(data, id,
766 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
767 : : }
768 : :
769 : : /* Old reauthentication identity must not be used anymore. In
770 : : * other words, if no new reauth identity is received, full
771 : : * authentication will be used on next reauthentication (using
772 : : * pseudonym identity or permanent identity). */
773 : 4 : eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
774 : :
775 [ + - ]: 4 : if (attr->encr_data) {
776 : : u8 *decrypted;
777 : 4 : decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
778 : : attr->encr_data_len, attr->iv,
779 : : &eattr, 0);
780 [ - + ]: 4 : if (decrypted == NULL) {
781 : 0 : return eap_sim_client_error(
782 : : data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
783 : : }
784 : 4 : eap_sim_learn_ids(sm, data, &eattr);
785 : 4 : os_free(decrypted);
786 : : }
787 : :
788 [ - + ][ # # ]: 4 : if (data->result_ind && attr->result_ind)
789 : 0 : data->use_result_ind = 1;
790 : :
791 [ + - ][ + - ]: 4 : if (data->state != FAILURE && data->state != RESULT_FAILURE) {
792 [ - + ]: 4 : eap_sim_state(data, data->use_result_ind ?
793 : : RESULT_SUCCESS : SUCCESS);
794 : : }
795 : :
796 : 4 : data->num_id_req = 0;
797 : 4 : data->num_notification = 0;
798 : : /* RFC 4186 specifies that counter is initialized to one after
799 : : * fullauth, but initializing it to zero makes it easier to implement
800 : : * reauth verification. */
801 : 4 : data->counter = 0;
802 : 6 : return eap_sim_response_challenge(data, id);
803 : : }
804 : :
805 : :
806 : 0 : static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
807 : : struct eap_sim_attrs *attr)
808 : : {
809 : : struct eap_sim_attrs eattr;
810 : : u8 *decrypted;
811 : :
812 [ # # ][ # # ]: 0 : if (attr->encr_data == NULL || attr->iv == NULL) {
813 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
814 : : "reauth did not include encrypted data");
815 : 0 : return -1;
816 : : }
817 : :
818 : 0 : decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
819 : : attr->encr_data_len, attr->iv, &eattr,
820 : : 0);
821 [ # # ]: 0 : if (decrypted == NULL) {
822 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
823 : : "data from notification message");
824 : 0 : return -1;
825 : : }
826 : :
827 [ # # ][ # # ]: 0 : if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
828 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
829 : : "message does not match with counter in reauth "
830 : : "message");
831 : 0 : os_free(decrypted);
832 : 0 : return -1;
833 : : }
834 : :
835 : 0 : os_free(decrypted);
836 : 0 : return 0;
837 : : }
838 : :
839 : :
840 : 0 : static int eap_sim_process_notification_auth(struct eap_sim_data *data,
841 : : const struct wpabuf *reqData,
842 : : struct eap_sim_attrs *attr)
843 : : {
844 [ # # ]: 0 : if (attr->mac == NULL) {
845 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth "
846 : : "Notification message");
847 : 0 : return -1;
848 : : }
849 : :
850 [ # # ]: 0 : if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
851 : : {
852 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Notification message "
853 : : "used invalid AT_MAC");
854 : 0 : return -1;
855 : : }
856 : :
857 [ # # # # ]: 0 : if (data->reauth &&
858 : 0 : eap_sim_process_notification_reauth(data, attr)) {
859 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
860 : : "message after reauth");
861 : 0 : return -1;
862 : : }
863 : :
864 : 0 : return 0;
865 : : }
866 : :
867 : :
868 : 0 : static struct wpabuf * eap_sim_process_notification(
869 : : struct eap_sm *sm, struct eap_sim_data *data, u8 id,
870 : : const struct wpabuf *reqData, struct eap_sim_attrs *attr)
871 : : {
872 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification");
873 [ # # ]: 0 : if (data->num_notification > 0) {
874 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
875 : : "rounds (only one allowed)");
876 : 0 : return eap_sim_client_error(data, id,
877 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
878 : : }
879 : 0 : data->num_notification++;
880 [ # # ]: 0 : if (attr->notification == -1) {
881 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
882 : : "Notification message");
883 : 0 : return eap_sim_client_error(data, id,
884 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
885 : : }
886 : :
887 [ # # # # ]: 0 : if ((attr->notification & 0x4000) == 0 &&
888 : 0 : eap_sim_process_notification_auth(data, reqData, attr)) {
889 : 0 : return eap_sim_client_error(data, id,
890 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
891 : : }
892 : :
893 : 0 : eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
894 [ # # ][ # # ]: 0 : if (attr->notification >= 0 && attr->notification < 32768) {
895 : 0 : eap_sim_state(data, FAILURE);
896 [ # # ][ # # ]: 0 : } else if (attr->notification == EAP_SIM_SUCCESS &&
897 : 0 : data->state == RESULT_SUCCESS)
898 : 0 : eap_sim_state(data, SUCCESS);
899 : 0 : return eap_sim_response_notification(data, id, attr->notification);
900 : : }
901 : :
902 : :
903 : 1 : static struct wpabuf * eap_sim_process_reauthentication(
904 : : struct eap_sm *sm, struct eap_sim_data *data, u8 id,
905 : : const struct wpabuf *reqData, struct eap_sim_attrs *attr)
906 : : {
907 : : struct eap_sim_attrs eattr;
908 : : u8 *decrypted;
909 : :
910 : 1 : wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
911 : :
912 [ - + ]: 1 : if (data->reauth_id == NULL) {
913 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
914 : : "reauthentication, but no reauth_id available");
915 : 0 : return eap_sim_client_error(data, id,
916 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
917 : : }
918 : :
919 : 1 : data->reauth = 1;
920 [ - + ]: 1 : if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
921 : : {
922 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
923 : : "did not have valid AT_MAC");
924 : 0 : return eap_sim_client_error(data, id,
925 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
926 : : }
927 : :
928 [ + - ][ - + ]: 1 : if (attr->encr_data == NULL || attr->iv == NULL) {
929 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
930 : : "message did not include encrypted data");
931 : 0 : return eap_sim_client_error(data, id,
932 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
933 : : }
934 : :
935 : 1 : decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
936 : : attr->encr_data_len, attr->iv, &eattr,
937 : : 0);
938 [ - + ]: 1 : if (decrypted == NULL) {
939 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
940 : : "data from reauthentication message");
941 : 0 : return eap_sim_client_error(data, id,
942 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
943 : : }
944 : :
945 [ + - ][ - + ]: 1 : if (eattr.nonce_s == NULL || eattr.counter < 0) {
946 [ # # ][ # # ]: 0 : wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
947 : 0 : !eattr.nonce_s ? " AT_NONCE_S" : "",
948 : 0 : eattr.counter < 0 ? " AT_COUNTER" : "");
949 : 0 : os_free(decrypted);
950 : 0 : return eap_sim_client_error(data, id,
951 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
952 : : }
953 : :
954 [ + - ][ - + ]: 1 : if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
955 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
956 : : "(%d <= %d)", eattr.counter, data->counter);
957 : 0 : data->counter_too_small = eattr.counter;
958 : : /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
959 : : * reauth_id must not be used to start a new reauthentication.
960 : : * However, since it was used in the last EAP-Response-Identity
961 : : * packet, it has to saved for the following fullauth to be
962 : : * used in MK derivation. */
963 : 0 : os_free(data->last_eap_identity);
964 : 0 : data->last_eap_identity = data->reauth_id;
965 : 0 : data->last_eap_identity_len = data->reauth_id_len;
966 : 0 : data->reauth_id = NULL;
967 : 0 : data->reauth_id_len = 0;
968 : 0 : os_free(decrypted);
969 : 0 : return eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
970 : : }
971 : 1 : data->counter = eattr.counter;
972 : :
973 : 1 : os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
974 : 1 : wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
975 : 1 : data->nonce_s, EAP_SIM_NONCE_S_LEN);
976 : :
977 : 1 : eap_sim_derive_keys_reauth(data->counter,
978 : 1 : data->reauth_id, data->reauth_id_len,
979 : 1 : data->nonce_s, data->mk, data->msk,
980 : 1 : data->emsk);
981 : 1 : eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
982 : 1 : eap_sim_learn_ids(sm, data, &eattr);
983 : :
984 [ - + ][ # # ]: 1 : if (data->result_ind && attr->result_ind)
985 : 0 : data->use_result_ind = 1;
986 : :
987 [ + - ][ + - ]: 1 : if (data->state != FAILURE && data->state != RESULT_FAILURE) {
988 [ - + ]: 1 : eap_sim_state(data, data->use_result_ind ?
989 : : RESULT_SUCCESS : SUCCESS);
990 : : }
991 : :
992 : 1 : data->num_id_req = 0;
993 : 1 : data->num_notification = 0;
994 [ - + ]: 1 : if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
995 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
996 : : "fast reauths performed - force fullauth");
997 : 0 : eap_sim_clear_identities(sm, data,
998 : : CLEAR_REAUTH_ID | CLEAR_EAP_ID);
999 : : }
1000 : 1 : os_free(decrypted);
1001 : 1 : return eap_sim_response_reauth(data, id, 0, data->nonce_s);
1002 : : }
1003 : :
1004 : :
1005 : 12 : static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv,
1006 : : struct eap_method_ret *ret,
1007 : : const struct wpabuf *reqData)
1008 : : {
1009 : 12 : struct eap_sim_data *data = priv;
1010 : : const struct eap_hdr *req;
1011 : : u8 subtype, id;
1012 : : struct wpabuf *res;
1013 : : const u8 *pos;
1014 : : struct eap_sim_attrs attr;
1015 : : size_t len;
1016 : :
1017 : 12 : wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData);
1018 [ - + ]: 12 : if (eap_get_config_identity(sm, &len) == NULL) {
1019 : 0 : wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
1020 : 0 : eap_sm_request_identity(sm);
1021 : 0 : ret->ignore = TRUE;
1022 : 0 : return NULL;
1023 : : }
1024 : :
1025 : 12 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
1026 [ + - ][ - + ]: 12 : if (pos == NULL || len < 1) {
1027 : 0 : ret->ignore = TRUE;
1028 : 0 : return NULL;
1029 : : }
1030 : 12 : req = wpabuf_head(reqData);
1031 : 12 : id = req->identifier;
1032 : 12 : len = be_to_host16(req->length);
1033 : :
1034 : 12 : ret->ignore = FALSE;
1035 : 12 : ret->methodState = METHOD_MAY_CONT;
1036 : 12 : ret->decision = DECISION_FAIL;
1037 : 12 : ret->allowNotifications = TRUE;
1038 : :
1039 : 12 : subtype = *pos++;
1040 : 12 : wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
1041 : 12 : pos += 2; /* Reserved */
1042 : :
1043 [ - + ]: 12 : if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0,
1044 : : 0)) {
1045 : 0 : res = eap_sim_client_error(data, id,
1046 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
1047 : 0 : goto done;
1048 : : }
1049 : :
1050 [ + + - + : 12 : switch (subtype) {
- - ]
1051 : : case EAP_SIM_SUBTYPE_START:
1052 : 5 : res = eap_sim_process_start(sm, data, id, &attr);
1053 : 5 : break;
1054 : : case EAP_SIM_SUBTYPE_CHALLENGE:
1055 : 6 : res = eap_sim_process_challenge(sm, data, id, reqData, &attr);
1056 : 6 : break;
1057 : : case EAP_SIM_SUBTYPE_NOTIFICATION:
1058 : 0 : res = eap_sim_process_notification(sm, data, id, reqData,
1059 : : &attr);
1060 : 0 : break;
1061 : : case EAP_SIM_SUBTYPE_REAUTHENTICATION:
1062 : 1 : res = eap_sim_process_reauthentication(sm, data, id, reqData,
1063 : : &attr);
1064 : 1 : break;
1065 : : case EAP_SIM_SUBTYPE_CLIENT_ERROR:
1066 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
1067 : 0 : res = eap_sim_client_error(data, id,
1068 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
1069 : 0 : break;
1070 : : default:
1071 : 0 : wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
1072 : 0 : res = eap_sim_client_error(data, id,
1073 : : EAP_SIM_UNABLE_TO_PROCESS_PACKET);
1074 : 0 : break;
1075 : : }
1076 : :
1077 : : done:
1078 [ - + ]: 12 : if (data->state == FAILURE) {
1079 : 0 : ret->decision = DECISION_FAIL;
1080 : 0 : ret->methodState = METHOD_DONE;
1081 [ + + ]: 12 : } else if (data->state == SUCCESS) {
1082 [ - + ]: 5 : ret->decision = data->use_result_ind ?
1083 : : DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
1084 [ - + ]: 5 : ret->methodState = data->use_result_ind ?
1085 : : METHOD_DONE : METHOD_MAY_CONT;
1086 [ - + ]: 7 : } else if (data->state == RESULT_FAILURE)
1087 : 0 : ret->methodState = METHOD_CONT;
1088 [ - + ]: 7 : else if (data->state == RESULT_SUCCESS)
1089 : 0 : ret->methodState = METHOD_CONT;
1090 : :
1091 [ - + ]: 12 : if (ret->methodState == METHOD_DONE) {
1092 : 0 : ret->allowNotifications = FALSE;
1093 : : }
1094 : :
1095 : 12 : return res;
1096 : : }
1097 : :
1098 : :
1099 : 2 : static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
1100 : : {
1101 : 2 : struct eap_sim_data *data = priv;
1102 [ - + ][ # # ]: 2 : return data->pseudonym || data->reauth_id;
1103 : : }
1104 : :
1105 : :
1106 : 1 : static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
1107 : : {
1108 : 1 : struct eap_sim_data *data = priv;
1109 : 1 : eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
1110 : 1 : data->use_result_ind = 0;
1111 : 1 : }
1112 : :
1113 : :
1114 : 1 : static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
1115 : : {
1116 : 1 : struct eap_sim_data *data = priv;
1117 [ - + ]: 1 : if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
1118 : 0 : wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
1119 : : "for NONCE_MT");
1120 : 0 : os_free(data);
1121 : 0 : return NULL;
1122 : : }
1123 : 1 : data->num_id_req = 0;
1124 : 1 : data->num_notification = 0;
1125 : 1 : eap_sim_state(data, CONTINUE);
1126 : 1 : return priv;
1127 : : }
1128 : :
1129 : :
1130 : 1 : static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
1131 : : size_t *len)
1132 : : {
1133 : 1 : struct eap_sim_data *data = priv;
1134 : :
1135 [ + - ]: 1 : if (data->reauth_id) {
1136 : 1 : *len = data->reauth_id_len;
1137 : 1 : return data->reauth_id;
1138 : : }
1139 : :
1140 [ # # ]: 0 : if (data->pseudonym) {
1141 : 0 : *len = data->pseudonym_len;
1142 : 0 : return data->pseudonym;
1143 : : }
1144 : :
1145 : 1 : return NULL;
1146 : : }
1147 : :
1148 : :
1149 : 12 : static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
1150 : : {
1151 : 12 : struct eap_sim_data *data = priv;
1152 : 12 : return data->state == SUCCESS;
1153 : : }
1154 : :
1155 : :
1156 : 5 : static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
1157 : : {
1158 : 5 : struct eap_sim_data *data = priv;
1159 : : u8 *key;
1160 : :
1161 [ - + ]: 5 : if (data->state != SUCCESS)
1162 : 0 : return NULL;
1163 : :
1164 : 5 : key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
1165 [ - + ]: 5 : if (key == NULL)
1166 : 0 : return NULL;
1167 : :
1168 : 5 : *len = EAP_SIM_KEYING_DATA_LEN;
1169 : 5 : os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
1170 : :
1171 : 5 : return key;
1172 : : }
1173 : :
1174 : :
1175 : 5 : static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1176 : : {
1177 : 5 : struct eap_sim_data *data = priv;
1178 : : u8 *id;
1179 : :
1180 [ - + ]: 5 : if (data->state != SUCCESS)
1181 : 0 : return NULL;
1182 : :
1183 : 5 : *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
1184 : 5 : id = os_malloc(*len);
1185 [ - + ]: 5 : if (id == NULL)
1186 : 0 : return NULL;
1187 : :
1188 : 5 : id[0] = EAP_TYPE_SIM;
1189 : 5 : os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
1190 : 5 : os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
1191 : : EAP_SIM_NONCE_MT_LEN);
1192 : 5 : wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
1193 : :
1194 : 5 : return id;
1195 : : }
1196 : :
1197 : :
1198 : 0 : static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1199 : : {
1200 : 0 : struct eap_sim_data *data = priv;
1201 : : u8 *key;
1202 : :
1203 [ # # ]: 0 : if (data->state != SUCCESS)
1204 : 0 : return NULL;
1205 : :
1206 : 0 : key = os_malloc(EAP_EMSK_LEN);
1207 [ # # ]: 0 : if (key == NULL)
1208 : 0 : return NULL;
1209 : :
1210 : 0 : *len = EAP_EMSK_LEN;
1211 : 0 : os_memcpy(key, data->emsk, EAP_EMSK_LEN);
1212 : :
1213 : 0 : return key;
1214 : : }
1215 : :
1216 : :
1217 : 4 : int eap_peer_sim_register(void)
1218 : : {
1219 : : struct eap_method *eap;
1220 : : int ret;
1221 : :
1222 : 4 : eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1223 : : EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
1224 [ - + ]: 4 : if (eap == NULL)
1225 : 0 : return -1;
1226 : :
1227 : 4 : eap->init = eap_sim_init;
1228 : 4 : eap->deinit = eap_sim_deinit;
1229 : 4 : eap->process = eap_sim_process;
1230 : 4 : eap->isKeyAvailable = eap_sim_isKeyAvailable;
1231 : 4 : eap->getKey = eap_sim_getKey;
1232 : 4 : eap->getSessionId = eap_sim_get_session_id;
1233 : 4 : eap->has_reauth_data = eap_sim_has_reauth_data;
1234 : 4 : eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
1235 : 4 : eap->init_for_reauth = eap_sim_init_for_reauth;
1236 : 4 : eap->get_identity = eap_sim_get_identity;
1237 : 4 : eap->get_emsk = eap_sim_get_emsk;
1238 : :
1239 : 4 : ret = eap_peer_method_register(eap);
1240 [ - + ]: 4 : if (ret)
1241 : 0 : eap_peer_method_free(eap);
1242 : 4 : return ret;
1243 : : }
|