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