]>
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, | |
5d65ca51 JM |
435 | u8 id, int counter_too_small, |
436 | const u8 *nonce_s) | |
6fc6879b JM |
437 | { |
438 | struct eap_sim_msg *msg; | |
439 | unsigned int counter; | |
440 | ||
441 | wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)", | |
442 | id); | |
443 | msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM, | |
444 | EAP_SIM_SUBTYPE_REAUTHENTICATION); | |
445 | wpa_printf(MSG_DEBUG, " AT_IV"); | |
446 | wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); | |
447 | eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); | |
448 | ||
449 | if (counter_too_small) { | |
450 | wpa_printf(MSG_DEBUG, " *AT_COUNTER_TOO_SMALL"); | |
451 | eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0); | |
452 | counter = data->counter_too_small; | |
453 | } else | |
454 | counter = data->counter; | |
455 | ||
456 | wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", counter); | |
457 | eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); | |
458 | ||
459 | if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { | |
460 | wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt " | |
461 | "AT_ENCR_DATA"); | |
462 | eap_sim_msg_free(msg); | |
463 | return NULL; | |
464 | } | |
465 | if (data->use_result_ind) { | |
466 | wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); | |
467 | eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); | |
468 | } | |
469 | wpa_printf(MSG_DEBUG, " AT_MAC"); | |
470 | eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); | |
5d65ca51 | 471 | return eap_sim_msg_finish(msg, data->k_aut, nonce_s, |
6fc6879b JM |
472 | EAP_SIM_NONCE_S_LEN); |
473 | } | |
474 | ||
475 | ||
476 | static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data, | |
477 | u8 id, u16 notification) | |
478 | { | |
479 | struct eap_sim_msg *msg; | |
480 | u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL; | |
481 | ||
482 | wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id); | |
483 | msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, | |
484 | EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION); | |
6fc6879b JM |
485 | if (k_aut && data->reauth) { |
486 | wpa_printf(MSG_DEBUG, " AT_IV"); | |
487 | wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); | |
488 | eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, | |
489 | EAP_SIM_AT_ENCR_DATA); | |
490 | wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", data->counter); | |
491 | eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, | |
492 | NULL, 0); | |
493 | if (eap_sim_msg_add_encr_end(msg, data->k_encr, | |
494 | EAP_SIM_AT_PADDING)) { | |
495 | wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt " | |
496 | "AT_ENCR_DATA"); | |
497 | eap_sim_msg_free(msg); | |
498 | return NULL; | |
499 | } | |
500 | } | |
501 | if (k_aut) { | |
502 | wpa_printf(MSG_DEBUG, " AT_MAC"); | |
503 | eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); | |
504 | } | |
505 | return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0); | |
506 | } | |
507 | ||
508 | ||
509 | static struct wpabuf * eap_sim_process_start(struct eap_sm *sm, | |
510 | struct eap_sim_data *data, u8 id, | |
511 | struct eap_sim_attrs *attr) | |
512 | { | |
513 | int selected_version = -1, id_error; | |
514 | size_t i; | |
515 | u8 *pos; | |
516 | ||
517 | wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start"); | |
518 | if (attr->version_list == NULL) { | |
519 | wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in " | |
520 | "SIM/Start"); | |
521 | return eap_sim_client_error(data, id, | |
522 | EAP_SIM_UNSUPPORTED_VERSION); | |
523 | } | |
524 | ||
525 | os_free(data->ver_list); | |
526 | data->ver_list = os_malloc(attr->version_list_len); | |
527 | if (data->ver_list == NULL) { | |
528 | wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate " | |
529 | "memory for version list"); | |
530 | return eap_sim_client_error(data, id, | |
531 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
532 | } | |
533 | os_memcpy(data->ver_list, attr->version_list, attr->version_list_len); | |
534 | data->ver_list_len = attr->version_list_len; | |
535 | pos = data->ver_list; | |
536 | for (i = 0; i < data->ver_list_len / 2; i++) { | |
537 | int ver = pos[0] * 256 + pos[1]; | |
538 | pos += 2; | |
539 | if (eap_sim_supported_ver(ver)) { | |
540 | selected_version = ver; | |
541 | break; | |
542 | } | |
543 | } | |
544 | if (selected_version < 0) { | |
545 | wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported " | |
546 | "version"); | |
547 | return eap_sim_client_error(data, id, | |
548 | EAP_SIM_UNSUPPORTED_VERSION); | |
549 | } | |
550 | wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d", | |
551 | selected_version); | |
552 | data->selected_version = selected_version; | |
553 | ||
554 | id_error = 0; | |
555 | switch (attr->id_req) { | |
556 | case NO_ID_REQ: | |
557 | break; | |
558 | case ANY_ID: | |
559 | if (data->num_id_req > 0) | |
560 | id_error++; | |
561 | data->num_id_req++; | |
562 | break; | |
563 | case FULLAUTH_ID: | |
564 | if (data->num_id_req > 1) | |
565 | id_error++; | |
566 | data->num_id_req++; | |
567 | break; | |
568 | case PERMANENT_ID: | |
569 | if (data->num_id_req > 2) | |
570 | id_error++; | |
571 | data->num_id_req++; | |
572 | break; | |
573 | } | |
574 | if (id_error) { | |
575 | wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests " | |
576 | "used within one authentication"); | |
577 | return eap_sim_client_error(data, id, | |
578 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
579 | } | |
580 | ||
581 | return eap_sim_response_start(sm, data, id, attr->id_req); | |
582 | } | |
583 | ||
584 | ||
585 | static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, | |
586 | struct eap_sim_data *data, | |
587 | u8 id, | |
588 | const struct wpabuf *reqData, | |
589 | struct eap_sim_attrs *attr) | |
590 | { | |
591 | const u8 *identity; | |
592 | size_t identity_len; | |
593 | struct eap_sim_attrs eattr; | |
594 | ||
595 | wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge"); | |
596 | data->reauth = 0; | |
597 | if (!attr->mac || !attr->rand) { | |
598 | wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " | |
599 | "did not include%s%s", | |
600 | !attr->mac ? " AT_MAC" : "", | |
601 | !attr->rand ? " AT_RAND" : ""); | |
602 | return eap_sim_client_error(data, id, | |
603 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
604 | } | |
605 | ||
606 | wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges", | |
607 | (unsigned long) attr->num_chal); | |
608 | if (attr->num_chal < data->min_num_chal) { | |
609 | wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of " | |
610 | "challenges (%lu)", (unsigned long) attr->num_chal); | |
611 | return eap_sim_client_error(data, id, | |
612 | EAP_SIM_INSUFFICIENT_NUM_OF_CHAL); | |
613 | } | |
614 | if (attr->num_chal > 3) { | |
615 | wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges " | |
616 | "(%lu)", (unsigned long) attr->num_chal); | |
617 | return eap_sim_client_error(data, id, | |
618 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
619 | } | |
620 | ||
621 | /* Verify that RANDs are different */ | |
622 | if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN, | |
623 | GSM_RAND_LEN) == 0 || | |
624 | (attr->num_chal > 2 && | |
625 | (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN, | |
626 | GSM_RAND_LEN) == 0 || | |
627 | os_memcmp(attr->rand + GSM_RAND_LEN, | |
628 | attr->rand + 2 * GSM_RAND_LEN, | |
629 | GSM_RAND_LEN) == 0))) { | |
630 | wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times"); | |
631 | return eap_sim_client_error(data, id, | |
632 | EAP_SIM_RAND_NOT_FRESH); | |
633 | } | |
634 | ||
635 | os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN); | |
636 | data->num_chal = attr->num_chal; | |
637 | ||
638 | if (eap_sim_gsm_auth(sm, data)) { | |
639 | wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed"); | |
640 | return eap_sim_client_error(data, id, | |
641 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
642 | } | |
643 | if (data->last_eap_identity) { | |
644 | identity = data->last_eap_identity; | |
645 | identity_len = data->last_eap_identity_len; | |
646 | } else if (data->pseudonym) { | |
647 | identity = data->pseudonym; | |
648 | identity_len = data->pseudonym_len; | |
649 | } else | |
650 | identity = eap_get_config_identity(sm, &identity_len); | |
651 | wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK " | |
652 | "derivation", identity, identity_len); | |
653 | eap_sim_derive_mk(identity, identity_len, data->nonce_mt, | |
654 | data->selected_version, data->ver_list, | |
655 | data->ver_list_len, data->num_chal, | |
656 | (const u8 *) data->kc, data->mk); | |
657 | eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, | |
658 | data->emsk); | |
659 | if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt, | |
660 | EAP_SIM_NONCE_MT_LEN)) { | |
661 | wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " | |
662 | "used invalid AT_MAC"); | |
663 | return eap_sim_client_error(data, id, | |
664 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
665 | } | |
666 | ||
a9f40ae7 SB |
667 | /* Old reauthentication identity must not be used anymore. In |
668 | * other words, if no new reauth identity is received, full | |
669 | * authentication will be used on next reauthentication (using | |
670 | * pseudonym identity or permanent identity). */ | |
671 | eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); | |
6fc6879b JM |
672 | |
673 | if (attr->encr_data) { | |
674 | u8 *decrypted; | |
675 | decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, | |
676 | attr->encr_data_len, attr->iv, | |
677 | &eattr, 0); | |
678 | if (decrypted == NULL) { | |
679 | return eap_sim_client_error( | |
680 | data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
681 | } | |
a6689be8 | 682 | eap_sim_learn_ids(sm, data, &eattr); |
6fc6879b JM |
683 | os_free(decrypted); |
684 | } | |
685 | ||
686 | if (data->result_ind && attr->result_ind) | |
687 | data->use_result_ind = 1; | |
688 | ||
689 | if (data->state != FAILURE && data->state != RESULT_FAILURE) { | |
690 | eap_sim_state(data, data->use_result_ind ? | |
691 | RESULT_SUCCESS : SUCCESS); | |
692 | } | |
693 | ||
694 | data->num_id_req = 0; | |
695 | data->num_notification = 0; | |
696 | /* RFC 4186 specifies that counter is initialized to one after | |
697 | * fullauth, but initializing it to zero makes it easier to implement | |
698 | * reauth verification. */ | |
699 | data->counter = 0; | |
700 | return eap_sim_response_challenge(data, id); | |
701 | } | |
702 | ||
703 | ||
704 | static int eap_sim_process_notification_reauth(struct eap_sim_data *data, | |
705 | struct eap_sim_attrs *attr) | |
706 | { | |
707 | struct eap_sim_attrs eattr; | |
708 | u8 *decrypted; | |
709 | ||
710 | if (attr->encr_data == NULL || attr->iv == NULL) { | |
711 | wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after " | |
712 | "reauth did not include encrypted data"); | |
713 | return -1; | |
714 | } | |
715 | ||
716 | decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, | |
717 | attr->encr_data_len, attr->iv, &eattr, | |
718 | 0); | |
719 | if (decrypted == NULL) { | |
720 | wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " | |
721 | "data from notification message"); | |
722 | return -1; | |
723 | } | |
724 | ||
725 | if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) { | |
726 | wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification " | |
727 | "message does not match with counter in reauth " | |
728 | "message"); | |
729 | os_free(decrypted); | |
730 | return -1; | |
731 | } | |
732 | ||
733 | os_free(decrypted); | |
734 | return 0; | |
735 | } | |
736 | ||
737 | ||
738 | static int eap_sim_process_notification_auth(struct eap_sim_data *data, | |
739 | const struct wpabuf *reqData, | |
740 | struct eap_sim_attrs *attr) | |
741 | { | |
742 | if (attr->mac == NULL) { | |
743 | wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth " | |
744 | "Notification message"); | |
745 | return -1; | |
746 | } | |
747 | ||
748 | if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0)) | |
749 | { | |
750 | wpa_printf(MSG_WARNING, "EAP-SIM: Notification message " | |
751 | "used invalid AT_MAC"); | |
752 | return -1; | |
753 | } | |
754 | ||
755 | if (data->reauth && | |
756 | eap_sim_process_notification_reauth(data, attr)) { | |
757 | wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification " | |
758 | "message after reauth"); | |
759 | return -1; | |
760 | } | |
761 | ||
762 | return 0; | |
763 | } | |
764 | ||
765 | ||
766 | static struct wpabuf * eap_sim_process_notification( | |
767 | struct eap_sm *sm, struct eap_sim_data *data, u8 id, | |
768 | const struct wpabuf *reqData, struct eap_sim_attrs *attr) | |
769 | { | |
770 | wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification"); | |
771 | if (data->num_notification > 0) { | |
772 | wpa_printf(MSG_INFO, "EAP-SIM: too many notification " | |
773 | "rounds (only one allowed)"); | |
774 | return eap_sim_client_error(data, id, | |
775 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
776 | } | |
777 | data->num_notification++; | |
778 | if (attr->notification == -1) { | |
779 | wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in " | |
780 | "Notification message"); | |
781 | return eap_sim_client_error(data, id, | |
782 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
783 | } | |
784 | ||
785 | if ((attr->notification & 0x4000) == 0 && | |
786 | eap_sim_process_notification_auth(data, reqData, attr)) { | |
787 | return eap_sim_client_error(data, id, | |
788 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
789 | } | |
790 | ||
791 | eap_sim_report_notification(sm->msg_ctx, attr->notification, 0); | |
792 | if (attr->notification >= 0 && attr->notification < 32768) { | |
793 | eap_sim_state(data, FAILURE); | |
794 | } else if (attr->notification == EAP_SIM_SUCCESS && | |
795 | data->state == RESULT_SUCCESS) | |
796 | eap_sim_state(data, SUCCESS); | |
797 | return eap_sim_response_notification(data, id, attr->notification); | |
798 | } | |
799 | ||
800 | ||
801 | static struct wpabuf * eap_sim_process_reauthentication( | |
802 | struct eap_sm *sm, struct eap_sim_data *data, u8 id, | |
803 | const struct wpabuf *reqData, struct eap_sim_attrs *attr) | |
804 | { | |
805 | struct eap_sim_attrs eattr; | |
806 | u8 *decrypted; | |
807 | ||
808 | wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication"); | |
809 | ||
810 | if (data->reauth_id == NULL) { | |
811 | wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying " | |
812 | "reauthentication, but no reauth_id available"); | |
813 | return eap_sim_client_error(data, id, | |
814 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
815 | } | |
816 | ||
817 | data->reauth = 1; | |
818 | if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0)) | |
819 | { | |
820 | wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " | |
821 | "did not have valid AT_MAC"); | |
822 | return eap_sim_client_error(data, id, | |
823 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
824 | } | |
825 | ||
826 | if (attr->encr_data == NULL || attr->iv == NULL) { | |
827 | wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " | |
828 | "message did not include encrypted data"); | |
829 | return eap_sim_client_error(data, id, | |
830 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
831 | } | |
832 | ||
833 | decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, | |
834 | attr->encr_data_len, attr->iv, &eattr, | |
835 | 0); | |
836 | if (decrypted == NULL) { | |
837 | wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " | |
838 | "data from reauthentication message"); | |
839 | return eap_sim_client_error(data, id, | |
840 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
841 | } | |
842 | ||
843 | if (eattr.nonce_s == NULL || eattr.counter < 0) { | |
844 | wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet", | |
845 | !eattr.nonce_s ? " AT_NONCE_S" : "", | |
846 | eattr.counter < 0 ? " AT_COUNTER" : ""); | |
847 | os_free(decrypted); | |
848 | return eap_sim_client_error(data, id, | |
849 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
850 | } | |
851 | ||
852 | if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) { | |
853 | wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter " | |
854 | "(%d <= %d)", eattr.counter, data->counter); | |
855 | data->counter_too_small = eattr.counter; | |
856 | /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current | |
857 | * reauth_id must not be used to start a new reauthentication. | |
858 | * However, since it was used in the last EAP-Response-Identity | |
859 | * packet, it has to saved for the following fullauth to be | |
860 | * used in MK derivation. */ | |
861 | os_free(data->last_eap_identity); | |
862 | data->last_eap_identity = data->reauth_id; | |
863 | data->last_eap_identity_len = data->reauth_id_len; | |
864 | data->reauth_id = NULL; | |
865 | data->reauth_id_len = 0; | |
866 | os_free(decrypted); | |
5d65ca51 | 867 | return eap_sim_response_reauth(data, id, 1, eattr.nonce_s); |
6fc6879b JM |
868 | } |
869 | data->counter = eattr.counter; | |
870 | ||
871 | os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN); | |
872 | wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S", | |
873 | data->nonce_s, EAP_SIM_NONCE_S_LEN); | |
874 | ||
875 | eap_sim_derive_keys_reauth(data->counter, | |
876 | data->reauth_id, data->reauth_id_len, | |
877 | data->nonce_s, data->mk, data->msk, | |
878 | data->emsk); | |
879 | eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); | |
a6689be8 | 880 | eap_sim_learn_ids(sm, data, &eattr); |
6fc6879b JM |
881 | |
882 | if (data->result_ind && attr->result_ind) | |
883 | data->use_result_ind = 1; | |
884 | ||
885 | if (data->state != FAILURE && data->state != RESULT_FAILURE) { | |
886 | eap_sim_state(data, data->use_result_ind ? | |
887 | RESULT_SUCCESS : SUCCESS); | |
888 | } | |
889 | ||
890 | data->num_id_req = 0; | |
891 | data->num_notification = 0; | |
892 | if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) { | |
893 | wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of " | |
894 | "fast reauths performed - force fullauth"); | |
895 | eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); | |
896 | } | |
897 | os_free(decrypted); | |
5d65ca51 | 898 | return eap_sim_response_reauth(data, id, 0, data->nonce_s); |
6fc6879b JM |
899 | } |
900 | ||
901 | ||
902 | static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv, | |
903 | struct eap_method_ret *ret, | |
904 | const struct wpabuf *reqData) | |
905 | { | |
906 | struct eap_sim_data *data = priv; | |
907 | const struct eap_hdr *req; | |
908 | u8 subtype, id; | |
909 | struct wpabuf *res; | |
910 | const u8 *pos; | |
911 | struct eap_sim_attrs attr; | |
912 | size_t len; | |
913 | ||
914 | wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData); | |
915 | if (eap_get_config_identity(sm, &len) == NULL) { | |
916 | wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured"); | |
917 | eap_sm_request_identity(sm); | |
918 | ret->ignore = TRUE; | |
919 | return NULL; | |
920 | } | |
921 | ||
922 | pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len); | |
923 | if (pos == NULL || len < 1) { | |
924 | ret->ignore = TRUE; | |
925 | return NULL; | |
926 | } | |
927 | req = wpabuf_head(reqData); | |
928 | id = req->identifier; | |
929 | len = be_to_host16(req->length); | |
930 | ||
931 | ret->ignore = FALSE; | |
932 | ret->methodState = METHOD_MAY_CONT; | |
933 | ret->decision = DECISION_FAIL; | |
934 | ret->allowNotifications = TRUE; | |
935 | ||
936 | subtype = *pos++; | |
937 | wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype); | |
938 | pos += 2; /* Reserved */ | |
939 | ||
940 | if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0, | |
941 | 0)) { | |
942 | res = eap_sim_client_error(data, id, | |
943 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
944 | goto done; | |
945 | } | |
946 | ||
947 | switch (subtype) { | |
948 | case EAP_SIM_SUBTYPE_START: | |
949 | res = eap_sim_process_start(sm, data, id, &attr); | |
950 | break; | |
951 | case EAP_SIM_SUBTYPE_CHALLENGE: | |
952 | res = eap_sim_process_challenge(sm, data, id, reqData, &attr); | |
953 | break; | |
954 | case EAP_SIM_SUBTYPE_NOTIFICATION: | |
955 | res = eap_sim_process_notification(sm, data, id, reqData, | |
956 | &attr); | |
957 | break; | |
958 | case EAP_SIM_SUBTYPE_REAUTHENTICATION: | |
959 | res = eap_sim_process_reauthentication(sm, data, id, reqData, | |
960 | &attr); | |
961 | break; | |
962 | case EAP_SIM_SUBTYPE_CLIENT_ERROR: | |
963 | wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error"); | |
964 | res = eap_sim_client_error(data, id, | |
965 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
966 | break; | |
967 | default: | |
968 | wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype); | |
969 | res = eap_sim_client_error(data, id, | |
970 | EAP_SIM_UNABLE_TO_PROCESS_PACKET); | |
971 | break; | |
972 | } | |
973 | ||
974 | done: | |
975 | if (data->state == FAILURE) { | |
976 | ret->decision = DECISION_FAIL; | |
977 | ret->methodState = METHOD_DONE; | |
978 | } else if (data->state == SUCCESS) { | |
979 | ret->decision = data->use_result_ind ? | |
980 | DECISION_UNCOND_SUCC : DECISION_COND_SUCC; | |
981 | ret->methodState = data->use_result_ind ? | |
982 | METHOD_DONE : METHOD_MAY_CONT; | |
983 | } else if (data->state == RESULT_FAILURE) | |
984 | ret->methodState = METHOD_CONT; | |
985 | else if (data->state == RESULT_SUCCESS) | |
986 | ret->methodState = METHOD_CONT; | |
987 | ||
988 | if (ret->methodState == METHOD_DONE) { | |
989 | ret->allowNotifications = FALSE; | |
990 | } | |
991 | ||
992 | return res; | |
993 | } | |
994 | ||
995 | ||
996 | static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv) | |
997 | { | |
998 | struct eap_sim_data *data = priv; | |
999 | return data->pseudonym || data->reauth_id; | |
1000 | } | |
1001 | ||
1002 | ||
1003 | static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv) | |
1004 | { | |
1005 | struct eap_sim_data *data = priv; | |
1006 | eap_sim_clear_identities(data, CLEAR_EAP_ID); | |
1007 | data->use_result_ind = 0; | |
1008 | } | |
1009 | ||
1010 | ||
1011 | static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv) | |
1012 | { | |
1013 | struct eap_sim_data *data = priv; | |
3642c431 | 1014 | if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) { |
6fc6879b JM |
1015 | wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data " |
1016 | "for NONCE_MT"); | |
1017 | os_free(data); | |
1018 | return NULL; | |
1019 | } | |
1020 | data->num_id_req = 0; | |
1021 | data->num_notification = 0; | |
1022 | eap_sim_state(data, CONTINUE); | |
1023 | return priv; | |
1024 | } | |
1025 | ||
1026 | ||
1027 | static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv, | |
1028 | size_t *len) | |
1029 | { | |
1030 | struct eap_sim_data *data = priv; | |
1031 | ||
1032 | if (data->reauth_id) { | |
1033 | *len = data->reauth_id_len; | |
1034 | return data->reauth_id; | |
1035 | } | |
1036 | ||
1037 | if (data->pseudonym) { | |
1038 | *len = data->pseudonym_len; | |
1039 | return data->pseudonym; | |
1040 | } | |
1041 | ||
1042 | return NULL; | |
1043 | } | |
1044 | ||
1045 | ||
1046 | static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv) | |
1047 | { | |
1048 | struct eap_sim_data *data = priv; | |
1049 | return data->state == SUCCESS; | |
1050 | } | |
1051 | ||
1052 | ||
1053 | static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len) | |
1054 | { | |
1055 | struct eap_sim_data *data = priv; | |
1056 | u8 *key; | |
1057 | ||
1058 | if (data->state != SUCCESS) | |
1059 | return NULL; | |
1060 | ||
1061 | key = os_malloc(EAP_SIM_KEYING_DATA_LEN); | |
1062 | if (key == NULL) | |
1063 | return NULL; | |
1064 | ||
1065 | *len = EAP_SIM_KEYING_DATA_LEN; | |
1066 | os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); | |
1067 | ||
1068 | return key; | |
1069 | } | |
1070 | ||
1071 | ||
1072 | static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len) | |
1073 | { | |
1074 | struct eap_sim_data *data = priv; | |
1075 | u8 *key; | |
1076 | ||
1077 | if (data->state != SUCCESS) | |
1078 | return NULL; | |
1079 | ||
1080 | key = os_malloc(EAP_EMSK_LEN); | |
1081 | if (key == NULL) | |
1082 | return NULL; | |
1083 | ||
1084 | *len = EAP_EMSK_LEN; | |
1085 | os_memcpy(key, data->emsk, EAP_EMSK_LEN); | |
1086 | ||
1087 | return key; | |
1088 | } | |
1089 | ||
1090 | ||
1091 | int eap_peer_sim_register(void) | |
1092 | { | |
1093 | struct eap_method *eap; | |
1094 | int ret; | |
1095 | ||
1096 | eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, | |
1097 | EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM"); | |
1098 | if (eap == NULL) | |
1099 | return -1; | |
1100 | ||
1101 | eap->init = eap_sim_init; | |
1102 | eap->deinit = eap_sim_deinit; | |
1103 | eap->process = eap_sim_process; | |
1104 | eap->isKeyAvailable = eap_sim_isKeyAvailable; | |
1105 | eap->getKey = eap_sim_getKey; | |
1106 | eap->has_reauth_data = eap_sim_has_reauth_data; | |
1107 | eap->deinit_for_reauth = eap_sim_deinit_for_reauth; | |
1108 | eap->init_for_reauth = eap_sim_init_for_reauth; | |
1109 | eap->get_identity = eap_sim_get_identity; | |
1110 | eap->get_emsk = eap_sim_get_emsk; | |
1111 | ||
1112 | ret = eap_peer_method_register(eap); | |
1113 | if (ret) | |
1114 | eap_peer_method_free(eap); | |
1115 | return ret; | |
1116 | } |