Delete reference without relevance.
[dragonfly.git] / contrib / wpa_supplicant-0.5.8 / eap_gpsk.c
blob1366d43359869f9f9feb71996501fb67b904ddb2
1 /*
2 * EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-03.txt)
3 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #include "common.h"
18 #include "eap_i.h"
19 #include "config_ssid.h"
20 #include "eap_gpsk_common.h"
22 struct eap_gpsk_data {
23 enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
24 u8 rand_server[EAP_GPSK_RAND_LEN];
25 u8 rand_client[EAP_GPSK_RAND_LEN];
26 u8 msk[EAP_MSK_LEN];
27 u8 emsk[EAP_EMSK_LEN];
28 u8 sk[EAP_GPSK_MAX_SK_LEN];
29 size_t sk_len;
30 u8 pk[EAP_GPSK_MAX_PK_LEN];
31 size_t pk_len;
32 u8 session_id;
33 int session_id_set;
34 u8 *id_client;
35 size_t id_client_len;
36 u8 *id_server;
37 size_t id_server_len;
38 int vendor; /* CSuite/Specifier */
39 int specifier; /* CSuite/Specifier */
40 u8 *psk;
41 size_t psk_len;
45 #ifndef CONFIG_NO_STDOUT_DEBUG
46 static const char * eap_gpsk_state_txt(int state)
48 switch (state) {
49 case GPSK_1:
50 return "GPSK-1";
51 case GPSK_3:
52 return "GPSK-3";
53 case SUCCESS:
54 return "SUCCESS";
55 case FAILURE:
56 return "FAILURE";
57 default:
58 return "?";
61 #endif /* CONFIG_NO_STDOUT_DEBUG */
64 static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
66 wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
67 eap_gpsk_state_txt(data->state),
68 eap_gpsk_state_txt(state));
69 data->state = state;
73 static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
76 static void * eap_gpsk_init(struct eap_sm *sm)
78 struct wpa_ssid *config = eap_get_config(sm);
79 struct eap_gpsk_data *data;
81 if (config == NULL) {
82 wpa_printf(MSG_INFO, "EAP-GPSK: No configuration found");
83 return NULL;
86 if (config->eappsk == NULL) {
87 wpa_printf(MSG_INFO, "EAP-GPSK: No key (eappsk) configured");
88 return NULL;
91 data = os_zalloc(sizeof(*data));
92 if (data == NULL)
93 return NULL;
94 data->state = GPSK_1;
96 if (config->nai) {
97 data->id_client = os_malloc(config->nai_len);
98 if (data->id_client == NULL) {
99 eap_gpsk_deinit(sm, data);
100 return NULL;
102 os_memcpy(data->id_client, config->nai, config->nai_len);
103 data->id_client_len = config->nai_len;
106 data->psk = os_malloc(config->eappsk_len);
107 if (data->psk == NULL) {
108 eap_gpsk_deinit(sm, data);
109 return NULL;
111 os_memcpy(data->psk, config->eappsk, config->eappsk_len);
112 data->psk_len = config->eappsk_len;
114 return data;
118 static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
120 struct eap_gpsk_data *data = priv;
121 os_free(data->id_server);
122 os_free(data->id_client);
123 os_free(data->psk);
124 os_free(data);
128 static u8 * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
129 struct eap_gpsk_data *data,
130 struct eap_method_ret *ret,
131 const u8 *reqData, size_t reqDataLen,
132 const u8 *payload, size_t payload_len,
133 size_t *respDataLen)
135 size_t len, csuite_list_len, miclen;
136 struct eap_hdr *resp;
137 u8 *rpos, *start;
138 const u8 *csuite_list, *pos, *end;
139 const struct eap_hdr *req;
140 struct eap_gpsk_csuite *csuite;
141 u16 alen;
142 int i, count;
144 if (data->state != GPSK_1) {
145 ret->ignore = TRUE;
146 return NULL;
149 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
151 req = (const struct eap_hdr *) reqData;
152 pos = payload;
153 end = payload + payload_len;
155 if (end - pos < 2) {
156 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
157 return NULL;
159 alen = WPA_GET_BE16(pos);
160 pos += 2;
161 if (end - pos < alen) {
162 wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
163 return NULL;
165 os_free(data->id_server);
166 data->id_server = os_malloc(alen);
167 if (data->id_server == NULL) {
168 wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
169 return NULL;
171 os_memcpy(data->id_server, pos, alen);
172 data->id_server_len = alen;
173 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
174 data->id_server, data->id_server_len);
175 pos += alen;
177 if (end - pos < EAP_GPSK_RAND_LEN) {
178 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
179 return NULL;
181 os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
182 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
183 data->rand_server, EAP_GPSK_RAND_LEN);
184 pos += EAP_GPSK_RAND_LEN;
186 if (end - pos < 2) {
187 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
188 return NULL;
190 csuite_list_len = WPA_GET_BE16(pos);
191 pos += 2;
192 if (end - pos < (int) csuite_list_len) {
193 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
194 return NULL;
196 csuite_list = pos;
198 if (csuite_list_len == 0 ||
199 csuite_list_len % sizeof(struct eap_gpsk_csuite)) {
200 wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %d",
201 csuite_list_len);
202 return NULL;
204 count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
205 data->vendor = EAP_GPSK_VENDOR_IETF;
206 data->specifier = EAP_GPSK_CIPHER_RESERVED;
207 csuite = (struct eap_gpsk_csuite *) csuite_list;
208 for (i = 0; i < count; i++) {
209 int vendor, specifier;
210 vendor = WPA_GET_BE24(csuite->vendor);
211 specifier = WPA_GET_BE24(csuite->specifier);
212 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
213 i, vendor, specifier);
214 if (data->vendor == EAP_GPSK_VENDOR_IETF &&
215 data->specifier == EAP_GPSK_CIPHER_RESERVED &&
216 eap_gpsk_supported_ciphersuite(vendor, specifier)) {
217 data->vendor = vendor;
218 data->specifier = specifier;
220 csuite++;
222 if (data->vendor == EAP_GPSK_VENDOR_IETF &&
223 data->specifier == EAP_GPSK_CIPHER_RESERVED) {
224 wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
225 "ciphersuite found");
226 eap_gpsk_state(data, FAILURE);
227 return NULL;
229 wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
230 data->vendor, data->specifier);
232 wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
234 miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
235 len = 1 + 2 + data->id_client_len + 2 + data->id_server_len +
236 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
237 sizeof(struct eap_gpsk_csuite) + 2 + miclen;
239 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respDataLen, len,
240 EAP_CODE_RESPONSE, req->identifier, &rpos);
241 if (resp == NULL)
242 return NULL;
244 *rpos++ = EAP_GPSK_OPCODE_GPSK_2;
245 start = rpos;
247 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Client",
248 data->id_client, data->id_client_len);
249 WPA_PUT_BE16(rpos, data->id_client_len);
250 rpos += 2;
251 if (data->id_client)
252 os_memcpy(rpos, data->id_client, data->id_client_len);
253 rpos += data->id_client_len;
255 WPA_PUT_BE16(rpos, data->id_server_len);
256 rpos += 2;
257 if (data->id_server)
258 os_memcpy(rpos, data->id_server, data->id_server_len);
259 rpos += data->id_server_len;
261 if (os_get_random(data->rand_client, EAP_GPSK_RAND_LEN)) {
262 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
263 "for RAND_Client");
264 eap_gpsk_state(data, FAILURE);
265 os_free(resp);
266 return NULL;
268 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client",
269 data->rand_client, EAP_GPSK_RAND_LEN);
270 os_memcpy(rpos, data->rand_client, EAP_GPSK_RAND_LEN);
271 rpos += EAP_GPSK_RAND_LEN;
273 os_memcpy(rpos, data->rand_server, EAP_GPSK_RAND_LEN);
274 rpos += EAP_GPSK_RAND_LEN;
276 WPA_PUT_BE16(rpos, csuite_list_len);
277 rpos += 2;
278 os_memcpy(rpos, csuite_list, csuite_list_len);
279 rpos += csuite_list_len;
281 csuite = (struct eap_gpsk_csuite *) rpos;
282 WPA_PUT_BE24(csuite->vendor, data->vendor);
283 WPA_PUT_BE24(csuite->specifier, data->specifier);
284 rpos = (u8 *) (csuite + 1);
286 if (eap_gpsk_derive_keys(data->psk, data->psk_len,
287 data->vendor, data->specifier,
288 data->rand_client, data->rand_server,
289 data->id_client, data->id_client_len,
290 data->id_server, data->id_server_len,
291 data->msk, data->emsk,
292 data->sk, &data->sk_len,
293 data->pk, &data->pk_len) < 0) {
294 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
295 eap_gpsk_state(data, FAILURE);
296 os_free(resp);
297 return NULL;
300 /* No PD_Payload_1 */
301 WPA_PUT_BE16(rpos, 0);
302 rpos += 2;
304 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
305 data->specifier, start, rpos - start, rpos) <
306 0) {
307 eap_gpsk_state(data, FAILURE);
308 os_free(resp);
309 return NULL;
312 eap_gpsk_state(data, GPSK_3);
314 return (u8 *) resp;
318 static u8 * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
319 struct eap_gpsk_data *data,
320 struct eap_method_ret *ret,
321 const u8 *reqData, size_t reqDataLen,
322 const u8 *payload, size_t payload_len,
323 size_t *respDataLen)
325 size_t len, miclen;
326 struct eap_hdr *resp;
327 u8 *rpos, *start;
328 const struct eap_hdr *req;
329 const u8 *pos, *end;
330 u16 alen;
331 int vendor, specifier;
332 const struct eap_gpsk_csuite *csuite;
333 u8 mic[EAP_GPSK_MAX_MIC_LEN];
335 if (data->state != GPSK_3) {
336 ret->ignore = TRUE;
337 return NULL;
340 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
342 req = (const struct eap_hdr *) reqData;
343 pos = payload;
344 end = payload + payload_len;
346 if (end - pos < EAP_GPSK_RAND_LEN) {
347 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
348 "RAND_Client");
349 return NULL;
351 if (os_memcmp(pos, data->rand_client, EAP_GPSK_RAND_LEN) != 0) {
352 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-2 and "
353 "GPSK-3 did not match");
354 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-2",
355 data->rand_client, EAP_GPSK_RAND_LEN);
356 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-3",
357 pos, EAP_GPSK_RAND_LEN);
358 eap_gpsk_state(data, FAILURE);
359 return NULL;
361 pos += EAP_GPSK_RAND_LEN;
363 if (end - pos < EAP_GPSK_RAND_LEN) {
364 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
365 "RAND_Server");
366 return NULL;
368 if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
369 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
370 "GPSK-3 did not match");
371 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
372 data->rand_server, EAP_GPSK_RAND_LEN);
373 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
374 pos, EAP_GPSK_RAND_LEN);
375 eap_gpsk_state(data, FAILURE);
376 return NULL;
378 pos += EAP_GPSK_RAND_LEN;
380 if (end - pos < (int) sizeof(*csuite)) {
381 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
382 "CSuite_Sel");
383 return NULL;
385 csuite = (const struct eap_gpsk_csuite *) pos;
386 vendor = WPA_GET_BE24(csuite->vendor);
387 specifier = WPA_GET_BE24(csuite->specifier);
388 pos += sizeof(*csuite);
389 if (vendor != data->vendor || specifier != data->specifier) {
390 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
391 "match with the one sent in GPSK-2 (%d:%d)",
392 vendor, specifier, data->vendor, data->specifier);
393 eap_gpsk_state(data, FAILURE);
394 return NULL;
397 if (end - pos < 2) {
398 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
399 "PD_Payload_2 length");
400 eap_gpsk_state(data, FAILURE);
401 return NULL;
403 alen = WPA_GET_BE16(pos);
404 pos += 2;
405 if (end - pos < alen) {
406 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
407 "%d-octet PD_Payload_2", alen);
408 eap_gpsk_state(data, FAILURE);
409 return NULL;
411 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
412 pos += alen;
413 miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
414 if (end - pos < (int) miclen) {
415 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
416 "(left=%d miclen=%d)", end - pos, miclen);
417 eap_gpsk_state(data, FAILURE);
418 return NULL;
420 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
421 data->specifier, payload, pos - payload, mic)
422 < 0) {
423 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
424 eap_gpsk_state(data, FAILURE);
425 return NULL;
427 if (os_memcmp(mic, pos, miclen) != 0) {
428 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
429 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
430 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
431 eap_gpsk_state(data, FAILURE);
432 return NULL;
434 pos += miclen;
436 if (pos != end) {
437 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
438 "data in the end of GPSK-2", end - pos);
441 wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
443 len = 1 + 2 + miclen;
445 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respDataLen, len,
446 EAP_CODE_RESPONSE, req->identifier, &rpos);
447 if (resp == NULL)
448 return NULL;
450 *rpos++ = EAP_GPSK_OPCODE_GPSK_4;
451 start = rpos;
453 /* No PD_Payload_3 */
454 WPA_PUT_BE16(rpos, 0);
455 rpos += 2;
457 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
458 data->specifier, start, rpos - start, rpos) <
459 0) {
460 eap_gpsk_state(data, FAILURE);
461 os_free(resp);
462 return NULL;
465 eap_gpsk_state(data, SUCCESS);
466 ret->methodState = METHOD_DONE;
467 ret->decision = DECISION_UNCOND_SUCC;
469 return (u8 *) resp;
473 static u8 * eap_gpsk_process(struct eap_sm *sm, void *priv,
474 struct eap_method_ret *ret,
475 const u8 *reqData, size_t reqDataLen,
476 size_t *respDataLen)
478 struct eap_gpsk_data *data = priv;
479 u8 *resp;
480 const u8 *pos;
481 size_t len;
483 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK,
484 reqData, reqDataLen, &len);
485 if (pos == NULL || len < 1) {
486 ret->ignore = TRUE;
487 return NULL;
490 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
492 ret->ignore = FALSE;
493 ret->methodState = METHOD_MAY_CONT;
494 ret->decision = DECISION_FAIL;
495 ret->allowNotifications = FALSE;
497 switch (*pos) {
498 case EAP_GPSK_OPCODE_GPSK_1:
499 resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
500 reqDataLen, pos + 1, len - 1,
501 respDataLen);
502 break;
503 case EAP_GPSK_OPCODE_GPSK_3:
504 resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
505 reqDataLen, pos + 1, len - 1,
506 respDataLen);
507 break;
508 default:
509 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
510 "unknown opcode %d", *pos);
511 ret->ignore = TRUE;
512 return NULL;
515 return resp;
519 static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
521 struct eap_gpsk_data *data = priv;
522 return data->state == SUCCESS;
526 static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
528 struct eap_gpsk_data *data = priv;
529 u8 *key;
531 if (data->state != SUCCESS)
532 return NULL;
534 key = os_malloc(EAP_MSK_LEN);
535 if (key == NULL)
536 return NULL;
537 os_memcpy(key, data->msk, EAP_MSK_LEN);
538 *len = EAP_MSK_LEN;
540 return key;
544 static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
546 struct eap_gpsk_data *data = priv;
547 u8 *key;
549 if (data->state != SUCCESS)
550 return NULL;
552 key = os_malloc(EAP_EMSK_LEN);
553 if (key == NULL)
554 return NULL;
555 os_memcpy(key, data->emsk, EAP_EMSK_LEN);
556 *len = EAP_EMSK_LEN;
558 return key;
562 int eap_peer_gpsk_register(void)
564 struct eap_method *eap;
565 int ret;
567 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
568 EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
569 if (eap == NULL)
570 return -1;
572 eap->init = eap_gpsk_init;
573 eap->deinit = eap_gpsk_deinit;
574 eap->process = eap_gpsk_process;
575 eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
576 eap->getKey = eap_gpsk_getKey;
577 eap->get_emsk = eap_gpsk_get_emsk;
579 ret = eap_peer_method_register(eap);
580 if (ret)
581 eap_peer_method_free(eap);
582 return ret;