Line data Source code
1 : /*
2 : * EAP peer method: EAP-GPSK (RFC 5433)
3 : * Copyright (c) 2006-2014, 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 "crypto/random.h"
13 : #include "eap_peer/eap_i.h"
14 : #include "eap_common/eap_gpsk_common.h"
15 :
16 : struct eap_gpsk_data {
17 : enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
18 : u8 rand_server[EAP_GPSK_RAND_LEN];
19 : u8 rand_peer[EAP_GPSK_RAND_LEN];
20 : u8 msk[EAP_MSK_LEN];
21 : u8 emsk[EAP_EMSK_LEN];
22 : u8 sk[EAP_GPSK_MAX_SK_LEN];
23 : size_t sk_len;
24 : u8 pk[EAP_GPSK_MAX_PK_LEN];
25 : size_t pk_len;
26 : u8 session_id[128];
27 : size_t id_len;
28 : u8 *id_peer;
29 : size_t id_peer_len;
30 : u8 *id_server;
31 : size_t id_server_len;
32 : int vendor; /* CSuite/Specifier */
33 : int specifier; /* CSuite/Specifier */
34 : u8 *psk;
35 : size_t psk_len;
36 : u16 forced_cipher; /* force cipher or 0 to allow all supported */
37 : };
38 :
39 :
40 : static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
41 : u8 identifier,
42 : const u8 *csuite_list,
43 : size_t csuite_list_len);
44 : static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
45 : u8 identifier);
46 :
47 :
48 : #ifndef CONFIG_NO_STDOUT_DEBUG
49 1206 : static const char * eap_gpsk_state_txt(int state)
50 : {
51 1206 : switch (state) {
52 : case GPSK_1:
53 310 : return "GPSK-1";
54 : case GPSK_3:
55 593 : return "GPSK-3";
56 : case SUCCESS:
57 279 : return "SUCCESS";
58 : case FAILURE:
59 24 : return "FAILURE";
60 : default:
61 0 : return "?";
62 : }
63 : }
64 : #endif /* CONFIG_NO_STDOUT_DEBUG */
65 :
66 :
67 603 : static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
68 : {
69 1206 : wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
70 603 : eap_gpsk_state_txt(data->state),
71 : eap_gpsk_state_txt(state));
72 603 : data->state = state;
73 603 : }
74 :
75 :
76 : static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
77 :
78 :
79 313 : static void * eap_gpsk_init(struct eap_sm *sm)
80 : {
81 : struct eap_gpsk_data *data;
82 : const u8 *identity, *password;
83 : size_t identity_len, password_len;
84 : const char *phase1;
85 :
86 313 : password = eap_get_config_password(sm, &password_len);
87 313 : if (password == NULL) {
88 0 : wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
89 0 : return NULL;
90 : }
91 :
92 313 : data = os_zalloc(sizeof(*data));
93 313 : if (data == NULL)
94 0 : return NULL;
95 313 : data->state = GPSK_1;
96 :
97 313 : identity = eap_get_config_identity(sm, &identity_len);
98 313 : if (identity) {
99 313 : data->id_peer = os_malloc(identity_len);
100 313 : if (data->id_peer == NULL) {
101 0 : eap_gpsk_deinit(sm, data);
102 0 : return NULL;
103 : }
104 313 : os_memcpy(data->id_peer, identity, identity_len);
105 313 : data->id_peer_len = identity_len;
106 : }
107 :
108 313 : phase1 = eap_get_config_phase1(sm);
109 313 : if (phase1) {
110 : const char *pos;
111 :
112 3 : pos = os_strstr(phase1, "cipher=");
113 3 : if (pos) {
114 3 : data->forced_cipher = atoi(pos + 7);
115 3 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
116 3 : data->forced_cipher);
117 : }
118 : }
119 :
120 313 : data->psk = os_malloc(password_len);
121 313 : if (data->psk == NULL) {
122 0 : eap_gpsk_deinit(sm, data);
123 0 : return NULL;
124 : }
125 313 : os_memcpy(data->psk, password, password_len);
126 313 : data->psk_len = password_len;
127 :
128 313 : return data;
129 : }
130 :
131 :
132 313 : static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
133 : {
134 313 : struct eap_gpsk_data *data = priv;
135 313 : os_free(data->id_server);
136 313 : os_free(data->id_peer);
137 313 : if (data->psk) {
138 313 : os_memset(data->psk, 0, data->psk_len);
139 313 : os_free(data->psk);
140 : }
141 313 : bin_clear_free(data, sizeof(*data));
142 313 : }
143 :
144 :
145 310 : static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
146 : const u8 *pos, const u8 *end)
147 : {
148 : u16 alen;
149 :
150 310 : if (end - pos < 2) {
151 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
152 1 : return NULL;
153 : }
154 309 : alen = WPA_GET_BE16(pos);
155 309 : pos += 2;
156 309 : if (end - pos < alen) {
157 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
158 1 : return NULL;
159 : }
160 308 : os_free(data->id_server);
161 308 : data->id_server = os_malloc(alen);
162 308 : if (data->id_server == NULL) {
163 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
164 0 : return NULL;
165 : }
166 308 : os_memcpy(data->id_server, pos, alen);
167 308 : data->id_server_len = alen;
168 616 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
169 308 : data->id_server, data->id_server_len);
170 308 : pos += alen;
171 :
172 308 : return pos;
173 : }
174 :
175 :
176 310 : static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
177 : const u8 *pos, const u8 *end)
178 : {
179 310 : if (pos == NULL)
180 2 : return NULL;
181 :
182 308 : if (end - pos < EAP_GPSK_RAND_LEN) {
183 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
184 1 : return NULL;
185 : }
186 307 : os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
187 307 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
188 307 : data->rand_server, EAP_GPSK_RAND_LEN);
189 307 : pos += EAP_GPSK_RAND_LEN;
190 :
191 307 : return pos;
192 : }
193 :
194 :
195 303 : static int eap_gpsk_select_csuite(struct eap_sm *sm,
196 : struct eap_gpsk_data *data,
197 : const u8 *csuite_list,
198 : size_t csuite_list_len)
199 : {
200 : struct eap_gpsk_csuite *csuite;
201 : int i, count;
202 :
203 303 : count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
204 303 : data->vendor = EAP_GPSK_VENDOR_IETF;
205 303 : data->specifier = EAP_GPSK_CIPHER_RESERVED;
206 303 : csuite = (struct eap_gpsk_csuite *) csuite_list;
207 892 : for (i = 0; i < count; i++) {
208 : int vendor, specifier;
209 589 : vendor = WPA_GET_BE32(csuite->vendor);
210 589 : specifier = WPA_GET_BE16(csuite->specifier);
211 589 : wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
212 : i, vendor, specifier);
213 1178 : if (data->vendor == EAP_GPSK_VENDOR_IETF &&
214 894 : data->specifier == EAP_GPSK_CIPHER_RESERVED &&
215 609 : eap_gpsk_supported_ciphersuite(vendor, specifier) &&
216 309 : (!data->forced_cipher || data->forced_cipher == specifier))
217 : {
218 301 : data->vendor = vendor;
219 301 : data->specifier = specifier;
220 : }
221 589 : csuite++;
222 : }
223 606 : if (data->vendor == EAP_GPSK_VENDOR_IETF &&
224 303 : data->specifier == EAP_GPSK_CIPHER_RESERVED) {
225 2 : wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
226 : "ciphersuite found");
227 2 : return -1;
228 : }
229 301 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
230 : data->vendor, data->specifier);
231 :
232 301 : return 0;
233 : }
234 :
235 :
236 310 : static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
237 : struct eap_gpsk_data *data,
238 : const u8 **list,
239 : size_t *list_len,
240 : const u8 *pos, const u8 *end)
241 : {
242 : size_t len;
243 :
244 310 : if (pos == NULL)
245 3 : return NULL;
246 :
247 307 : if (end - pos < 2) {
248 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
249 1 : return NULL;
250 : }
251 306 : len = WPA_GET_BE16(pos);
252 306 : pos += 2;
253 306 : if (len > (size_t) (end - pos)) {
254 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
255 1 : return NULL;
256 : }
257 305 : if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) {
258 2 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
259 : (unsigned long) len);
260 2 : return NULL;
261 : }
262 :
263 303 : if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
264 2 : return NULL;
265 :
266 301 : *list = pos;
267 301 : *list_len = len;
268 301 : pos += len;
269 :
270 301 : return pos;
271 : }
272 :
273 :
274 311 : static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
275 : struct eap_gpsk_data *data,
276 : struct eap_method_ret *ret,
277 : u8 identifier,
278 : const u8 *payload,
279 : size_t payload_len)
280 : {
281 : size_t csuite_list_len;
282 : const u8 *csuite_list, *pos, *end;
283 : struct wpabuf *resp;
284 :
285 311 : if (data->state != GPSK_1) {
286 1 : ret->ignore = TRUE;
287 1 : return NULL;
288 : }
289 :
290 310 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
291 :
292 310 : end = payload + payload_len;
293 :
294 310 : pos = eap_gpsk_process_id_server(data, payload, end);
295 310 : pos = eap_gpsk_process_rand_server(data, pos, end);
296 310 : pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
297 : &csuite_list_len, pos, end);
298 310 : if (pos == NULL) {
299 9 : ret->methodState = METHOD_DONE;
300 9 : eap_gpsk_state(data, FAILURE);
301 9 : return NULL;
302 : }
303 :
304 301 : resp = eap_gpsk_send_gpsk_2(data, identifier,
305 : csuite_list, csuite_list_len);
306 301 : if (resp == NULL)
307 1 : return NULL;
308 :
309 300 : eap_gpsk_state(data, GPSK_3);
310 :
311 300 : return resp;
312 : }
313 :
314 :
315 301 : static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
316 : u8 identifier,
317 : const u8 *csuite_list,
318 : size_t csuite_list_len)
319 : {
320 : struct wpabuf *resp;
321 : size_t len, miclen;
322 : u8 *rpos, *start;
323 : struct eap_gpsk_csuite *csuite;
324 :
325 301 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
326 :
327 301 : miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
328 602 : len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
329 301 : 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
330 301 : sizeof(struct eap_gpsk_csuite) + 2 + miclen;
331 :
332 301 : resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
333 : EAP_CODE_RESPONSE, identifier);
334 301 : if (resp == NULL)
335 0 : return NULL;
336 :
337 301 : wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
338 301 : start = wpabuf_put(resp, 0);
339 :
340 602 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
341 301 : data->id_peer, data->id_peer_len);
342 301 : wpabuf_put_be16(resp, data->id_peer_len);
343 301 : wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
344 :
345 301 : wpabuf_put_be16(resp, data->id_server_len);
346 301 : wpabuf_put_data(resp, data->id_server, data->id_server_len);
347 :
348 301 : if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
349 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
350 : "for RAND_Peer");
351 0 : eap_gpsk_state(data, FAILURE);
352 0 : wpabuf_free(resp);
353 0 : return NULL;
354 : }
355 301 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
356 301 : data->rand_peer, EAP_GPSK_RAND_LEN);
357 301 : wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
358 301 : wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
359 :
360 301 : wpabuf_put_be16(resp, csuite_list_len);
361 301 : wpabuf_put_data(resp, csuite_list, csuite_list_len);
362 :
363 301 : csuite = wpabuf_put(resp, sizeof(*csuite));
364 301 : WPA_PUT_BE32(csuite->vendor, data->vendor);
365 301 : WPA_PUT_BE16(csuite->specifier, data->specifier);
366 :
367 1505 : if (eap_gpsk_derive_keys(data->psk, data->psk_len,
368 : data->vendor, data->specifier,
369 301 : data->rand_peer, data->rand_server,
370 301 : data->id_peer, data->id_peer_len,
371 301 : data->id_server, data->id_server_len,
372 301 : data->msk, data->emsk,
373 301 : data->sk, &data->sk_len,
374 301 : data->pk, &data->pk_len) < 0) {
375 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
376 1 : eap_gpsk_state(data, FAILURE);
377 1 : wpabuf_free(resp);
378 1 : return NULL;
379 : }
380 :
381 1200 : if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
382 : data->vendor, data->specifier,
383 300 : data->rand_peer, data->rand_server,
384 300 : data->id_peer, data->id_peer_len,
385 300 : data->id_server, data->id_server_len,
386 : EAP_TYPE_GPSK,
387 300 : data->session_id, &data->id_len) < 0) {
388 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
389 0 : eap_gpsk_state(data, FAILURE);
390 0 : wpabuf_free(resp);
391 0 : return NULL;
392 : }
393 600 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
394 300 : data->session_id, data->id_len);
395 :
396 : /* No PD_Payload_1 */
397 300 : wpabuf_put_be16(resp, 0);
398 :
399 300 : rpos = wpabuf_put(resp, miclen);
400 300 : if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
401 300 : data->specifier, start, rpos - start, rpos) <
402 : 0) {
403 0 : eap_gpsk_state(data, FAILURE);
404 0 : wpabuf_free(resp);
405 0 : return NULL;
406 : }
407 :
408 300 : return resp;
409 : }
410 :
411 :
412 293 : static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
413 : const u8 *pos, const u8 *end)
414 : {
415 293 : if (end - pos < EAP_GPSK_RAND_LEN) {
416 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
417 : "RAND_Peer");
418 1 : return NULL;
419 : }
420 292 : if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
421 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
422 : "GPSK-3 did not match");
423 1 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
424 1 : data->rand_peer, EAP_GPSK_RAND_LEN);
425 1 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
426 : pos, EAP_GPSK_RAND_LEN);
427 1 : return NULL;
428 : }
429 291 : pos += EAP_GPSK_RAND_LEN;
430 :
431 291 : if (end - pos < EAP_GPSK_RAND_LEN) {
432 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
433 : "RAND_Server");
434 1 : return NULL;
435 : }
436 290 : if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
437 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
438 : "GPSK-3 did not match");
439 1 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
440 1 : data->rand_server, EAP_GPSK_RAND_LEN);
441 1 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
442 : pos, EAP_GPSK_RAND_LEN);
443 1 : return NULL;
444 : }
445 289 : pos += EAP_GPSK_RAND_LEN;
446 :
447 289 : return pos;
448 : }
449 :
450 :
451 293 : static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
452 : const u8 *pos, const u8 *end)
453 : {
454 : size_t len;
455 :
456 293 : if (pos == NULL)
457 4 : return NULL;
458 :
459 289 : if (end - pos < (int) 2) {
460 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
461 : "length(ID_Server)");
462 1 : return NULL;
463 : }
464 :
465 288 : len = WPA_GET_BE16(pos);
466 288 : pos += 2;
467 :
468 288 : if (end - pos < (int) len) {
469 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
470 : "ID_Server");
471 1 : return NULL;
472 : }
473 :
474 573 : if (len != data->id_server_len ||
475 286 : os_memcmp(pos, data->id_server, len) != 0) {
476 2 : wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
477 : "the one used in GPSK-1");
478 4 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
479 2 : data->id_server, data->id_server_len);
480 2 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
481 : pos, len);
482 2 : return NULL;
483 : }
484 :
485 285 : pos += len;
486 :
487 285 : return pos;
488 : }
489 :
490 :
491 293 : static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
492 : const u8 *pos, const u8 *end)
493 : {
494 : int vendor, specifier;
495 : const struct eap_gpsk_csuite *csuite;
496 :
497 293 : if (pos == NULL)
498 8 : return NULL;
499 :
500 285 : if (end - pos < (int) sizeof(*csuite)) {
501 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
502 : "CSuite_Sel");
503 1 : return NULL;
504 : }
505 284 : csuite = (const struct eap_gpsk_csuite *) pos;
506 284 : vendor = WPA_GET_BE32(csuite->vendor);
507 284 : specifier = WPA_GET_BE16(csuite->specifier);
508 284 : pos += sizeof(*csuite);
509 284 : if (vendor != data->vendor || specifier != data->specifier) {
510 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
511 : "match with the one sent in GPSK-2 (%d:%d)",
512 : vendor, specifier, data->vendor, data->specifier);
513 1 : return NULL;
514 : }
515 :
516 283 : return pos;
517 : }
518 :
519 :
520 293 : static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
521 : const u8 *pos, const u8 *end)
522 : {
523 : u16 alen;
524 :
525 293 : if (pos == NULL)
526 10 : return NULL;
527 :
528 283 : if (end - pos < 2) {
529 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
530 : "PD_Payload_2 length");
531 1 : return NULL;
532 : }
533 282 : alen = WPA_GET_BE16(pos);
534 282 : pos += 2;
535 282 : if (end - pos < alen) {
536 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
537 : "%d-octet PD_Payload_2", alen);
538 1 : return NULL;
539 : }
540 281 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
541 281 : pos += alen;
542 :
543 281 : return pos;
544 : }
545 :
546 :
547 293 : static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
548 : const u8 *payload,
549 : const u8 *pos, const u8 *end)
550 : {
551 : size_t miclen;
552 : u8 mic[EAP_GPSK_MAX_MIC_LEN];
553 :
554 293 : if (pos == NULL)
555 12 : return NULL;
556 :
557 281 : miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
558 281 : if (end - pos < (int) miclen) {
559 1 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
560 : "(left=%lu miclen=%lu)",
561 1 : (unsigned long) (end - pos),
562 : (unsigned long) miclen);
563 1 : return NULL;
564 : }
565 280 : if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
566 280 : data->specifier, payload, pos - payload, mic)
567 : < 0) {
568 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
569 0 : return NULL;
570 : }
571 280 : if (os_memcmp_const(mic, pos, miclen) != 0) {
572 1 : wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
573 1 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
574 1 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
575 1 : return NULL;
576 : }
577 279 : pos += miclen;
578 :
579 279 : return pos;
580 : }
581 :
582 :
583 294 : static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
584 : struct eap_gpsk_data *data,
585 : struct eap_method_ret *ret,
586 : u8 identifier,
587 : const u8 *payload,
588 : size_t payload_len)
589 : {
590 : struct wpabuf *resp;
591 : const u8 *pos, *end;
592 :
593 294 : if (data->state != GPSK_3) {
594 1 : ret->ignore = TRUE;
595 1 : return NULL;
596 : }
597 :
598 293 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
599 :
600 293 : end = payload + payload_len;
601 :
602 293 : pos = eap_gpsk_validate_rand(data, payload, end);
603 293 : pos = eap_gpsk_validate_id_server(data, pos, end);
604 293 : pos = eap_gpsk_validate_csuite(data, pos, end);
605 293 : pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
606 293 : pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
607 :
608 293 : if (pos == NULL) {
609 14 : eap_gpsk_state(data, FAILURE);
610 14 : return NULL;
611 : }
612 279 : if (pos != end) {
613 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
614 : "data in the end of GPSK-2",
615 0 : (unsigned long) (end - pos));
616 : }
617 :
618 279 : resp = eap_gpsk_send_gpsk_4(data, identifier);
619 279 : if (resp == NULL)
620 0 : return NULL;
621 :
622 279 : eap_gpsk_state(data, SUCCESS);
623 279 : ret->methodState = METHOD_DONE;
624 279 : ret->decision = DECISION_UNCOND_SUCC;
625 :
626 279 : return resp;
627 : }
628 :
629 :
630 279 : static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
631 : u8 identifier)
632 : {
633 : struct wpabuf *resp;
634 : u8 *rpos, *start;
635 : size_t mlen;
636 :
637 279 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
638 :
639 279 : mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
640 :
641 279 : resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
642 : EAP_CODE_RESPONSE, identifier);
643 279 : if (resp == NULL)
644 0 : return NULL;
645 :
646 279 : wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
647 279 : start = wpabuf_put(resp, 0);
648 :
649 : /* No PD_Payload_3 */
650 279 : wpabuf_put_be16(resp, 0);
651 :
652 279 : rpos = wpabuf_put(resp, mlen);
653 279 : if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
654 279 : data->specifier, start, rpos - start, rpos) <
655 : 0) {
656 0 : eap_gpsk_state(data, FAILURE);
657 0 : wpabuf_free(resp);
658 0 : return NULL;
659 : }
660 :
661 279 : return resp;
662 : }
663 :
664 :
665 607 : static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
666 : struct eap_method_ret *ret,
667 : const struct wpabuf *reqData)
668 : {
669 607 : struct eap_gpsk_data *data = priv;
670 : struct wpabuf *resp;
671 : const u8 *pos;
672 : size_t len;
673 : u8 opcode, id;
674 :
675 607 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
676 607 : if (pos == NULL || len < 1) {
677 1 : ret->ignore = TRUE;
678 1 : return NULL;
679 : }
680 :
681 606 : id = eap_get_id(reqData);
682 606 : opcode = *pos++;
683 606 : len--;
684 606 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", opcode);
685 :
686 606 : ret->ignore = FALSE;
687 606 : ret->methodState = METHOD_MAY_CONT;
688 606 : ret->decision = DECISION_FAIL;
689 606 : ret->allowNotifications = FALSE;
690 :
691 606 : switch (opcode) {
692 : case EAP_GPSK_OPCODE_GPSK_1:
693 311 : resp = eap_gpsk_process_gpsk_1(sm, data, ret, id, pos, len);
694 311 : break;
695 : case EAP_GPSK_OPCODE_GPSK_3:
696 294 : resp = eap_gpsk_process_gpsk_3(sm, data, ret, id, pos, len);
697 294 : break;
698 : default:
699 1 : wpa_printf(MSG_DEBUG,
700 : "EAP-GPSK: Ignoring message with unknown opcode %d",
701 : opcode);
702 1 : ret->ignore = TRUE;
703 1 : return NULL;
704 : }
705 :
706 605 : return resp;
707 : }
708 :
709 :
710 603 : static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
711 : {
712 603 : struct eap_gpsk_data *data = priv;
713 603 : return data->state == SUCCESS;
714 : }
715 :
716 :
717 279 : static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
718 : {
719 279 : struct eap_gpsk_data *data = priv;
720 : u8 *key;
721 :
722 279 : if (data->state != SUCCESS)
723 0 : return NULL;
724 :
725 279 : key = os_malloc(EAP_MSK_LEN);
726 279 : if (key == NULL)
727 0 : return NULL;
728 279 : os_memcpy(key, data->msk, EAP_MSK_LEN);
729 279 : *len = EAP_MSK_LEN;
730 :
731 279 : return key;
732 : }
733 :
734 :
735 1 : static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
736 : {
737 1 : struct eap_gpsk_data *data = priv;
738 : u8 *key;
739 :
740 1 : if (data->state != SUCCESS)
741 0 : return NULL;
742 :
743 1 : key = os_malloc(EAP_EMSK_LEN);
744 1 : if (key == NULL)
745 0 : return NULL;
746 1 : os_memcpy(key, data->emsk, EAP_EMSK_LEN);
747 1 : *len = EAP_EMSK_LEN;
748 :
749 1 : return key;
750 : }
751 :
752 :
753 279 : static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
754 : {
755 279 : struct eap_gpsk_data *data = priv;
756 : u8 *sid;
757 :
758 279 : if (data->state != SUCCESS)
759 0 : return NULL;
760 :
761 279 : sid = os_malloc(data->id_len);
762 279 : if (sid == NULL)
763 0 : return NULL;
764 279 : os_memcpy(sid, data->session_id, data->id_len);
765 279 : *len = data->id_len;
766 :
767 279 : return sid;
768 : }
769 :
770 :
771 49 : int eap_peer_gpsk_register(void)
772 : {
773 : struct eap_method *eap;
774 : int ret;
775 :
776 49 : eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
777 : EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
778 49 : if (eap == NULL)
779 0 : return -1;
780 :
781 49 : eap->init = eap_gpsk_init;
782 49 : eap->deinit = eap_gpsk_deinit;
783 49 : eap->process = eap_gpsk_process;
784 49 : eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
785 49 : eap->getKey = eap_gpsk_getKey;
786 49 : eap->get_emsk = eap_gpsk_get_emsk;
787 49 : eap->getSessionId = eap_gpsk_get_session_id;
788 :
789 49 : ret = eap_peer_method_register(eap);
790 49 : if (ret)
791 0 : eap_peer_method_free(eap);
792 49 : return ret;
793 : }
|