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