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