Branch data 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 : 48 : static const char * eap_gpsk_state_txt(int state)
50 : : {
51 [ + + + + : 48 : switch (state) {
- ]
52 : : case GPSK_1:
53 : 13 : return "GPSK-1";
54 : : case GPSK_3:
55 : 23 : return "GPSK-3";
56 : : case SUCCESS:
57 : 11 : return "SUCCESS";
58 : : case FAILURE:
59 : 1 : return "FAILURE";
60 : : default:
61 : 48 : return "?";
62 : : }
63 : : }
64 : : #endif /* CONFIG_NO_STDOUT_DEBUG */
65 : :
66 : :
67 : 24 : static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
68 : : {
69 : 24 : wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
70 : 24 : eap_gpsk_state_txt(data->state),
71 : : eap_gpsk_state_txt(state));
72 : 24 : data->state = state;
73 : 24 : }
74 : :
75 : :
76 : : static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
77 : :
78 : :
79 : 13 : 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 : 13 : password = eap_get_config_password(sm, &password_len);
87 [ - + ]: 13 : if (password == NULL) {
88 : 0 : wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
89 : 0 : return NULL;
90 : : }
91 : :
92 : 13 : data = os_zalloc(sizeof(*data));
93 [ - + ]: 13 : if (data == NULL)
94 : 0 : return NULL;
95 : 13 : data->state = GPSK_1;
96 : :
97 : 13 : identity = eap_get_config_identity(sm, &identity_len);
98 [ + - ]: 13 : if (identity) {
99 : 13 : data->id_peer = os_malloc(identity_len);
100 [ - + ]: 13 : if (data->id_peer == NULL) {
101 : 0 : eap_gpsk_deinit(sm, data);
102 : 0 : return NULL;
103 : : }
104 : 13 : os_memcpy(data->id_peer, identity, identity_len);
105 : 13 : data->id_peer_len = identity_len;
106 : : }
107 : :
108 : 13 : phase1 = eap_get_config_phase1(sm);
109 [ + + ]: 13 : 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 : 13 : data->psk = os_malloc(password_len);
121 [ - + ]: 13 : if (data->psk == NULL) {
122 : 0 : eap_gpsk_deinit(sm, data);
123 : 0 : return NULL;
124 : : }
125 : 13 : os_memcpy(data->psk, password, password_len);
126 : 13 : data->psk_len = password_len;
127 : :
128 : 13 : return data;
129 : : }
130 : :
131 : :
132 : 13 : static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
133 : : {
134 : 13 : struct eap_gpsk_data *data = priv;
135 : 13 : os_free(data->id_server);
136 : 13 : os_free(data->id_peer);
137 : 13 : os_free(data->psk);
138 : 13 : os_free(data);
139 : 13 : }
140 : :
141 : :
142 : 13 : 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 [ - + ]: 13 : if (end - pos < 2) {
148 : 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
149 : 0 : return NULL;
150 : : }
151 : 13 : alen = WPA_GET_BE16(pos);
152 : 13 : pos += 2;
153 [ - + ]: 13 : if (end - pos < alen) {
154 : 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
155 : 0 : return NULL;
156 : : }
157 : 13 : os_free(data->id_server);
158 : 13 : data->id_server = os_malloc(alen);
159 [ - + ]: 13 : if (data->id_server == NULL) {
160 : 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
161 : 0 : return NULL;
162 : : }
163 : 13 : os_memcpy(data->id_server, pos, alen);
164 : 13 : data->id_server_len = alen;
165 : 13 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
166 : 13 : data->id_server, data->id_server_len);
167 : 13 : pos += alen;
168 : :
169 : 13 : return pos;
170 : : }
171 : :
172 : :
173 : 13 : static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
174 : : const u8 *pos, const u8 *end)
175 : : {
176 [ - + ]: 13 : if (pos == NULL)
177 : 0 : return NULL;
178 : :
179 [ - + ]: 13 : if (end - pos < EAP_GPSK_RAND_LEN) {
180 : 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
181 : 0 : return NULL;
182 : : }
183 : 13 : os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
184 : 13 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
185 : 13 : data->rand_server, EAP_GPSK_RAND_LEN);
186 : 13 : pos += EAP_GPSK_RAND_LEN;
187 : :
188 : 13 : return pos;
189 : : }
190 : :
191 : :
192 : 13 : 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 : 13 : count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
201 : 13 : data->vendor = EAP_GPSK_VENDOR_IETF;
202 : 13 : data->specifier = EAP_GPSK_CIPHER_RESERVED;
203 : 13 : csuite = (struct eap_gpsk_csuite *) csuite_list;
204 [ + + ]: 39 : for (i = 0; i < count; i++) {
205 : : int vendor, specifier;
206 : 26 : vendor = WPA_GET_BE32(csuite->vendor);
207 : 26 : specifier = WPA_GET_BE16(csuite->specifier);
208 : 26 : wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
209 : : i, vendor, specifier);
210 [ + - ][ + + ]: 26 : if (data->vendor == EAP_GPSK_VENDOR_IETF &&
211 [ + - ]: 15 : data->specifier == EAP_GPSK_CIPHER_RESERVED &&
212 [ + + ]: 30 : eap_gpsk_supported_ciphersuite(vendor, specifier) &&
213 [ + + ]: 5 : (!data->forced_cipher || data->forced_cipher == specifier))
214 : : {
215 : 12 : data->vendor = vendor;
216 : 12 : data->specifier = specifier;
217 : : }
218 : 26 : csuite++;
219 : : }
220 [ + - ][ + + ]: 13 : if (data->vendor == EAP_GPSK_VENDOR_IETF &&
221 : 13 : 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 : 12 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
227 : : data->vendor, data->specifier);
228 : :
229 : 13 : return 0;
230 : : }
231 : :
232 : :
233 : 13 : 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 [ - + ]: 13 : if (pos == NULL)
240 : 0 : return NULL;
241 : :
242 [ - + ]: 13 : if (end - pos < 2) {
243 : 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
244 : 0 : return NULL;
245 : : }
246 : 13 : *list_len = WPA_GET_BE16(pos);
247 : 13 : pos += 2;
248 [ - + ]: 13 : if (end - pos < (int) *list_len) {
249 : 0 : wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
250 : 0 : return NULL;
251 : : }
252 [ + - ][ - + ]: 13 : 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 : 13 : *list = pos;
258 : 13 : pos += *list_len;
259 : :
260 [ + + ]: 13 : if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0)
261 : 1 : return NULL;
262 : :
263 : 13 : return pos;
264 : : }
265 : :
266 : :
267 : 13 : 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 [ - + ]: 13 : if (data->state != GPSK_1) {
279 : 0 : ret->ignore = TRUE;
280 : 0 : return NULL;
281 : : }
282 : :
283 : 13 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
284 : :
285 : 13 : end = payload + payload_len;
286 : :
287 : 13 : pos = eap_gpsk_process_id_server(data, payload, end);
288 : 13 : pos = eap_gpsk_process_rand_server(data, pos, end);
289 : 13 : pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
290 : : &csuite_list_len, pos, end);
291 [ + + ]: 13 : if (pos == NULL) {
292 : 1 : ret->methodState = METHOD_DONE;
293 : 1 : eap_gpsk_state(data, FAILURE);
294 : 1 : return NULL;
295 : : }
296 : :
297 : 12 : resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData),
298 : : csuite_list, csuite_list_len);
299 [ - + ]: 12 : if (resp == NULL)
300 : 0 : return NULL;
301 : :
302 : 12 : eap_gpsk_state(data, GPSK_3);
303 : :
304 : 13 : return resp;
305 : : }
306 : :
307 : :
308 : 12 : 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 : 12 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
319 : :
320 : 12 : miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
321 : 24 : len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
322 : 12 : 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
323 : 12 : sizeof(struct eap_gpsk_csuite) + 2 + miclen;
324 : :
325 : 12 : resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
326 : : EAP_CODE_RESPONSE, identifier);
327 [ - + ]: 12 : if (resp == NULL)
328 : 0 : return NULL;
329 : :
330 : 12 : wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
331 : 12 : start = wpabuf_put(resp, 0);
332 : :
333 : 12 : wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
334 : 12 : data->id_peer, data->id_peer_len);
335 : 12 : wpabuf_put_be16(resp, data->id_peer_len);
336 : 12 : wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
337 : :
338 : 12 : wpabuf_put_be16(resp, data->id_server_len);
339 : 12 : wpabuf_put_data(resp, data->id_server, data->id_server_len);
340 : :
341 [ - + ]: 12 : 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 : 12 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
349 : 12 : data->rand_peer, EAP_GPSK_RAND_LEN);
350 : 12 : wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
351 : 12 : wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
352 : :
353 : 12 : wpabuf_put_be16(resp, csuite_list_len);
354 : 12 : wpabuf_put_data(resp, csuite_list, csuite_list_len);
355 : :
356 : 12 : csuite = wpabuf_put(resp, sizeof(*csuite));
357 : 12 : WPA_PUT_BE32(csuite->vendor, data->vendor);
358 : 12 : WPA_PUT_BE16(csuite->specifier, data->specifier);
359 : :
360 [ - + ]: 12 : if (eap_gpsk_derive_keys(data->psk, data->psk_len,
361 : : data->vendor, data->specifier,
362 : 12 : data->rand_peer, data->rand_server,
363 : 12 : data->id_peer, data->id_peer_len,
364 : 12 : data->id_server, data->id_server_len,
365 : 12 : data->msk, data->emsk,
366 : 12 : data->sk, &data->sk_len,
367 : 12 : 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 [ - + ]: 12 : if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
375 : : data->vendor, data->specifier,
376 : 12 : data->rand_peer, data->rand_server,
377 : 12 : data->id_peer, data->id_peer_len,
378 : 12 : data->id_server, data->id_server_len,
379 : : EAP_TYPE_GPSK,
380 : 12 : 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 : 12 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
387 : 12 : data->session_id, data->id_len);
388 : :
389 : : /* No PD_Payload_1 */
390 : 12 : wpabuf_put_be16(resp, 0);
391 : :
392 : 12 : rpos = wpabuf_put(resp, miclen);
393 [ - + ]: 12 : if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
394 : 12 : 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 : 12 : return resp;
402 : : }
403 : :
404 : :
405 : 11 : static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
406 : : const u8 *pos, const u8 *end)
407 : : {
408 [ - + ]: 11 : 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 [ - + ]: 11 : 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 : 11 : pos += EAP_GPSK_RAND_LEN;
423 : :
424 [ - + ]: 11 : 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 [ - + ]: 11 : 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 : 11 : pos += EAP_GPSK_RAND_LEN;
439 : :
440 : 11 : return pos;
441 : : }
442 : :
443 : :
444 : 11 : 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 [ - + ]: 11 : if (pos == NULL)
450 : 0 : return NULL;
451 : :
452 [ - + ]: 11 : 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 : 11 : len = WPA_GET_BE16(pos);
459 : 11 : pos += 2;
460 : :
461 [ - + ]: 11 : 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 [ + - ][ - + ]: 11 : if (len != data->id_server_len ||
468 : 11 : 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 : 11 : pos += len;
479 : :
480 : 11 : return pos;
481 : : }
482 : :
483 : :
484 : 11 : 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 [ - + ]: 11 : if (pos == NULL)
491 : 0 : return NULL;
492 : :
493 [ - + ]: 11 : 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 : 11 : csuite = (const struct eap_gpsk_csuite *) pos;
499 : 11 : vendor = WPA_GET_BE32(csuite->vendor);
500 : 11 : specifier = WPA_GET_BE16(csuite->specifier);
501 : 11 : pos += sizeof(*csuite);
502 [ + - ][ - + ]: 11 : 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 : 11 : return pos;
510 : : }
511 : :
512 : :
513 : 11 : 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 [ - + ]: 11 : if (pos == NULL)
519 : 0 : return NULL;
520 : :
521 [ - + ]: 11 : 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 : 11 : alen = WPA_GET_BE16(pos);
527 : 11 : pos += 2;
528 [ - + ]: 11 : 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 : 11 : wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
534 : 11 : pos += alen;
535 : :
536 : 11 : return pos;
537 : : }
538 : :
539 : :
540 : 11 : 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 [ - + ]: 11 : if (pos == NULL)
548 : 0 : return NULL;
549 : :
550 : 11 : miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
551 [ - + ]: 11 : 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 [ - + ]: 11 : if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
559 : 11 : 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 [ - + ]: 11 : 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 : 11 : pos += miclen;
571 : :
572 : 11 : return pos;
573 : : }
574 : :
575 : :
576 : 11 : 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 [ - + ]: 11 : if (data->state != GPSK_3) {
587 : 0 : ret->ignore = TRUE;
588 : 0 : return NULL;
589 : : }
590 : :
591 : 11 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
592 : :
593 : 11 : end = payload + payload_len;
594 : :
595 : 11 : pos = eap_gpsk_validate_rand(data, payload, end);
596 : 11 : pos = eap_gpsk_validate_id_server(data, pos, end);
597 : 11 : pos = eap_gpsk_validate_csuite(data, pos, end);
598 : 11 : pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
599 : 11 : pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
600 : :
601 [ - + ]: 11 : if (pos == NULL) {
602 : 0 : eap_gpsk_state(data, FAILURE);
603 : 0 : return NULL;
604 : : }
605 [ - + ]: 11 : 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 : 11 : resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData));
612 [ - + ]: 11 : if (resp == NULL)
613 : 0 : return NULL;
614 : :
615 : 11 : eap_gpsk_state(data, SUCCESS);
616 : 11 : ret->methodState = METHOD_DONE;
617 : 11 : ret->decision = DECISION_UNCOND_SUCC;
618 : :
619 : 11 : return resp;
620 : : }
621 : :
622 : :
623 : 11 : 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 : 11 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
631 : :
632 : 11 : mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
633 : :
634 : 11 : resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
635 : : EAP_CODE_RESPONSE, identifier);
636 [ - + ]: 11 : if (resp == NULL)
637 : 0 : return NULL;
638 : :
639 : 11 : wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
640 : 11 : start = wpabuf_put(resp, 0);
641 : :
642 : : /* No PD_Payload_3 */
643 : 11 : wpabuf_put_be16(resp, 0);
644 : :
645 : 11 : rpos = wpabuf_put(resp, mlen);
646 [ - + ]: 11 : if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
647 : 11 : 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 : 11 : return resp;
655 : : }
656 : :
657 : :
658 : 24 : 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 : 24 : struct eap_gpsk_data *data = priv;
663 : : struct wpabuf *resp;
664 : : const u8 *pos;
665 : : size_t len;
666 : :
667 : 24 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
668 [ + - ][ - + ]: 24 : if (pos == NULL || len < 1) {
669 : 0 : ret->ignore = TRUE;
670 : 0 : return NULL;
671 : : }
672 : :
673 : 24 : wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
674 : :
675 : 24 : ret->ignore = FALSE;
676 : 24 : ret->methodState = METHOD_MAY_CONT;
677 : 24 : ret->decision = DECISION_FAIL;
678 : 24 : ret->allowNotifications = FALSE;
679 : :
680 [ + + - ]: 24 : switch (*pos) {
681 : : case EAP_GPSK_OPCODE_GPSK_1:
682 : 13 : resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
683 : : pos + 1, len - 1);
684 : 13 : break;
685 : : case EAP_GPSK_OPCODE_GPSK_3:
686 : 11 : resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
687 : : pos + 1, len - 1);
688 : 11 : 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 : 24 : return resp;
697 : : }
698 : :
699 : :
700 : 24 : static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
701 : : {
702 : 24 : struct eap_gpsk_data *data = priv;
703 : 24 : return data->state == SUCCESS;
704 : : }
705 : :
706 : :
707 : 11 : static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
708 : : {
709 : 11 : struct eap_gpsk_data *data = priv;
710 : : u8 *key;
711 : :
712 [ - + ]: 11 : if (data->state != SUCCESS)
713 : 0 : return NULL;
714 : :
715 : 11 : key = os_malloc(EAP_MSK_LEN);
716 [ - + ]: 11 : if (key == NULL)
717 : 0 : return NULL;
718 : 11 : os_memcpy(key, data->msk, EAP_MSK_LEN);
719 : 11 : *len = EAP_MSK_LEN;
720 : :
721 : 11 : 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 : 11 : static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
744 : : {
745 : 11 : struct eap_gpsk_data *data = priv;
746 : : u8 *sid;
747 : :
748 [ - + ]: 11 : if (data->state != SUCCESS)
749 : 0 : return NULL;
750 : :
751 : 11 : sid = os_malloc(data->id_len);
752 [ - + ]: 11 : if (sid == NULL)
753 : 0 : return NULL;
754 : 11 : os_memcpy(sid, data->session_id, data->id_len);
755 : 11 : *len = data->id_len;
756 : :
757 : 11 : 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 : : }
|