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