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